--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java
@@ -166,6 +166,40 @@ public enum HttpMethod
         }
     }
 
+    /**
+     * Optimized lookup to find a method name and trailing space in a byte array.
+     *
+     * @param buffer buffer containing ISO-8859-1 characters, it is not modified, which must have at least 5 bytes remaining
+     * @param lookAhead The integer representation of the first 4 bytes of the buffer that has previously been fetched
+     *                  with the equivalent of {@code buffer.getInt(buffer.position())}
+     * @return An HttpMethod if a match or null if no easy match.
+     */
+    static HttpMethod lookAheadGet(ByteBuffer buffer, int lookAhead)
+    {
+        switch (lookAhead)
+        {
+            case ACL_AS_INT:
+                return ACL;
+            case GET_AS_INT:
+                return GET;
+            case PRI_AS_INT:
+                return PRI;
+            case PUT_AS_INT:
+                return PUT;
+            case POST_AS_INT:
+                if (buffer.get(buffer.position() + 4) == ' ')
+                    return POST;
+                break;
+            case HEAD_AS_INT:
+                if (buffer.get(buffer.position() + 4) == ' ')
+                    return HEAD;
+                break;
+            default:
+                break;
+        }
+        return LOOK_AHEAD.getBest(buffer, 0, buffer.remaining());
+    }
+
     /**
      * Optimized lookup to find a method name and trailing space in a byte array.
      *
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
@@ -105,14 +105,24 @@ public class HttpParser
     public static final Trie<HttpField> CACHE = new ArrayTrie<>(2048);
     private static final Trie<HttpField> NO_CACHE = Trie.empty(true);
 
-    // States
-    public enum FieldState
-    {
-        FIELD,
-        IN_NAME,
-        VALUE,
-        IN_VALUE,
-        WS_AFTER_NAME,
+    private static final long HTTP_1_0_AS_LONG = stringAsLong("HTTP/1.0");
+    private static final long HTTP_1_1_AS_LONG = stringAsLong("HTTP/1.1");
+    private static final long GET_SLASH_HT_AS_LONG = stringAsLong("GET / HT");
+    private static final long TP_SLASH_1_0_CRLF_AS_LONG = stringAsLong("TP/1.0\r\n");
+    private static final long TP_SLASH_1_1_CRLF_AS_LONG = stringAsLong("TP/1.1\r\n");
+    private static final long SPACE_200_OK_CR_AS_LONG = stringAsLong(" 200 OK\r");
+    private static final int CRLF_AS_SHORT = ((0xFF & '\r') << Byte.SIZE) | (0xFF & '\n');
+
+    private static long stringAsLong(String s)
+    {
+        if (s == null || s.length() != Long.BYTES)
+            throw new IllegalArgumentException();
+        long l = 0;
+        for (char c : s.toCharArray())
+        {
+            l = l << Byte.SIZE | ((long)c & 0xFFL);
+        }
+        return l;
     }
 
     // States
@@ -133,8 +143,8 @@ public class HttpParser
         EOF_CONTENT,
         CHUNKED_CONTENT,
         CHUNK_SIZE,
-        CHUNK_PARAMS,
         CHUNK,
+        CHUNK_END,
         CONTENT_END,
         TRAILER,
         END,
@@ -142,6 +152,28 @@ public class HttpParser
         CLOSED  // The associated stream/endpoint is at EOF
     }
 
+    public enum FieldState
+    {
+        FIELD,
+        IN_NAME,
+        VALUE,
+        IN_VALUE,
+        WS_AFTER_NAME,
+    }
+
+    public enum ChunkSizeState
+    {
+        SIZE,
+        EXT_BWS,
+        EXT_NAME_BWS_BEFORE,
+        EXT_NAME,
+        EXT_NAME_BWS_AFTER,
+        EXT_VALUE_BWS_BEFORE,
+        EXT_VALUE_OPEN_QUOTE,
+        EXT_VALUE,
+        EXT_VALUE_CLOSE_QUOTE,
+    }
+
     private static final EnumSet<State> __idleStates = EnumSet.of(State.START, State.END, State.CLOSE, State.CLOSED);
     private static final EnumSet<State> __completeStates = EnumSet.of(State.END, State.CLOSE, State.CLOSED);
     private static final EnumSet<State> __terminatedStates = EnumSet.of(State.CLOSE, State.CLOSED);
@@ -170,13 +202,14 @@ public class HttpParser
     private HttpMethod _method;
     private String _methodString;
     private HttpVersion _version;
-    private EndOfContent _endOfContent;
+    private EndOfContent _endOfContent = EndOfContent.UNKNOWN_CONTENT;
     private boolean _hasContentLength;
     private boolean _hasTransferEncoding;
     private long _contentLength = -1;
     private long _contentPosition;
-    private int _chunkLength;
-    private int _chunkPosition;
+    private int _chunkSizeDigits;
+    private long _chunkLength;
+    private long _chunkPosition;
     private boolean _headResponse;
     private boolean _cr;
     private ByteBuffer _contentChunk;
@@ -184,6 +217,8 @@ public class HttpParser
 
     private int _length;
     private final StringBuilder _string = new StringBuilder();
+    private ChunkSizeState _chunkSizeState = ChunkSizeState.SIZE;
+    private boolean _chunkQuotedEscape = false;
 
     static
     {
@@ -450,7 +485,7 @@ public class HttpParser
     private HttpTokens.Token next(ByteBuffer buffer)
     {
         byte ch = buffer.get();
-
+        addAndCheckHeadersSize(1);
         HttpTokens.Token t = HttpTokens.TOKENS[0xff & ch];
 
         switch (t.getType())
@@ -459,22 +494,33 @@ public class HttpParser
                 throw new IllegalCharacterException(_state, t, buffer);
 
             case LF:
-                _cr = false;
-                break;
+                if (_cr)
+                {
+                    _cr = false;
+                    return HttpTokens.EOL_CRLF;
+                }
+                return HttpTokens.EOL_LF;
 
             case CR:
                 if (_cr)
                     throw new BadMessageException("Bad EOL");
 
-                _cr = true;
                 if (buffer.hasRemaining())
                 {
-                    // Don't count the CRs and LFs of the chunked encoding.
-                    if (_maxHeaderBytes > 0 && (_state == State.HEADER || _state == State.TRAILER))
-                        _headerBytes++;
-                    return next(buffer);
+                    ch = buffer.get();
+                    addAndCheckHeadersSize(1);
+                    t = HttpTokens.TOKENS[0xff & ch];
+                    switch (t.getType())
+                    {
+                        case CNTL:
+                            throw new IllegalCharacterException(_state, t, buffer);
+                        case LF:
+                            return HttpTokens.EOL_CRLF;
+                        default:
+                            throw new BadMessageException("Bad EOL");
+                    }
                 }
-
+                _cr = true;
                 return null;
 
             case ALPHA:
@@ -496,6 +542,133 @@ public class HttpParser
         return t;
     }
 
+    private void addAndCheckHeadersSize(int delta)
+    {
+        if (_maxHeaderBytes <= 0)
+            return;
+        if (_state.ordinal() <= State.HEADER.ordinal() ||
+            (_state == State.CHUNK_SIZE && _chunkSizeState != ChunkSizeState.SIZE) ||
+            _state.ordinal() == State.TRAILER.ordinal())
+        {
+            _headerBytes += delta;
+            if (_headerBytes > _maxHeaderBytes)
+            {
+                if (_state == State.URI)
+                    throw new BadMessageException(HttpStatus.URI_TOO_LONG_414);
+                if (_requestHandler != null)
+                    throw new BadMessageException(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE_431);
+                throw new BadMessageException(_responseStatus, "Response Header Bytes Too Large");
+            }
+        }
+    }
+
+    private boolean quickStartRequestLine(ByteBuffer buffer)
+    {
+        int position = buffer.position();
+        int remaining = buffer.remaining();
+
+        if (remaining >= 2 * Long.BYTES)
+        {
+            // try to match "GET / HTTP/1.x\r\n" with two longs
+            long lookahead = buffer.getLong(position);
+            if (lookahead == GET_SLASH_HT_AS_LONG)
+            {
+                long v = buffer.getLong(position + Long.BYTES);
+                if (v == TP_SLASH_1_1_CRLF_AS_LONG)
+                {
+                    int delta = 2 * Long.BYTES;
+                    buffer.position(position + delta);
+                    addAndCheckHeadersSize(delta);
+                    _methodString = HttpMethod.GET.asString();
+                    _version = HttpVersion.HTTP_1_1;
+                    setState(State.HEADER);
+                    _requestHandler.startRequest(_methodString, "/", _version);
+                    return true;
+                }
+                if (v == TP_SLASH_1_0_CRLF_AS_LONG)
+                {
+                    int delta = 2 * Long.BYTES;
+                    buffer.position(position + delta);
+                    addAndCheckHeadersSize(delta);
+                    _methodString = HttpMethod.GET.asString();
+                    _version = HttpVersion.HTTP_1_0;
+                    setState(State.HEADER);
+                    _requestHandler.startRequest(_methodString, "/", _version);
+                    return true;
+                }
+            }
+            else
+            {
+                // else lookup just the method using the first 4 bytes of the already fetched long as a lookahead.
+                _method = HttpMethod.lookAheadGet(buffer, (int)((lookahead >> 32)));
+            }
+        }
+        else if (remaining >= Integer.BYTES)
+        {
+            // otherwise try a lookahead to match just the method
+            _method = HttpMethod.lookAheadGet(buffer);
+        }
+
+        if (_method != null)
+        {
+            _methodString = _method.asString();
+            // The lookAheadGet method above checks for the trailing space,
+            // so it is safe to move the position 1 more than the method length.
+            int delta = _methodString.length() + 1;
+            buffer.position(position + delta);
+            addAndCheckHeadersSize(delta);
+            setState(State.SPACE1);
+            return true;
+        }
+        return false;
+    }
+
+    private boolean quickStartResponseLine(ByteBuffer buffer)
+    {
+        int position = buffer.position();
+        int remaining = buffer.remaining();
+
+        if (remaining > Long.BYTES)
+        {
+            // Match version as a long
+            long v = buffer.getLong(position);
+            if (v == HTTP_1_1_AS_LONG)
+                _version = HttpVersion.HTTP_1_1;
+            else if (v == HTTP_1_0_AS_LONG)
+                _version = HttpVersion.HTTP_1_0;
+
+            if (_version != null)
+            {
+                position += Long.BYTES;
+
+                // Try to make 200 OK as a long
+                if (remaining > 2 * Long.BYTES &&
+                    buffer.get(position + Long.BYTES) == '\n' &&
+                    buffer.getLong(position) == SPACE_200_OK_CR_AS_LONG)
+                {
+                    buffer.position(position + 9);
+                    addAndCheckHeadersSize(9);
+                    _responseStatus = HttpStatus.OK_200;
+                    setState(State.HEADER);
+                    _responseHandler.startResponse(_version, _responseStatus, "OK");
+                    return true;
+                }
+
+                if (buffer.get(position) == ' ')
+                {
+                    buffer.position(position + 1);
+                    addAndCheckHeadersSize(1);
+                    setState(State.SPACE1);
+                    return true;
+                }
+
+                // Probably a bad version like HTTP/1.11
+                _version = null;
+            }
+        }
+        return false;
+    }
+
     /* Quick lookahead for the start state looking for a request method or an HTTP version,
      * otherwise skip white space until something else to parse.
      */
@@ -503,25 +676,13 @@ public class HttpParser
     {
         if (_requestHandler != null)
         {
-            _method = HttpMethod.lookAheadGet(buffer);
-            if (_method != null)
-            {
-                _methodString = _method.asString();
-                buffer.position(buffer.position() + _methodString.length() + 1);
-
-                setState(State.SPACE1);
+            if (quickStartRequestLine(buffer))
                 return;
-            }
         }
-        else if (_responseHandler != null)
+        else
         {
-            _version = HttpVersion.lookAheadGet(buffer);
-            if (_version != null)
-            {
-                buffer.position(buffer.position() + _version.asString().length() + 1);
-                setState(State.SPACE1);
+            if (quickStartResponseLine(buffer))
                 return;
-            }
         }
 
         // Quick start look
@@ -547,17 +708,9 @@ public class HttpParser
                 case SPACE:
                 case HTAB:
                     throw new IllegalCharacterException(_state, t, buffer);
-
                 default:
                     break;
             }
-
-            // count this white space as a header byte to avoid DOS
-            if (_maxHeaderBytes > 0 && ++_headerBytes > _maxHeaderBytes)
-            {
-                LOG.warn("padding is too large >" + _maxHeaderBytes);
-                throw new BadMessageException(HttpStatus.BAD_REQUEST_400);
-            }
         }
     }
 
@@ -610,23 +763,6 @@ public class HttpParser
             if (t == null)
                 break;
 
-            if (_maxHeaderBytes > 0 && ++_headerBytes > _maxHeaderBytes)
-            {
-                if (_state == State.URI)
-                {
-                    LOG.warn("URI is too large >" + _maxHeaderBytes);
-                    throw new BadMessageException(HttpStatus.URI_TOO_LONG_414);
-                }
-                else
-                {
-                    if (_requestHandler != null)
-                        LOG.warn("request is too large >" + _maxHeaderBytes);
-                    else
-                        LOG.warn("response is too large >" + _maxHeaderBytes);
-                    throw new BadMessageException(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE_431);
-                }
-            }
-
             switch (_state)
             {
                 case METHOD:
@@ -657,7 +793,7 @@ public class HttpParser
                             setState(State.SPACE1);
                             break;
 
-                        case LF:
+                        case EOL:
                             throw new BadMessageException("No URI");
 
                         case ALPHA:
@@ -689,6 +825,8 @@ public class HttpParser
                         case COLON:
                             _string.append(t.getChar());
                             break;
+                        case EOL:
+                            throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "No Status");
                         default:
                             throw new IllegalCharacterException(_state, t, buffer);
                     }
@@ -762,7 +900,7 @@ public class HttpParser
                                 throw new BadMessageException("Bad status");
                             break;
 
-                        case LF:
+                        case EOL:
                             setState(State.HEADER);
                             _responseHandler.startResponse(_version, _responseStatus, null);
                             break;
@@ -773,13 +911,37 @@ public class HttpParser
                     break;
 
                 case URI:
+                    int position = buffer.position();
+                    int remaining = buffer.remaining();
                     switch (t.getType())
                     {
                         case SPACE:
+                            int endOfVersion = position + Long.BYTES;
+                            if (remaining >= (Long.BYTES + 2) &&
+                                buffer.getShort(endOfVersion) == CRLF_AS_SHORT)
+                            {
+                                // try look-ahead for request HTTP Version
+                                long versionAsLong = buffer.getLong(position);
+                                HttpVersion version = versionAsLong == HTTP_1_1_AS_LONG
+                                    ? HttpVersion.HTTP_1_1
+                                    : versionAsLong == HTTP_1_0_AS_LONG ? HttpVersion.HTTP_1_0 : null;
+
+                                if (version != null)
+                                {
+                                    buffer.position(endOfVersion + 2);
+                                    addAndCheckHeadersSize(endOfVersion + 2 - position);
+                                    _version = version;
+                                    _string.setLength(0);
+                                    checkVersion();
+                                    setState(State.HEADER);
+                                    _requestHandler.startRequest(_methodString, _uri.toString(), _version);
+                                    continue;
+                                }
+                            }
                             setState(State.SPACE2);
                             break;
 
-                        case LF:
+                        case EOL:
                             // HTTP/0.9
                             if (complianceViolation(HttpComplianceSection.NO_HTTP_0_9, "No request version"))
                                 throw new BadMessageException(HttpStatus.HTTP_VERSION_NOT_SUPPORTED_505, "HTTP/0.9 not supported");
@@ -817,49 +979,11 @@ public class HttpParser
                         case COLON:
                             _string.setLength(0);
                             _string.append(t.getChar());
-                            if (_responseHandler != null)
-                            {
-                                _length = 1;
-                                setState(State.REASON);
-                            }
-                            else
-                            {
-                                setState(State.REQUEST_VERSION);
-
-                                // try quick look ahead for HTTP Version
-                                HttpVersion version;
-                                if (buffer.position() > 0 && buffer.hasArray())
-                                    version = HttpVersion.lookAheadGet(buffer.array(), buffer.arrayOffset() + buffer.position() - 1, buffer.arrayOffset() + buffer.limit());
-                                else
-                                    version = HttpVersion.CACHE.getBest(buffer, 0, buffer.remaining());
-
-                                if (version != null)
-                                {
-                                    int pos = buffer.position() + version.asString().length() - 1;
-                                    if (pos < buffer.limit())
-                                    {
-                                        byte n = buffer.get(pos);
-                                        if (n == HttpTokens.CARRIAGE_RETURN)
-                                        {
-                                            _cr = true;
-                                            _version = version;
-                                            checkVersion();
-                                            _string.setLength(0);
-                                            buffer.position(pos + 1);
-                                        }
-                                        else if (n == HttpTokens.LINE_FEED)
-                                        {
-                                            _version = version;
-                                            checkVersion();
-                                            _string.setLength(0);
-                                            buffer.position(pos);
-                                        }
-                                    }
-                                }
-                            }
+                            _length = 1;
+                            setState(_requestHandler != null ? State.REQUEST_VERSION : State.REASON);
                             break;
 
-                        case LF:
+                        case EOL:
                             if (_responseHandler != null)
                             {
                                 setState(State.HEADER);
@@ -887,7 +1011,7 @@ public class HttpParser
                 case REQUEST_VERSION:
                     switch (t.getType())
                     {
-                        case LF:
+                        case EOL:
                             if (_version == null)
                             {
                                 _length = _string.length();
@@ -905,7 +1029,57 @@ public class HttpParser
                         case TCHAR:
                         case VCHAR:
                         case COLON:
-                            _string.append(t.getChar());
+                            if (_string.length() == 0)
+                            {
+                                // This is the first char of the version, so try a quick lookup
+                                HttpVersion version = HttpVersion.CACHE.getBest(buffer);
+                                if (version != null)
+                                {
+                                    String versionString = version.asString();
+                                    buffer.position(buffer.position() + versionString.length());
+                                    addAndCheckHeadersSize(versionString.length());
+
+                                    HttpTokens.Token next = next(buffer);
+                                    if (next == null)
+                                    {
+                                        // No EOL yet, so this version could just be a prefix to the full version
+                                        // So we just append the version string and continue
+                                        _string.append(versionString);
+                                    }
+                                    else
+                                    {
+                                        switch (next.getType())
+                                        {
+                                            case EOL:
+                                                // We have an EOL, so this is the full version, thus we can complete the request line
+                                                _version = version;
+                                                checkVersion();
+                                                setState(State.HEADER);
+                                                _requestHandler.startRequest(_methodString, _uri.toString(), _version);
+                                                break;
+
+                                            case SPACE:
+                                            case ALPHA:
+                                            case DIGIT:
+                                            case TCHAR:
+                                            case VCHAR:
+                                            case COLON:
+                                                // This version was just a prefix to the full version, so append it and the next char and continue
+                                                _string.append(versionString);
+                                                _string.append(next.getChar());
+                                                break;
+
+                                            default:
+                                                throw new IllegalCharacterException(_state, next, buffer);
+                                        }
+                                    }
+                                }
+                            }
+                            else
+                            {
+                                // We already have some version chars, so just append this one
+                                _string.append(t.getChar());
+                            }
                             break;
 
                         default:
@@ -916,7 +1090,7 @@ public class HttpParser
                 case REASON:
                     switch (t.getType())
                     {
-                        case LF:
+                        case EOL:
                             String reason = takeString();
                             setState(State.HEADER);
                             _responseHandler.startResponse(_version, _responseStatus, reason);
@@ -1133,15 +1307,6 @@ public class HttpParser
             if (t == null)
                 break;
 
-            if (_maxHeaderBytes > 0 && ++_headerBytes > _maxHeaderBytes)
-            {
-                boolean header = _state == State.HEADER;
-                LOG.warn("{} is too large {}>{}", header ? "Header" : "Trailer", _headerBytes, _maxHeaderBytes);
-                throw new BadMessageException(header
-                    ? HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE_431
-                    : HttpStatus.PAYLOAD_TOO_LARGE_413);
-            }
-
             switch (_fieldState)
             {
                 case FIELD:
@@ -1171,7 +1336,7 @@ public class HttpParser
                             break;
                         }
 
-                        case LF:
+                        case EOL:
                         {
                             // process previous header
                             if (_state == State.HEADER)
@@ -1225,30 +1390,27 @@ public class HttpParser
                             }
 
                             // How is the message ended?
+                            boolean handle = _handler.headerComplete();
+                            _headerComplete = true;
                             switch (_endOfContent)
                             {
                                 case EOF_CONTENT:
                                 {
                                     setState(State.EOF_CONTENT);
-                                    boolean handle = _handler.headerComplete();
-                                    _headerComplete = true;
-                                    return handle;
+                                    break;
                                 }
                                 case CHUNKED_CONTENT:
                                 {
                                     setState(State.CHUNKED_CONTENT);
-                                    boolean handle = _handler.headerComplete();
-                                    _headerComplete = true;
-                                    return handle;
+                                    break;
                                 }
                                 default:
                                 {
                                     setState(State.CONTENT);
-                                    boolean handle = _handler.headerComplete();
-                                    _headerComplete = true;
-                                    return handle;
+                                    break;
                                 }
                             }
+                            return handle;
                         }
 
                         case ALPHA:
@@ -1265,9 +1427,9 @@ public class HttpParser
                             if (buffer.hasRemaining())
                             {
                                 // Try a look ahead for the known header name and value.
-                                HttpField cachedField = _fieldCache == null ? null : _fieldCache.getBest(buffer, -1, buffer.remaining());
+                                HttpField cachedField = _fieldCache == null ? null : _fieldCache.getBest(buffer, -1, buffer.remaining() + 1);
                                 if (cachedField == null)
-                                    cachedField = CACHE.getBest(buffer, -1, buffer.remaining());
+                                    cachedField = CACHE.getBest(buffer, -1, buffer.remaining() + 1);
 
                                 if (cachedField != null)
                                 {
@@ -1300,37 +1462,43 @@ public class HttpParser
                                     _header = cachedField.getHeader();
                                     _headerString = n;
 
-                                    if (v == null)
+                                    int position = buffer.position();
+                                    int delta = n.length() + 1;
+                                    int posAfterName = position + delta;
+
+                                    if (v == null || (posAfterName + v.length()) >= buffer.limit())
                                     {
                                         // Header only
                                         setState(FieldState.VALUE);
                                         _string.setLength(0);
                                         _length = 0;
-                                        buffer.position(buffer.position() + n.length() + 1);
+                                        buffer.position(posAfterName);
+                                        addAndCheckHeadersSize(delta);
                                         break;
                                     }
 
                                     // Header and value
-                                    int pos = buffer.position() + n.length() + v.length() + 1;
-                                    byte peek = buffer.get(pos);
+                                    int posAfterValue = posAfterName + v.length();
+                                    byte peek = buffer.get(posAfterValue);
                                     if (peek == HttpTokens.CARRIAGE_RETURN || peek == HttpTokens.LINE_FEED)
                                     {
                                         _field = cachedField;
                                         _valueString = v;
-                                        setState(FieldState.IN_VALUE);
-
-                                        if (peek == HttpTokens.CARRIAGE_RETURN)
+                                        buffer.position(posAfterValue + 1);
+                                        addAndCheckHeadersSize(posAfterValue + 1 - position);
+                                        if (peek == HttpTokens.LINE_FEED)
                                         {
-                                            _cr = true;
-                                            buffer.position(pos + 1);
+                                            setState(FieldState.FIELD);
+                                            break;
                                         }
-                                        else
-                                            buffer.position(pos);
+                                        setState(FieldState.IN_VALUE);
+                                        _cr = true;
                                         break;
                                     }
                                     setState(FieldState.IN_VALUE);
                                     setString(v);
-                                    buffer.position(pos);
+                                    buffer.position(posAfterValue);
+                                    addAndCheckHeadersSize(posAfterValue - position);
                                     break;
                                 }
                             }
@@ -1371,7 +1539,7 @@ public class HttpParser
                             setState(FieldState.VALUE);
                             break;
 
-                        case LF:
+                        case EOL:
                             _headerString = takeString();
                             _header = HttpHeader.CACHE.get(_headerString);
                             _string.setLength(0);
@@ -1409,7 +1577,7 @@ public class HttpParser
                             setState(FieldState.VALUE);
                             break;
 
-                        case LF:
+                        case EOL:
                             if (!complianceViolation(HttpComplianceSection.FIELD_COLON, _headerString))
                             {
                                 setState(FieldState.FIELD);
@@ -1425,7 +1593,7 @@ public class HttpParser
                 case VALUE:
                     switch (t.getType())
                     {
-                        case LF:
+                        case EOL:
                             _string.setLength(0);
                             _valueString = "";
                             _length = -1;
@@ -1456,7 +1624,7 @@ public class HttpParser
                 case IN_VALUE:
                     switch (t.getType())
                     {
-                        case LF:
+                        case EOL:
                             if (_length > 0)
                             {
                                 _valueString = takeString();
@@ -1572,6 +1740,7 @@ public class HttpParser
                     if (b != HttpTokens.CARRIAGE_RETURN && b != HttpTokens.LINE_FEED)
                         break;
                     buffer.get();
+                    addAndCheckHeadersSize(1);
                     ++whiteSpace;
                 }
                 if (debug && whiteSpace > 0)
@@ -1615,7 +1784,6 @@ public class HttpParser
                     case CONTENT:
                     case CHUNKED_CONTENT:
                     case CHUNK_SIZE:
-                    case CHUNK_PARAMS:
                     case CHUNK:
                         setState(State.CLOSED);
                         _handler.earlyEOF();
@@ -1625,7 +1793,10 @@ public class HttpParser
                         if (debug)
                             LOG.debug("{} EOF in {}", this, _state);
                         setState(State.CLOSED);
-                        _handler.badMessage(new BadMessageException(HttpStatus.BAD_REQUEST_400));
+                        if (_requestHandler != null)
+                            _handler.badMessage(new BadMessageException(HttpStatus.BAD_REQUEST_400, "Early EOF"));
+                        else
+                            _handler.badMessage(new BadMessageException(_responseStatus, "Early EOF"));
                         break;
                 }
             }
@@ -1684,7 +1855,7 @@ public class HttpParser
             switch (_state)
             {
                 case EOF_CONTENT:
-                    _contentChunk = buffer.asReadOnlyBuffer();
+                    _contentChunk = buffer.slice();
                     _contentPosition += remaining;
                     buffer.position(buffer.position() + remaining);
                     if (_handler.content(_contentChunk))
@@ -1701,18 +1872,17 @@ public class HttpParser
                     }
                     else
                     {
-                        _contentChunk = buffer.asReadOnlyBuffer();
-
-                        // limit content by expected size
-                        if (remaining > content)
+                        int length = remaining;
+                        // Limit the content by the expected length if _contentLength is >= 0 (i.e.: not infinite).
+                        if (_contentLength > -1 && remaining > content)
                         {
-                            // We can cast remaining to an int as we know that it is smaller than
-                            // or equal to length which is already an int.
-                            _contentChunk.limit(_contentChunk.position() + (int)content);
+                            // The cast to int is safe, since remaining is an int.
+                            length = (int)content;
                         }
+                        _contentChunk = ((ByteBuffer)buffer.duplicate().limit(buffer.position() + length)).slice();
 
-                        _contentPosition += _contentChunk.remaining();
-                        buffer.position(buffer.position() + _contentChunk.remaining());
+                        _contentPosition += length;
+                        buffer.position(buffer.position() + length);
 
                         if (_handler.content(_contentChunk))
                             return true;
@@ -1731,14 +1901,12 @@ public class HttpParser
                     HttpTokens.Token t = next(buffer);
                     if (t == null)
                         break;
+
+                    _chunkPosition = 0;
                     switch (t.getType())
                     {
-                        case LF:
-                            break;
-
                         case DIGIT:
                             _chunkLength = t.getHexDigit();
-                            _chunkPosition = 0;
                             setState(State.CHUNK_SIZE);
                             break;
 
@@ -1746,7 +1914,6 @@ public class HttpParser
                             if (t.isHexDigit())
                             {
                                 _chunkLength = t.getHexDigit();
-                                _chunkPosition = 0;
                                 setState(State.CHUNK_SIZE);
                                 break;
                             }
@@ -1760,89 +1927,42 @@ public class HttpParser
 
                 case CHUNK_SIZE:
                 {
-                    HttpTokens.Token t = next(buffer);
-                    if (t == null)
-                        break;
-
-                    switch (t.getType())
-                    {
-                        case LF:
-                            if (_chunkLength == 0)
-                            {
-                                setState(State.TRAILER);
-                                if (_handler.contentComplete())
-                                    return true;
-                            }
-                            else
-                                setState(State.CHUNK);
-                            break;
-
-                        case SPACE:
-                            setState(State.CHUNK_PARAMS);
-                            break;
-
-                        default:
-                            if (t.isHexDigit())
-                            {
-                                if (_chunkLength > MAX_CHUNK_LENGTH)
-                                    throw new BadMessageException(HttpStatus.PAYLOAD_TOO_LARGE_413);
-                                _chunkLength = _chunkLength * 16 + t.getHexDigit();
-                            }
-                            else
-                            {
-                                setState(State.CHUNK_PARAMS);
-                            }
-                    }
-                    break;
-                }
-
-                case CHUNK_PARAMS:
-                {
-                    HttpTokens.Token t = next(buffer);
-                    if (t == null)
-                        break;
-
-                    switch (t.getType())
-                    {
-                        case LF:
-                            if (_chunkLength == 0)
-                            {
-                                setState(State.TRAILER);
-                                if (_handler.contentComplete())
-                                    return true;
-                            }
-                            else
-                                setState(State.CHUNK);
-                            break;
-                        default:
-                            break; // TODO review
-                    }
+                    if (parseChunkSize(buffer))
+                        return true;
                     break;
                 }
-
                 case CHUNK:
                 {
-                    int chunk = _chunkLength - _chunkPosition;
-                    if (chunk == 0)
+                    long chunkLength = _chunkLength - _chunkPosition;
+                    if (chunkLength == 0)
                     {
-                        setState(State.CHUNKED_CONTENT);
+                        setState(State.CHUNK_END);
                     }
                     else
                     {
-                        _contentChunk = buffer.asReadOnlyBuffer();
+                        int length = (int)Math.min(remaining, chunkLength);
+                        _contentChunk = ((ByteBuffer)buffer.duplicate().limit(buffer.position() + length)).slice();
 
-                        if (remaining > chunk)
-                            _contentChunk.limit(_contentChunk.position() + chunk);
-                        chunk = _contentChunk.remaining();
-
-                        _contentPosition += chunk;
-                        _chunkPosition += chunk;
-                        buffer.position(buffer.position() + chunk);
+                        _contentPosition += length;
+                        _chunkPosition += length;
+                        buffer.position(buffer.position() + length);
                         if (_handler.content(_contentChunk))
                             return true;
                     }
                     break;
                 }
+                case CHUNK_END:
+                {
+                    HttpTokens.Token t = next(buffer);
+                    if (t == null)
+                        break;
+
+                    // We must be exactly on a line-terminator after consuming the chunk.
+                    if (t.getType() != HttpTokens.Type.EOL)
+                        throw new IllegalCharacterException(_state, t, buffer);
+                    setState(State.CHUNKED_CONTENT);
+                    break;
+                }
 
                 case CONTENT_END:
                 {
@@ -1859,6 +1979,230 @@ public class HttpParser
         return false;
     }
 
+    private boolean parseChunkSize(ByteBuffer buffer)
+    {
+        while (_state == State.CHUNK_SIZE && buffer.hasRemaining())
+        {
+            HttpTokens.Token t = next(buffer);
+            if (t == null)
+                break;
+
+            switch (_chunkSizeState)
+            {
+                case SIZE:
+                {
+                    if (t.getType() == HttpTokens.Type.EOL)
+                    {
+                        if (chunkSizeEnd(t))
+                            return true;
+                    }
+                    else if (t.isHexDigit())
+                    {
+                        if (++_chunkSizeDigits == 16)
+                            throw new BadMessageException(HttpStatus.BAD_REQUEST_400);
+                        _chunkLength = _chunkLength * 16 + t.getHexDigit();
+                        // Check for overflow.
+                        if (_chunkLength < 0)
+                            throw new BadMessageException(HttpStatus.BAD_REQUEST_400);
+                    }
+                    else if (isBWS(t))
+                        setChunkSizeState(ChunkSizeState.EXT_BWS);
+                    else if (t.getChar() == ';')
+                        setChunkSizeState(ChunkSizeState.EXT_NAME_BWS_BEFORE);
+                    else
+                        throw new IllegalCharacterException(_state, t, buffer);
+                    break;
+                }
+                case EXT_BWS:
+                {
+                    if (t.getChar() == ';')
+                        setChunkSizeState(ChunkSizeState.EXT_NAME_BWS_BEFORE);
+                    else if (!isBWS(t))
+                        throw new IllegalCharacterException(_state, t, buffer);
+                    break;
+                }
+                case EXT_NAME_BWS_BEFORE:
+                {
+                    if (isTchar(t))
+                        setChunkSizeState(ChunkSizeState.EXT_NAME);
+                    else if (!isBWS(t))
+                        throw new IllegalCharacterException(_state, t, buffer);
+                    break;
+                }
+                case EXT_NAME:
+                {
+                    if (t.getType() == HttpTokens.Type.EOL)
+                    {
+                        if (chunkSizeEnd(t))
+                            return true;
+                    }
+                    else if (t.getChar() == ';')
+                        setChunkSizeState(ChunkSizeState.EXT_NAME_BWS_BEFORE);
+                    else if (isBWS(t))
+                        setChunkSizeState(ChunkSizeState.EXT_NAME_BWS_AFTER);
+                    else if (t.getChar() == '=')
+                        setChunkSizeState(ChunkSizeState.EXT_VALUE_BWS_BEFORE);
+                    else if (!isTchar(t))
+                        throw new IllegalCharacterException(_state, t, buffer);
+                    break;
+                }
+                case EXT_NAME_BWS_AFTER:
+                {
+                    if (t.getChar() == ';')
+                        setChunkSizeState(ChunkSizeState.EXT_NAME_BWS_BEFORE);
+                    else if (t.getChar() == '=')
+                        setChunkSizeState(ChunkSizeState.EXT_VALUE_BWS_BEFORE);
+                    else if (!isBWS(t))
+                        throw new IllegalCharacterException(_state, t, buffer);
+                    break;
+                }
+                case EXT_VALUE_BWS_BEFORE:
+                {
+                    if (t.getChar() == '"')
+                        setChunkSizeState(ChunkSizeState.EXT_VALUE_OPEN_QUOTE);
+                    else if (isTchar(t))
+                        setChunkSizeState(ChunkSizeState.EXT_VALUE);
+                    else if (!isBWS(t))
+                        throw new IllegalCharacterException(_state, t, buffer);
+                    break;
+                }
+                case EXT_VALUE_OPEN_QUOTE:
+                {
+                    if (_chunkQuotedEscape)
+                    {
+                        if (!isQuotedPair(t))
+                            throw new IllegalCharacterException(_state, t, buffer);
+                        _chunkQuotedEscape = false;
+                    }
+                    else if (t.getChar() == '\\')
+                        _chunkQuotedEscape = true;
+                    else if (t.getChar() == '"')
+                        setChunkSizeState(ChunkSizeState.EXT_VALUE_CLOSE_QUOTE);
+                    else if (!isQdText(t))
+                        throw new IllegalCharacterException(_state, t, buffer);
+                    break;
+                }
+                case EXT_VALUE:
+                {
+                    if (t.getType() == HttpTokens.Type.EOL)
+                    {
+                        if (chunkSizeEnd(t))
+                            return true;
+                    }
+                    else if (isBWS(t))
+                        setChunkSizeState(ChunkSizeState.EXT_BWS);
+                    else if (t.getChar() == ';')
+                        setChunkSizeState(ChunkSizeState.EXT_NAME_BWS_BEFORE);
+                    else if (!isTchar(t))
+                        throw new IllegalCharacterException(_state, t, buffer);
+                    break;
+                }
+                case EXT_VALUE_CLOSE_QUOTE:
+                {
+                    if (t.getType() == HttpTokens.Type.EOL)
+                    {
+                        if (chunkSizeEnd(t))
+                            return true;
+                    }
+                    else if (isBWS(t))
+                        setChunkSizeState(ChunkSizeState.EXT_BWS);
+                    else if (t.getChar() == ';')
+                        setChunkSizeState(ChunkSizeState.EXT_NAME_BWS_BEFORE);
+                    else
+                        throw new IllegalCharacterException(_state, t, buffer);
+                    break;
+                }
+            }
+        }
+        return false;
+    }
+
+    private boolean chunkSizeEnd(HttpTokens.Token t)
+    {
+        setChunkSizeState(ChunkSizeState.SIZE);
+        _chunkSizeDigits = 0;
+        if (_chunkLength == 0)
+        {
+            setState(State.TRAILER);
+            return _handler.contentComplete();
+        }
+        else
+        {
+            setState(State.CHUNK);
+            return false;
+        }
+    }
+
+    /**
+     * Bad white space is defined in RFC-9110[5.6.3].
+     *
+     * @param t the token
+     * @return whether the token is a bad white space
+     */
+    private boolean isBWS(HttpTokens.Token t)
+    {
+        return t.getType() == HttpTokens.Type.SPACE || t.getType() == HttpTokens.Type.HTAB;
+    }
+
+    /**
+     * Token and token characters are defined in RFC-9110[5.6.2].
+     *
+     * @param t the token
+     * @return whether the token is a token character
+     */
+    private boolean isTchar(HttpTokens.Token t)
+    {
+        return t.getType() == HttpTokens.Type.TCHAR ||
+               t.getType() == HttpTokens.Type.DIGIT ||
+               t.getType() == HttpTokens.Type.ALPHA;
+    }
+
+    /**
+     * Text inside quotes (qdtext) is defined in RFC-9110[5.6.4].
+     *
+     * @param t the token
+     * @return whether the token is quoted text
+     */
+    private boolean isQdText(HttpTokens.Token t)
+    {
+        switch (t.getType())
+        {
+            case HTAB:
+            case SPACE:
+            case OTEXT:
+                return true;
+            default:
+                char c = t.getChar();
+                return c == 0x21 ||
+                      (c >= 0x23 && c <= 0x5B) ||
+                      (c >= 0x5D && c <= 0x7E);
+        }
+    }
+
+    /**
+     * Escaped text inside quotes (quoted-pair) is defined in RFC-9110[5.6.4].
+     *
+     * @param t the token
+     * @return whether the token is a quoted pair
+     */
+    private boolean isQuotedPair(HttpTokens.Token t)
+    {
+        switch (t.getType())
+        {
+            case HTAB:
+            case SPACE:
+            case COLON:
+            case TCHAR:
+            case VCHAR:
+            case DIGIT:
+            case ALPHA:
+            case OTEXT:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     public boolean isAtEOF()
     {
         return _eof;
@@ -1893,17 +2237,35 @@ public class HttpParser
         if (_state == State.CLOSE || _state == State.CLOSED)
             return;
 
-        setState(State.START);
-        _endOfContent = EndOfContent.UNKNOWN_CONTENT;
-        _contentLength = -1;
+        _uri.reset();
+        _string.setLength(0);
+        _field = null;
+        _header = null;
+        _headerString = null;
+        _valueString = null;
+        _responseStatus = 0;
+        _headerBytes = 0;
+        _headerComplete = false;
+        _state = State.START;
+        _fieldState = FieldState.FIELD;
+        _eof = false;
+        _method = null;
+        _methodString = null;
+        _version = null;
+        _endOfContent = EndOfContent.UNKNOWN_CONTENT;;
         _hasContentLength = false;
         _hasTransferEncoding = false;
+        _contentLength = -1;
         _contentPosition = 0;
-        _responseStatus = 0;
+        _chunkLength = 0;
+        _chunkPosition = 0;
+        _headResponse = false;
+        _cr = false;
         _contentChunk = null;
-        _headerBytes = 0;
+        _length = 0;
+        _chunkSizeState = ChunkSizeState.SIZE;
+        _chunkQuotedEscape = false;
         _host = false;
-        _headerComplete = false;
     }
 
     protected void setState(State state)
@@ -1920,6 +2282,13 @@ public class HttpParser
         _fieldState = state;
     }
 
+    private void setChunkSizeState(ChunkSizeState state)
+    {
+        if (debug)
+            LOG.debug("{}:{} --> {}", _state, _chunkSizeState, state);
+        _chunkSizeState = state;
+    }
+
     public Trie<HttpField> getFieldCache()
     {
         return _fieldCache;
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java
index 720faf4dd07..7000c82f9bd 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java
@@ -43,6 +43,7 @@ public class HttpTokens
         HTAB,    // Horizontal tab 
         LF,      // Line feed
         CR,      // Carriage return
+        EOL,     // A CRLF or LF (depending on configuration)
         SPACE,   // Space 
         COLON,   // Colon character
         DIGIT,   // Digit
@@ -118,6 +119,8 @@ public class HttpTokens
         }
     }
 
+    public static final Token EOL_LF = new Token(LINE_FEED, Type.EOL);
+    public static final Token EOL_CRLF = new Token(LINE_FEED, Type.EOL);
     public static final Token[] TOKENS = new Token[256];
 
     static
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
@@ -1030,7 +1030,7 @@ public class HttpParserTest
                 "Header1: value1\r\n" +
                 "Transfer-Encoding: chunked\r\n" +
                 "\r\n" +
-                "a;\r\n" +
+                "a;ext\r\n" +
                 "0123456789\r\n" +
                 "1a\r\n" +
                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n" +
@@ -1060,7 +1060,7 @@ public class HttpParserTest
                 "Header1: value1\r\n" +
                 "Transfer-Encoding: chunked, identity\r\n" +
                 "\r\n" +
-                "a;\r\n" +
+                "a;ext\r\n" +
                 "0123456789\r\n" +
                 "1a\r\n" +
                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n" +
@@ -1084,7 +1084,7 @@ public class HttpParserTest
                 "Header1: value1\r\n" +
                 "Transfer-Encoding: chunked\r\n" +
                 "\r\n" +
-                "a;\r\n" +
+                "a;ext\r\n" +
                 "0123456789\r\n" +
                 "1a\r\n" +
                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n" +
@@ -1118,7 +1118,7 @@ public class HttpParserTest
             "GET /chunk HTTP/1.0\r\n" +
                 "Transfer-Encoding: chunked\r\n" +
                 "\r\n" +
-                "a;\r\n" +
+                "a;ext\r\n" +
                 "0123456789\r\n" +
                 "1a\r\n" +
                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n" +
@@ -1157,7 +1157,7 @@ public class HttpParserTest
                 "Header1: value1\r\n" +
                 "Transfer-Encoding: chunked\r\n" +
                 "\r\n" +
-                "a;\r\n" +
+                "a;ext\r\n" +
                 "0123456789\r\n" +
                 "1a\r\n" +
                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n" +
@@ -1189,7 +1189,7 @@ public class HttpParserTest
                 "Header1: value1\r\n" +
                 "Transfer-Encoding: chunked\r\n" +
                 "\r\n" +
-                "a;\r\n" +
+                "a;ext\r\n" +
                 "0123456789\r\n" +
                 "1a\r\n" +
                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n" +
@@ -1253,7 +1253,7 @@ public class HttpParserTest
                 "Header1: value1\r\n" +
                 "Transfer-Encoding: chunked\r\n" +
                 "\r\n" +
-                "a;\r\n" +
+                "a;ext\r\n" +
                 "0123456789\r\n");
         HttpParser.RequestHandler handler = new Handler();
         HttpParser parser = new HttpParser(handler);
@@ -1280,7 +1280,7 @@ public class HttpParserTest
                 "Header1: value1\r\n" +
                 "Transfer-Encoding: chunked\r\n" +
                 "\r\n" +
-                "a;\r\n" +
+                "a;ext\r\n" +
                 "0123456789\r\n" +
                 "1a\r\n" +
                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n" +
@@ -1346,7 +1346,7 @@ public class HttpParserTest
         ByteBuffer buffer1 = BufferUtil.toBuffer("Header1: value1\r\n" +
             "Transfer-Encoding: chunked\r\n" +
             "\r\n" +
-            "a;\r\n" +
+            "a;ext\r\n" +
             "0123456789\r\n" +
             "1a\r\n" +
             "ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n" +
--- /dev/null
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ChunkSizeExtensionTest.java
@@ -0,0 +1,308 @@
+//
+// ========================================================================
+// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License v. 2.0 which is available at
+// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+// ========================================================================
+//
+
+package org.eclipse.jetty.server;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.http.HttpTester;
+import org.eclipse.jetty.server.handler.ErrorHandler;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+
+public class ChunkSizeExtensionTest
+{
+    private Server _server;
+    private LocalConnector _connector;
+
+    @BeforeEach
+    public void init() throws Exception
+    {
+        _server = new Server();
+
+        HttpConfiguration config = new HttpConfiguration();
+        config.setRequestHeaderSize(1024);
+        config.setResponseHeaderSize(1024);
+        config.setSendDateHeader(true);
+        HttpConnectionFactory http = new HttpConnectionFactory(config);
+
+        _connector = new LocalConnector(_server, http, null);
+        _connector.setIdleTimeout(5000);
+        _server.addConnector(_connector);
+        _server.setHandler(new DumpHandler());
+        ErrorHandler eh = new ErrorHandler();
+        eh.setServer(_server);
+        _server.addBean(eh);
+        _server.start();
+    }
+
+    @AfterEach
+    public void destroy() throws Exception
+    {
+        _server.stop();
+        _server.join();
+    }
+
+    private void consumeRequest(InputStream in) throws IOException
+    {
+        byte[] buffer = new byte[1024];
+        while (in.read(buffer) != -1);
+    }
+
+    @ParameterizedTest
+    @ValueSource(booleans = {false, true})
+    public void testExtensionNoValue(boolean bws) throws Exception
+    {
+        String ws = bws ? "\t" : "";
+
+        String request = String.format(
+            "POST / HTTP/1.1\r\n" +
+            "Host: localhost\r\n" +
+            "Transfer-Encoding: chunked\r\n" +
+            "\r\n" +
+            "10%sW;%sWext\r\n" +
+            "0123456789ABCDEF\r\n" +
+            "0\r\n" +
+            "\r\n",
+            ws, ws
+        );
+
+        String rawResponse = _connector.getResponses(request);
+        HttpTester.Response response = HttpTester.parseResponse(rawResponse);
+        assertThat(response.getStatus(), equalTo(HttpStatus.OK_200));
+    }
+
+    @ParameterizedTest
+    @ValueSource(booleans = {false, true})
+    public void testExtensionWithValue(boolean bws) throws Exception
+    {
+        String ws = bws ? "\t" : "";
+
+        String request = String.format(
+            "POST / HTTP/1.1\r\n" +
+            "Host: localhost\r\n" +
+            "Transfer-Encoding: chunked\r\n" +
+            "\r\n" +
+            "10%sW;%sWext\r\n" +
+            "0123456789ABCDEF\r\n" +
+            "0\r\n" +
+            "\r\n",
+            ws, ws
+        );
+
+        String rawResponse = _connector.getResponses(request);
+        HttpTester.Response response = HttpTester.parseResponse(rawResponse);
+        assertThat(response.getStatus(), equalTo(HttpStatus.OK_200));
+    }
+
+    @ParameterizedTest
+    @ValueSource(booleans = {false, true})
+    public void testExtensionWithQuotedValue(boolean bws) throws Exception
+    {
+        String ws = bws ? "\t" : "";
+
+        String request = String.format(
+            "POST / HTTP/1.1\r\n" +
+            "Host: localhost\r\n" +
+            "Transfer-Encoding: chunked\r\n" +
+            "\r\n" +
+            "1%sW;%sWext%s=%s\"val\"\r\n" +
+            "X\r\n" +
+            "0\r\n" +
+            "\r\n",
+            ws, ws, ws, ws
+        );
+
+        String rawResponse = _connector.getResponses(request);
+        HttpTester.Response response = HttpTester.parseResponse(rawResponse);
+        assertThat(response.getStatus(), equalTo(HttpStatus.OK_200));
+    }
+
+    @ParameterizedTest
+    @ValueSource(booleans = {false, true})
+    public void testMultipleExtensionsNoValues(boolean bws) throws Exception
+    {
+        String ws = bws ? "\t" : "";
+
+        String request = String.format(
+            "POST / HTTP/1.1\r\n" +
+            "Host: localhost\r\n" +
+            "Transfer-Encoding: chunked\r\n" +
+            "\r\n" +
+            "4%sW;%sWext1%s;%sWext2\r\n" +
+            "0123\r\n" +
+            "0\r\n" +
+            "\r\n",
+            ws, ws, ws, ws
+        );
+
+        String rawResponse = _connector.getResponses(request);
+        HttpTester.Response response = HttpTester.parseResponse(rawResponse);
+        assertThat(response.getStatus(), equalTo(HttpStatus.OK_200));
+    }
+
+    @ParameterizedTest
+    @ValueSource(booleans = {false, true})
+    public void testMultipleExtensionsWithValues(boolean bws) throws Exception
+    {
+        String ws = bws ? "\t" : "";
+
+        String request = String.format(
+            "POST / HTTP/1.1\r\n" +
+            "Host: localhost\r\n" +
+            "Transfer-Encoding: chunked\r\n" +
+            "\r\n" +
+            "4%sW;%sWext1%s=%s1%s;%sWext2%s=%s2\r\n" +
+            "0123\r\n" +
+            "0\r\n" +
+            "\r\n",
+            ws, ws, ws, ws, ws, ws, ws, ws
+        );
+
+        String rawResponse = _connector.getResponses(request);
+        HttpTester.Response response = HttpTester.parseResponse(rawResponse);
+        assertThat(response.getStatus(), equalTo(HttpStatus.OK_200));
+    }
+
+    @ParameterizedTest
+    @ValueSource(booleans = {false, true})
+    public void testMultipleExtensionsWithQuotes(boolean bws) throws Exception
+    {
+        String ws = bws ? "\t" : "";
+
+        String request = String.format(
+            "POST / HTTP/1.1\r\n" +
+            "Host: localhost\r\n" +
+            "Transfer-Encoding: chunked\r\n" +
+            "\r\n" +
+            "4%sW;%sWext1%s=%s\"1\"%s;%sWext2%s=%s\"2\"\r\n" +
+            "0123\r\n" +
+            "0\r\n" +
+            "\r\n",
+            ws, ws, ws, ws, ws, ws, ws, ws
+        );
+
+        String rawResponse = _connector.getResponses(request);
+        HttpTester.Response response = HttpTester.parseResponse(rawResponse);
+        assertThat(response.getStatus(), equalTo(HttpStatus.OK_200));
+    }
+
+    @Test
+    public void testEmptyExtension() throws Exception
+    {
+        String request =
+            "POST / HTTP/1.1\r\n" +
+            "Host: localhost\r\n" +
+            "Transfer-Encoding: chunked\r\n" +
+            "\r\n" +
+            "a;\r\n" +
+            "0123456789\r\n" +
+            "0\r\n" +
+            "\r\n";
+
+        String rawResponse = _connector.getResponses(request);
+        System.out.println("Fridrich: " + rawResponse);
+        HttpTester.Response response = HttpTester.parseResponse(rawResponse);
+        assertThat(response.getStatus(), equalTo(HttpStatus.OK_200));
+        assertThat(rawResponse, containsString("Connection: close"));
+        assertThat(rawResponse, containsString("Early EOF"));
+
+    }
+
+    @Test
+    public void testQuotesWithinQuotes() throws Exception
+    {
+        String request =
+            "POST / HTTP/1.1\r\n" +
+            "Host: localhost\r\n" +
+            "Transfer-Encoding: chunked\r\n" +
+            "\r\n" +
+            "1;a=\"\\\"val\\\"\"\r\n" +
+            "X\r\n" +
+            "0\r\n" +
+            "\r\n";
+
+        String rawResponse = _connector.getResponses(request);
+        HttpTester.Response response = HttpTester.parseResponse(rawResponse);
+        assertThat(response.getStatus(), equalTo(HttpStatus.OK_200));
+    }
+
+    @ParameterizedTest
+    @ValueSource(booleans = {false, true})
+    public void testTerminalChunkWithExtension(boolean quoted) throws Exception
+    {
+        String q = quoted ? "\"" : "";
+
+        String request = String.format(
+            "POST / HTTP/1.1\r\n" +
+            "Host: localhost\r\n" +
+            "Transfer-Encoding: chunked\r\n" +
+            "\r\n" +
+            "a\r\n" +
+            "0123456789\r\n" +
+            "0;ext=%sQ1%s\r\n" +
+            "\r\n",
+            q, q
+        );
+
+        String rawResponse = _connector.getResponses(request);
+        HttpTester.Response response = HttpTester.parseResponse(rawResponse);
+        assertThat(response.getStatus(), equalTo(HttpStatus.OK_200));
+    }
+
+    @Test
+    public void testTerminalChunkWithExtensionNoValue() throws Exception
+    {
+        String request =
+            "POST / HTTP/1.1\r\n" +
+            "Host: localhost\r\n" +
+            "Transfer-Encoding: chunked\r\n" +
+            "\r\n" +
+            "a\r\n" +
+            "0123456789\r\n" +
+            "0;ext\r\n" +
+            "\r\n";
+
+        String rawResponse = _connector.getResponses(request);
+        HttpTester.Response response = HttpTester.parseResponse(rawResponse);
+        assertThat(response.getStatus(), equalTo(HttpStatus.OK_200));
+    }
+
+    @Test
+    public void testTerminalChunkWithExtensionWithTrailers() throws Exception
+    {
+        String request =
+            "POST / HTTP/1.1\r\n" +
+            "Host: localhost\r\n" +
+            "Transfer-Encoding: chunked\r\n" +
+            "\r\n" +
+            "a\r\n" +
+            "0123456789\r\n" +
+            "0;ext\r\n" +
+            "Trailer: value\r\n" +
+            "\r\n";
+
+        String rawResponse = _connector.getResponses(request);
+        HttpTester.Response response = HttpTester.parseResponse(rawResponse);
+        assertThat(response.getStatus(), equalTo(HttpStatus.OK_200));
+    }
+}
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java
@@ -65,6 +65,7 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.ValueSource;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsString;
@@ -124,9 +125,9 @@ public class HttpConnectionTest
                 "Content-Type: text/plain\r\n" +
                 "Connection: close\r\n" +
                 "\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "12345\r\n" +
-                "0;\r\n" +
+                "0\r\n" +
                 "\r\n");
             offset = checkContains(response, offset, "HTTP/1.1 200");
             offset = checkContains(response, offset, "/R1");
@@ -139,9 +140,9 @@ public class HttpConnectionTest
                 "Content-Type: text/plain\r\n" +
                 "Connection: close\r\n" +
                 "\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "ABCDE\r\n" +
-                "0;\r\n" +
+                "0\r\n" +
                 "\r\n");
             offset = checkContains(response, offset, "HTTP/1.1 200");
             offset = checkContains(response, offset, "/R2");
@@ -203,28 +204,18 @@ public class HttpConnectionTest
         assertThat(response, not(containsString("id=456")));
     }
 
-    /**
-     * Ensure that excessively large hexadecimal chunk body length is parsed properly.
-     */
-    @Test
-    public void testHttp11ChunkedBodyTruncation() throws Exception
+    @ParameterizedTest
+    @ValueSource(strings = {"8000000000000000", "FFFFFFFFFFFFFFFF", "1FFFFFFFFFFFFFFFF"})
+    public void testHttp11ChunkedSizeTooLarge(String chunkSize) throws Exception
     {
         String request = "POST /?id=123 HTTP/1.1\r\n" +
-            "Host: local\r\n" +
-            "Transfer-Encoding: chunked\r\n" +
-            "Content-Type: text/plain\r\n" +
-            "Connection: close\r\n" +
-            "\r\n" +
-            "1ff00000008\r\n" +
-            "abcdefgh\r\n" +
-            "\r\n" +
-            "0\r\n" +
-            "\r\n" +
-            "POST /?id=bogus HTTP/1.1\r\n" +
-            "Content-Length: 5\r\n" +
-            "Host: dummy-host.example.com\r\n" +
-            "\r\n" +
-            "12345";
+                         "Host: local\r\n" +
+                         "Transfer-Encoding: chunked\r\n" +
+                         "Content-Type: text/plain\r\n" +
+                         "Connection: close\r\n" +
+                         "\r\n" +
+                         chunkSize + "\r\n" +
+                         "abcdefgh\r\n";
 
         String response = connector.getResponse(request);
         assertThat(response, containsString(" 200 OK"));
@@ -232,6 +223,28 @@ public class HttpConnectionTest
         assertThat(response, containsString("Early EOF"));
     }
 
+    @Test
+    public void testHttp11ChunkedSizeCanBeALong() throws Exception
+    {
+        connector.setIdleTimeout(500);
+        String request = "POST /?id=123 HTTP/1.1\r\n" +
+                         "Host: local\r\n" +
+                         "Transfer-Encoding: chunked\r\n" +
+                         "Content-Type: text/plain\r\n" +
+                         "Connection: close\r\n" +
+                         "\r\n" +
+                         "1FFFFFFFF\r\n" +
+                         "abcdefgh\r\n";
+
+        try (StacklessLogging ignored = new StacklessLogging(Response.class))
+        {
+            String response = connector.getResponse(request);
+            // assertThat(response, containsString(" 500 Server Error"));
+            assertThat(response, containsString("Connection: close"));
+            assertThat(response, containsString("TimeoutException"));
+        }
+    }
+
     /**
      * More then 1 Content-Length is a bad requests per HTTP rfcs.
      */
@@ -335,9 +348,9 @@ public class HttpConnectionTest
         }
         request.append("Content-Type: text/plain\r\n");
         request.append("\r\n");
-        request.append("8;\r\n"); // chunk header
+        request.append("8\r\n"); // chunk header
         request.append("abcdefgh"); // actual content of 8 bytes
-        request.append("\r\n0;\r\n\r\n"); // last chunk
+        request.append("\r\n0\r\n\r\n"); // last chunk
 
         String rawResponse = connector.getResponse(request.toString());
         HttpTester.Response response = HttpTester.parseResponse(rawResponse);
@@ -379,9 +392,9 @@ public class HttpConnectionTest
         tokens.forEach((token) -> request.append("Transfer-Encoding: ").append(token).append("\r\n"));
         request.append("Content-Type: text/plain\r\n");
         request.append("\r\n");
-        request.append("8;\r\n"); // chunk header
+        request.append("8\r\n"); // chunk header
         request.append("abcdefgh"); // actual content of 8 bytes
-        request.append("\r\n0;\r\n\r\n"); // last chunk
+        request.append("\r\n0\r\n\r\n"); // last chunk
 
         System.out.println(request.toString());
 
@@ -433,9 +446,9 @@ public class HttpConnectionTest
         tokens.forEach((token) -> request.append("Transfer-Encoding: ").append(token).append("\r\n"));
         request.append("Content-Type: text/plain\r\n");
         request.append("\r\n");
-        request.append("8;\r\n"); // chunk header
+        request.append("8\r\n"); // chunk header
         request.append("abcdefgh"); // actual content of 8 bytes
-        request.append("\r\n0;\r\n\r\n"); // last chunk
+        request.append("\r\n0\r\n\r\n"); // last chunk
 
         System.out.println(request.toString());
 
@@ -853,9 +866,9 @@ public class HttpConnectionTest
             "Content-Type: text/plain\r\n" +
             "Connection: close\r\n" +
             "\r\n" +
-            "5;\r\n" +
+            "5\r\n" +
             "12345\r\n" +
-            "0;\r\n" +
+            "0\r\n" +
             "\r\n");
         offset = checkContains(response, offset, "HTTP/1.1 200");
         checkNotContained(response, offset, "IgnoreMe");
@@ -902,9 +915,9 @@ public class HttpConnectionTest
                 "Content-Type: text/plain; charset=utf-8\r\n" +
                 "Connection: close\r\n" +
                 "\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "12345\r\n" +
-                "0;\r\n" +
+                "0\r\n" +
                 "\r\n");
             offset = checkContains(response, offset, "HTTP/1.1 200");
             offset = checkContains(response, offset, "/R1");
@@ -918,9 +931,9 @@ public class HttpConnectionTest
                 "Content-Type: text/plain; charset =  iso-8859-1 ; other=value\r\n" +
                 "Connection: close\r\n" +
                 "\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "12345\r\n" +
-                "0;\r\n" +
+                "0\r\n" +
                 "\r\n");
             offset = checkContains(response, offset, "HTTP/1.1 200");
             offset = checkContains(response, offset, "encoding=iso-8859-1");
@@ -935,9 +948,9 @@ public class HttpConnectionTest
                 "Content-Type: text/plain; charset=unknown\r\n" +
                 "Connection: close\r\n" +
                 "\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "12345\r\n" +
-                "0;\r\n" +
+                "0\r\n" +
                 "\r\n");
 
             offset = checkContains(response, offset, "HTTP/1.1 200");
@@ -963,11 +976,11 @@ public class HttpConnectionTest
                 "Transfer-Encoding: chunked\r\n" +
                 "Content-Type: text/plain; charset=utf-8\r\n" +
                 "\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "12345\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "67890\r\n" +
-                "0;\r\n" +
+                "0\r\n" +
                 "\r\n" +
                 "GET /R2 HTTP/1.1\r\n" +
                 "Host: localhost\r\n" +
@@ -1001,7 +1014,7 @@ public class HttpConnectionTest
                 "Transfer-Encoding: chunked\r\n" +
                 "Content-Type: text/plain; charset=utf-8\r\n" +
                 "\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "12345\r\n";
 
         long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
@@ -1024,11 +1037,11 @@ public class HttpConnectionTest
                 "Transfer-Encoding: chunked\r\n" +
                 "Content-Type: text/plain; charset=utf-8\r\n" +
                 "\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "12345\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "67890\r\n" +
-                "0;\r\n" +
+                "0\r\n" +
                 "\r\n" +
                 "GET /R2 HTTP/1.1\r\n" +
                 "Host: localhost\r\n" +
@@ -1058,11 +1071,11 @@ public class HttpConnectionTest
                 "Transfer-Encoding: chunked\r\n" +
                 "Content-Type: application/data; charset=utf-8\r\n" +
                 "\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "12345\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "67890\r\n" +
-                "0;\r\n" +
+                "0\r\n" +
                 "\r\n" +
                 "GET /R2 HTTP/1.1\r\n" +
                 "Host: localhost\r\n" +
@@ -1091,11 +1104,11 @@ public class HttpConnectionTest
             "Transfer-Encoding: chunked\r\n" +
             "Content-Type: text/plain; charset=utf-8\r\n" +
             "\r\n" +
-            "5;\r\n" +
+            "5\r\n" +
             "12345\r\n" +
-            "5;\r\n" +
+            "5\r\n" +
             "67890\r\n" +
-            "0;\r\n" +
+            "0\r\n" +
             "\r\n" +
             "GET /R2 HTTP/1.1\r\n" +
             "Host: localhost\r\n" +
@@ -1128,9 +1141,9 @@ public class HttpConnectionTest
                 "Transfer-Encoding: chunked\r\n" +
                 "Content-Type: text/plain; charset=utf-8\r\n" +
                 "\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "12345\r\n" +
-                "0;\r\n" +
+                "0\r\n" +
                 "\r\n");
             checkContains(response, offset, "Connection: close");
         }
@@ -1306,9 +1319,9 @@ public class HttpConnectionTest
                 "Content-Type: text/plain; charset=utf-8\r\n" +
                 "Connection: close\r\n" +
                 "\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "12345\r\n" +
-                "0;\r\n" +
+                "0\r\n" +
                 "\r\n");
             checkContains(response, offset, "HTTP/1.1 200");
 
@@ -1319,9 +1332,9 @@ public class HttpConnectionTest
                 "Content-Type: text/plain; charset=utf-8\r\n" +
                 "Connection: close\r\n" +
                 "\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "12345\r\n" +
-                "0;\r\n" +
+                "0\r\n" +
                 "\r\n");
             checkContains(response, offset, "HTTP/1.1 400");
 
@@ -1332,9 +1345,9 @@ public class HttpConnectionTest
                 "Content-Type: text/plain; charset=utf-8\r\n" +
                 "Connection: close\r\n" +
                 "\r\n" +
-                "5;\r\n" +
+                "5\r\n" +
                 "12345\r\n" +
-                "0;\r\n" +
+                "0\r\n" +
                 "\r\n");
             checkContains(response, offset, "HTTP/1.1 400 Bad Request");
         }
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
index d0e21769754..bffe5967bd0 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpServerTestBase.java
@@ -487,7 +487,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
             os.flush();
             Thread.sleep(1000);
             os.write(("ABCDE\r\n" +
-                "0;\r\n\r\n").getBytes());
+                "0\r\n\r\n").getBytes());
             os.flush();
 
             // Read the response.
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java
@@ -145,9 +145,9 @@ public class PartialRFC2616Test
                 "Content-Type: text/plain\n" +
                 //@checkstyle-disable-check : IllegalTokenText
                 "\015\012" +
-                "5;\015\012" +
+                "5\015\012" +
                 "123\015\012\015\012" +
-                "0;\015\012\015\012");
+                "0\015\012\015\012");
         //@checkstyle-enable-check : IllegalTokenText
         checkContains(response, offset, "HTTP/1.1 400 Bad", "Chunked last");
     }
@@ -164,22 +164,22 @@ public class PartialRFC2616Test
                 "Transfer-Encoding: chunked\n" +
                 "Content-Type: text/plain\n" +
                 "\n" +
-                "2;\n" +
+                "2\n" +
                 "12\n" +
-                "3;\n" +
+                "3\n" +
                 "345\n" +
-                "0;\n\n" +
+                "0\n\n" +
 
                 "GET /R2 HTTP/1.1\n" +
                 "Host: localhost\n" +
                 "Transfer-Encoding: chunked\n" +
                 "Content-Type: text/plain\n" +
                 "\n" +
-                "4;\n" +
+                "4\n" +
                 "6789\n" +
-                "5;\n" +
+                "5\n" +
                 "abcde\n" +
-                "0;\n\n" +
+                "0\n\n" +
 
                 "GET /R3 HTTP/1.1\n" +
                 "Host: localhost\n" +
@@ -209,22 +209,22 @@ public class PartialRFC2616Test
                 "Transfer-Encoding: chunked\n" +
                 "Content-Type: text/plain\n" +
                 "\n" +
-                "3;\n" +
+                "3\n" +
                 "fgh\n" +
-                "3;\n" +
+                "3\n" +
                 "Ijk\n" +
-                "0;\n\n" +
+                "0\n\n" +
 
                 "POST /R2 HTTP/1.1\n" +
                 "Host: localhost\n" +
                 "Transfer-Encoding: chunked\n" +
                 "Content-Type: text/plain\n" +
                 "\n" +
-                "4;\n" +
+                "4\n" +
                 "lmno\n" +
-                "5;\n" +
+                "5\n" +
                 "Pqrst\n" +
-                "0;\n\n" +
+                "0\n\n" +
 
                 "GET /R3 HTTP/1.1\n" +
                 "Host: localhost\n" +
@@ -259,11 +259,11 @@ public class PartialRFC2616Test
                 "Content-Type: text/plain\n" +
                 "Connection: keep-alive\n" +
                 "\n" +
-                "3;\n" +
+                "3\n" +
                 "123\n" +
-                "3;\n" +
+                "3\n" +
                 "456\n" +
-                "0;\n\n" +
+                "0\n\n" +
 
                 "GET /R2 HTTP/1.1\n" +
                 "Host: localhost\n" +
@@ -367,11 +367,11 @@ public class PartialRFC2616Test
                 "Content-Type: text/plain\n" +
                 "Content-Length: 100\n" +
                 "\n" +
-                "3;\n" +
+                "3\n" +
                 "123\n" +
-                "3;\n" +
+                "3\n" +
                 "456\n" +
-                "0;\n" +
+                "0\n" +
                 "\n" +
 
                 "GET /R2 HTTP/1.1\n" +
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/SizeLimitHandlerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/SizeLimitHandlerTest.java
@@ -252,7 +252,7 @@ public class SizeLimitHandlerTest
             String text = new String(data, 0, 1024, Charset.defaultCharset());
 
             for (int i = 0; i < 9; i++)
-                endp.addInput(Integer.toHexString(text.length()) + ";\r\n" + text + "\r\n");
+                endp.addInput(Integer.toHexString(text.length()) + "\r\n" + text + "\r\n");
 
             HttpTester.Response response = HttpTester.parseResponse(endp.getResponse());
 
--- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java
+++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java
@@ -172,9 +172,9 @@ public abstract class RFC2616BaseTest
         req1.append("Content-Type: text/plain\n");
         req1.append("Connection: close\n");
         req1.append("\r\n");
-        req1.append("5;\r\n");
+        req1.append("5\r\n");
         req1.append("123\r\n\r\n");
-        req1.append("0;\r\n\r\n");
+        req1.append("0\r\n\r\n");
 
         HttpTester.Response response = http.request(req1);
 
@@ -196,22 +196,22 @@ public abstract class RFC2616BaseTest
         req2.append("Transfer-Encoding: chunked\n");
         req2.append("Content-Type: text/plain\n");
         req2.append("\n");
-        req2.append("2;\n"); // 2 chars
+        req2.append("2\n"); // 2 chars
         req2.append("12\n");
-        req2.append("3;\n"); // 3 chars
+        req2.append("3\n"); // 3 chars
         req2.append("345\n");
-        req2.append("0;\n\n");
+        req2.append("0\n\n");
 
         req2.append("GET /echo/R2 HTTP/1.1\n");
         req2.append("Host: localhost\n");
         req2.append("Transfer-Encoding: chunked\n");
         req2.append("Content-Type: text/plain\n");
         req2.append("\n");
-        req2.append("4;\n"); // 4 chars
+        req2.append("4\n"); // 4 chars
         req2.append("6789\n");
-        req2.append("5;\n"); // 5 chars
+        req2.append("5\n"); // 5 chars
         req2.append("abcde\n");
-        req2.append("0;\n\n"); // 0 chars
+        req2.append("0\n\n"); // 0 chars
 
         req2.append("GET /echo/R3 HTTP/1.1\n");
         req2.append("Host: localhost\n");
@@ -249,22 +249,22 @@ public abstract class RFC2616BaseTest
         req3.append("Transfer-Encoding: chunked\n");
         req3.append("Content-Type: text/plain\n");
         req3.append("\n");
-        req3.append("3;\n"); // 3 chars
+        req3.append("3\n"); // 3 chars
         req3.append("fgh\n");
-        req3.append("3;\n"); // 3 chars
+        req3.append("3\n"); // 3 chars
         req3.append("Ijk\n");
-        req3.append("0;\n\n"); // 0 chars
+        req3.append("0\n\n"); // 0 chars
 
         req3.append("POST /echo/R2 HTTP/1.1\n");
         req3.append("Host: localhost\n");
         req3.append("Transfer-Encoding: chunked\n");
         req3.append("Content-Type: text/plain\n");
         req3.append("\n");
-        req3.append("4;\n"); // 4 chars
+        req3.append("4\n"); // 4 chars
         req3.append("lmno\n");
-        req3.append("5;\n"); // 5 chars
+        req3.append("5\n"); // 5 chars
         req3.append("Pqrst\n");
-        req3.append("0;\n\n"); // 0 chars
+        req3.append("0\n\n"); // 0 chars
 
         req3.append("GET /echo/R3 HTTP/1.1\n");
         req3.append("Host: localhost\n");
@@ -303,11 +303,11 @@ public abstract class RFC2616BaseTest
         req4.append("Content-Type: text/plain\n");
         req4.append("Connection: keep-alive\n"); // keep-alive
         req4.append("\n");
-        req4.append("3;\n"); // 3 chars
+        req4.append("3\n"); // 3 chars
         req4.append("123\n");
-        req4.append("3;\n"); // 3 chars
+        req4.append("3\n"); // 3 chars
         req4.append("456\n");
-        req4.append("0;\n\n"); // 0 chars
+        req4.append("0\n\n"); // 0 chars
 
         req4.append("GET /echo/R2 HTTP/1.1\n");
         req4.append("Host: localhost\n");
@@ -386,11 +386,11 @@ public abstract class RFC2616BaseTest
         req2.append("Content-Type: text/plain\n");
         req2.append("Content-Length: 100\n");
         req2.append("\n");
-        req2.append("3;\n");
+        req2.append("3\n");
         req2.append("123\n");
-        req2.append("3;\n");
+        req2.append("3\n");
         req2.append("456\n");
-        req2.append("0;\n");
+        req2.append("0\n");
         req2.append("\n");
 
         req2.append("GET /echo/R2 HTTP/1.1\n");
