[Git][java-team/jetty9][buster] Import Debian changes 9.4.16-0+deb10u3

Markus Koschany (@apo) gitlab at salsa.debian.org
Sat Sep 30 13:21:34 BST 2023



Markus Koschany pushed to branch buster at Debian Java Maintainers / jetty9


Commits:
6d98df40 by Markus Koschany at 2023-09-30T14:19:27+02:00
Import Debian changes 9.4.16-0+deb10u3

jetty9 (9.4.16-0+deb10u3) buster-security; urgency=high
.
  * Team upload.
  * The org.eclipse.jetty.servlets.CGI has been deprecated. It is potentially
    unsafe to use it. The upstream developers of Jetty recommend to use Fast CGI
    instead. See also CVE-2023-36479.
  * Fix CVE-2023-26048:
    Jetty is a java based web server and servlet engine. In affected versions
    servlets with multipart support (e.g. annotated with `@MultipartConfig`)
    that call `HttpServletRequest.getParameter()` or
    `HttpServletRequest.getParts()` may cause `OutOfMemoryError` when the
    client sends a multipart request with a part that has a name but no
    filename and very large content. This happens even with the default
    settings of `fileSizeThreshold=0` which should stream the whole part
    content to disk.
  * Fix CVE-2023-26049:
    Nonstandard cookie parsing in Jetty may allow an attacker to smuggle
    cookies within other cookies, or otherwise perform unintended behavior by
    tampering with the cookie parsing mechanism.
  * Fix CVE-2023-40167:
    Prior to this version Jetty accepted the `+` character proceeding the
    content-length value in a HTTP/1 header field. This is more permissive than
    allowed by the RFC and other servers routinely reject such requests with
    400 responses. There is no known exploit scenario, but it is conceivable
    that request smuggling could result if jetty is used in combination with a
    server that does not close the connection after sending such a 400
    response.
  * CVE-2023-36479:
    Users of the CgiServlet with a very specific command structure may have the
    wrong command executed. If a user sends a request to a
    org.eclipse.jetty.servlets.CGI Servlet for a binary with a space in its
    name, the servlet will escape the command by wrapping it in quotation
    marks. This wrapped command, plus an optional command prefix, will then be
    executed through a call to Runtime.exec. If the original binary name
    provided by the user contains a quotation mark followed by a space, the
    resulting command line will contain multiple tokens instead of one.

- - - - -


8 changed files:

- debian/changelog
- debian/patches/CVE-2022-2047.patch
- debian/patches/CVE-2022-2048.patch
- + debian/patches/CVE-2023-26048.patch
- + debian/patches/CVE-2023-26049.patch
- + debian/patches/CVE-2023-36479.patch
- + debian/patches/CVE-2023-40167.patch
- debian/patches/series


Changes:

=====================================
debian/changelog
=====================================
@@ -1,3 +1,42 @@
+jetty9 (9.4.16-0+deb10u3) buster-security; urgency=high
+
+  * Team upload.
+  * The org.eclipse.jetty.servlets.CGI has been deprecated. It is potentially
+    unsafe to use it. The upstream developers of Jetty recommend to use Fast CGI
+    instead. See also CVE-2023-36479.
+  * Fix CVE-2023-26048:
+    Jetty is a java based web server and servlet engine. In affected versions
+    servlets with multipart support (e.g. annotated with `@MultipartConfig`)
+    that call `HttpServletRequest.getParameter()` or
+    `HttpServletRequest.getParts()` may cause `OutOfMemoryError` when the
+    client sends a multipart request with a part that has a name but no
+    filename and very large content. This happens even with the default
+    settings of `fileSizeThreshold=0` which should stream the whole part
+    content to disk.
+  * Fix CVE-2023-26049:
+    Nonstandard cookie parsing in Jetty may allow an attacker to smuggle
+    cookies within other cookies, or otherwise perform unintended behavior by
+    tampering with the cookie parsing mechanism.
+  * Fix CVE-2023-40167:
+    Prior to this version Jetty accepted the `+` character proceeding the
+    content-length value in a HTTP/1 header field. This is more permissive than
+    allowed by the RFC and other servers routinely reject such requests with
+    400 responses. There is no known exploit scenario, but it is conceivable
+    that request smuggling could result if jetty is used in combination with a
+    server that does not close the connection after sending such a 400
+    response.
+  * CVE-2023-36479:
+    Users of the CgiServlet with a very specific command structure may have the
+    wrong command executed. If a user sends a request to a
+    org.eclipse.jetty.servlets.CGI Servlet for a binary with a space in its
+    name, the servlet will escape the command by wrapping it in quotation
+    marks. This wrapped command, plus an optional command prefix, will then be
+    executed through a call to Runtime.exec. If the original binary name
+    provided by the user contains a quotation mark followed by a space, the
+    resulting command line will contain multiple tokens instead of one.
+
+ -- Markus Koschany <apo at debian.org>  Wed, 27 Sep 2023 14:32:13 +0200
+
 jetty9 (9.4.16-0+deb10u2) buster-security; urgency=high
 
   * Team upload.


=====================================
debian/patches/CVE-2022-2047.patch
=====================================
@@ -5,13 +5,12 @@ Subject: CVE-2022-2047
 Origin: https://github.com/eclipse/jetty.project/pull/8146
 ---
  .../java/org/eclipse/jetty/client/HttpRequest.java |  8 +-
- .../eclipse/jetty/client/HttpClientURITest.java    | 45 ++++++++++
  .../main/java/org/eclipse/jetty/http/HttpURI.java  | 25 +++++-
  .../java/org/eclipse/jetty/http/HttpURITest.java   | 95 ++++++++++++++++++++++
  .../org/eclipse/jetty/proxy/ConnectHandler.java    |  2 +-
  .../java/org/eclipse/jetty/server/Request.java     | 14 +++-
  .../eclipse/jetty/server/HttpConnectionTest.java   | 12 +--
- 7 files changed, 187 insertions(+), 14 deletions(-)
+ 6 files changed, 142 insertions(+), 14 deletions(-)
 
 diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java
 index f6a453f..2d2afa0 100644


=====================================
debian/patches/CVE-2022-2048.patch
=====================================
@@ -4,10 +4,8 @@ Subject: CVE-2022-2048
 
 Origin: https://github.com/eclipse/jetty.project/issues/7935
 ---
- .../jetty/http2/server/HttpChannelOverHTTP2.java   |  12 +-
- .../org/eclipse/jetty/http2/server/BadURITest.java | 153 +++++++++++++++++++++
- 2 files changed, 157 insertions(+), 8 deletions(-)
- create mode 100644 jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/BadURITest.java
+ .../org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
 
 diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java
 index 03b082e..3548497 100644


=====================================
debian/patches/CVE-2023-26048.patch
=====================================
@@ -0,0 +1,537 @@
+From: Markus Koschany <apo at debian.org>
+Date: Tue, 26 Sep 2023 20:37:47 +0200
+Subject: CVE-2023-26048
+
+Origin: https://github.com/eclipse/jetty.project/pull/9345
+---
+ .../jetty/http/MultiPartFormInputStream.java       |  76 +++++++-----
+ .../java/org/eclipse/jetty/server/MultiParts.java  |  14 ++-
+ .../java/org/eclipse/jetty/server/Request.java     | 127 ++++++++++++---------
+ .../jetty/server/handler/ContextHandler.java       |   4 +
+ .../jetty/util/MultiPartInputStreamParser.java     |  24 +++-
+ 5 files changed, 158 insertions(+), 87 deletions(-)
+
+diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java
+index 928f59c..a1092f7 100644
+--- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java
++++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java
+@@ -60,11 +60,14 @@ import org.eclipse.jetty.util.log.Logger;
+ public class MultiPartFormInputStream
+ {
+     private static final Logger LOG = Log.getLogger(MultiPartFormInputStream.class);
++    private static final int DEFAULT_MAX_FORM_KEYS = 1000;
+     private static final MultiMap<Part> EMPTY_MAP = new MultiMap<>(Collections.emptyMap());
++    private final MultiMap<Part> _parts;
++    private final int _maxParts;
++    private int _numParts = 0;
+     private InputStream _in;
+     private MultipartConfigElement _config;
+     private String _contentType;
+-    private MultiMap<Part> _parts;
+     private Throwable _err;
+     private File _tmpDir;
+     private File _contextTmpDir;
+@@ -332,26 +335,42 @@ public class MultiPartFormInputStream
+      * @param contextTmpDir javax.servlet.context.tempdir
+      */
+     public MultiPartFormInputStream(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir)
++    {
++        this(in, contentType, config, contextTmpDir, DEFAULT_MAX_FORM_KEYS);
++    }
++
++    /**
++     * @param in Request input stream
++     * @param contentType Content-Type header
++     * @param config MultipartConfigElement
++     * @param contextTmpDir javax.servlet.context.tempdir
++     * @param maxParts the maximum number of parts that can be parsed from the multipart content (0 for no parts allowed, -1 for unlimited parts).
++     */
++    public MultiPartFormInputStream(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir, int maxParts)
++
+     {
+         _contentType = contentType;
+         _config = config;
+         _contextTmpDir = contextTmpDir;
++        _maxParts = maxParts;
+         if (_contextTmpDir == null)
+             _contextTmpDir = new File(System.getProperty("java.io.tmpdir"));
+         
+         if (_config == null)
+             _config = new MultipartConfigElement(_contextTmpDir.getAbsolutePath());
+         
++        MultiMap<Part> parts = new MultiMap<>();
+         if (in instanceof ServletInputStream)
+         {
+             if (((ServletInputStream)in).isFinished())
+             {
+-                _parts = EMPTY_MAP;
++                parts = EMPTY_MAP;
+                 _parsed = true;
+-                return;
+             }
+         }
+-        _in = new BufferedInputStream(in);
++        if (!_parsed)
++            _in = new BufferedInputStream(in);
++        _parts = parts;
+     }
+     
+     /**
+@@ -495,16 +514,15 @@ public class MultiPartFormInputStream
+         if (_parsed)
+             return;
+         _parsed = true;
+-        
++
++        MultiPartParser parser = null;
++        Handler handler = new Handler();
+         try
+         {
+-            // initialize
+-            _parts = new MultiMap<>();
+-            
+             // if its not a multipart request, don't parse it
+             if (_contentType == null || !_contentType.startsWith("multipart/form-data"))
+                 return;
+-            
++
+             // sort out the location to which to write the files
+             if (_config.getLocation() == null)
+                 _tmpDir = _contextTmpDir;
+@@ -518,10 +536,10 @@ public class MultiPartFormInputStream
+                 else
+                     _tmpDir = new File(_contextTmpDir, _config.getLocation());
+             }
+-            
++
+             if (!_tmpDir.exists())
+                 _tmpDir.mkdirs();
+-            
++
+             String contentTypeBoundary = "";
+             int bstart = _contentType.indexOf("boundary=");
+             if (bstart >= 0)
+@@ -530,22 +548,19 @@ public class MultiPartFormInputStream
+                 bend = (bend < 0 ? _contentType.length() : bend);
+                 contentTypeBoundary = QuotedStringTokenizer.unquote(value(_contentType.substring(bstart, bend)).trim());
+             }
+-            
+-            Handler handler = new Handler();
+-            MultiPartParser parser = new MultiPartParser(handler, contentTypeBoundary);
+-            
++
++            parser = new MultiPartParser(handler, contentTypeBoundary);
+             byte[] data = new byte[_bufferSize];
+             int len;
+             long total = 0;
+-            
++
+             while (true)
+             {
+-                
++
+                 len = _in.read(data);
+-                
++
+                 if (len > 0)
+                 {
+-                    
+                     // keep running total of size of bytes read from input and throw an exception if exceeds MultipartConfigElement._maxRequestSize
+                     total += len;
+                     if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize())
+@@ -553,30 +568,28 @@ public class MultiPartFormInputStream
+                         _err = new IllegalStateException("Request exceeds maxRequestSize (" + _config.getMaxRequestSize() + ")");
+                         return;
+                     }
+-                    
++
+                     ByteBuffer buffer = BufferUtil.toBuffer(data);
+                     buffer.limit(len);
+                     if (parser.parse(buffer, false))
+                         break;
+-                    
++
+                     if (buffer.hasRemaining())
+                         throw new IllegalStateException("Buffer did not fully consume");
+-                    
+                 }
+                 else if (len == -1)
+                 {
+                     parser.parse(BufferUtil.EMPTY_BUFFER, true);
+                     break;
+                 }
+-                
+             }
+-            
++
+             // check for exceptions
+             if (_err != null)
+             {
+                 return;
+             }
+-            
++
+             // check we read to the end of the message
+             if (parser.getState() != MultiPartParser.State.END)
+             {
+@@ -585,19 +598,23 @@ public class MultiPartFormInputStream
+                 else
+                     _err = new IOException("Incomplete Multipart");
+             }
+-            
++
+             if (LOG.isDebugEnabled())
+             {
+                 LOG.debug("Parsing Complete {} err={}", parser, _err);
+             }
+-            
+         }
+         catch (Throwable e)
+         {
+             _err = e;
++
++            // Notify parser if failure occurs
++            if (parser != null)
++                parser.parse(BufferUtil.EMPTY_BUFFER, true);
+         }
+     }
+-    
++
++
+     class Handler implements MultiPartParser.Handler
+     {
+         private MultiPart _part = null;
+@@ -735,6 +752,9 @@ public class MultiPartFormInputStream
+         public void startPart()
+         {
+             reset();
++            _numParts++;
++            if (_maxParts >= 0 && _numParts > _maxParts)
++                throw new IllegalStateException(String.format("Form with too many parts [%d > %d]", _numParts, _maxParts));
+         }
+         
+         @Override
+diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiParts.java b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiParts.java
+index f28b945..1b91649 100644
+--- a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiParts.java
++++ b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiParts.java
+@@ -57,7 +57,12 @@ public interface MultiParts extends Closeable
+ 
+         public MultiPartsHttpParser(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir, Request request) throws IOException
+         {
+-            _httpParser = new MultiPartFormInputStream(in, contentType, config, contextTmpDir);
++            this(in, contentType, config, contextTmpDir, request, ContextHandler.DEFAULT_MAX_FORM_KEYS);
++        }
++
++        public MultiPartsHttpParser(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir, Request request, int maxParts) throws IOException
++        {
++            _httpParser = new MultiPartFormInputStream(in, contentType, config, contextTmpDir, maxParts);
+             _context = request.getContext();
+             _httpParser.getParts();
+         }
+@@ -116,7 +121,12 @@ public interface MultiParts extends Closeable
+ 
+         public MultiPartsUtilParser(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir, Request request) throws IOException
+         {
+-            _utilParser = new MultiPartInputStreamParser(in, contentType, config, contextTmpDir);
++            this(in, contentType, config, contextTmpDir, request, ContextHandler.DEFAULT_MAX_FORM_KEYS);
++        }
++
++        public MultiPartsUtilParser(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir, Request request, int maxParts) throws IOException
++        {
++            _utilParser = new MultiPartInputStreamParser(in, contentType, config, contextTmpDir, maxParts);
+             _context = request.getContext();
+             _utilParser.getParts();
+ 
+diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
+index 5b996bb..8a7e6f9 100644
+--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
++++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
+@@ -425,6 +425,14 @@ public class Request implements HttpServletRequest
+         return parameters==null?NO_PARAMS:parameters;
+     }
+ 
++    private boolean isContentEncodingSupported()
++    {
++        String contentEncoding = getHttpFields().get(HttpHeader.CONTENT_ENCODING);
++        if (contentEncoding == null)
++            return true;
++        return HttpHeaderValue.IDENTITY.is(contentEncoding);
++    }
++
+     /* ------------------------------------------------------------ */
+     private void extractQueryParameters()
+     {
+@@ -458,33 +466,34 @@ public class Request implements HttpServletRequest
+     {
+         String contentType = getContentType();
+         if (contentType == null || contentType.isEmpty())
+-            _contentParameters=NO_PARAMS;
++            _contentParameters = NO_PARAMS;
+         else
+         {
+-            _contentParameters=new MultiMap<>();
++            _contentParameters = new MultiMap<>();
+             int contentLength = getContentLength();
+             if (contentLength != 0 && _inputState == __NONE)
+             {
+-                contentType = HttpFields.valueParameters(contentType, null);
+-                if (MimeTypes.Type.FORM_ENCODED.is(contentType) &&
++                String baseType = HttpFields.valueParameters(contentType, null);
++                if (MimeTypes.Type.FORM_ENCODED.is(baseType) &&
+                     _channel.getHttpConfiguration().isFormEncodedMethod(getMethod()))
+                 {
+-                    if (_metaData!=null)
++                    if (_metaData != null && !isContentEncodingSupported())
+                     {
+-                        String contentEncoding = getHttpFields().get(HttpHeader.CONTENT_ENCODING);
+-                        if (contentEncoding!=null && !HttpHeaderValue.IDENTITY.is(contentEncoding))
+-                            throw new BadMessageException(HttpStatus.NOT_IMPLEMENTED_501, "Unsupported Content-Encoding");
++                        throw new BadMessageException(HttpStatus.UNSUPPORTED_MEDIA_TYPE_415, "Unsupported Content-Encoding");
+                     }
++
+                     extractFormParameters(_contentParameters);
+                 }
+-                else if (MimeTypes.Type.MULTIPART_FORM_DATA.is(contentType) &&
+-                        getAttribute(__MULTIPART_CONFIG_ELEMENT) != null &&
+-                        _multiParts == null)
++                else if (MimeTypes.Type.MULTIPART_FORM_DATA.is(baseType) &&
++                    getAttribute(__MULTIPART_CONFIG_ELEMENT) != null &&
++                    _multiParts == null)
+                 {
+                     try
+                     {
+-                        if (_metaData!=null && getHttpFields().contains(HttpHeader.CONTENT_ENCODING))
+-                            throw new BadMessageException(HttpStatus.NOT_IMPLEMENTED_501,"Unsupported Content-Encoding");
++                        if (_metaData != null && !isContentEncodingSupported())
++                        {
++                            throw new BadMessageException(HttpStatus.UNSUPPORTED_MEDIA_TYPE_415, "Unsupported Content-Encoding");
++                        }
+                         getParts(_contentParameters);
+                     }
+                     catch (IOException | ServletException e)
+@@ -502,57 +511,30 @@ public class Request implements HttpServletRequest
+     {
+         try
+         {
+-            int maxFormContentSize = -1;
+-            int maxFormKeys = -1;
++            int maxFormContentSize = ContextHandler.DEFAULT_MAX_FORM_CONTENT_SIZE;
++            int maxFormKeys = ContextHandler.DEFAULT_MAX_FORM_KEYS;
+ 
+             if (_context != null)
+             {
+-                maxFormContentSize = _context.getContextHandler().getMaxFormContentSize();
+-                maxFormKeys = _context.getContextHandler().getMaxFormKeys();
++                ContextHandler contextHandler = _context.getContextHandler();
++                maxFormContentSize = contextHandler.getMaxFormContentSize();
++                maxFormKeys = contextHandler.getMaxFormKeys();
+             }
+-
+-            if (maxFormContentSize < 0)
++            else
+             {
+-                Object obj = _channel.getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormContentSize");
+-                if (obj == null)
+-                    maxFormContentSize = 200000;
+-                else if (obj instanceof Number)
+-                {
+-                    Number size = (Number)obj;
+-                    maxFormContentSize = size.intValue();
+-                }
+-                else if (obj instanceof String)
+-                {
+-                    maxFormContentSize = Integer.parseInt((String)obj);
+-                }
+-            }
+-
+-            if (maxFormKeys < 0)
+-            {
+-                Object obj = _channel.getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormKeys");
+-                if (obj == null)
+-                    maxFormKeys = 1000;
+-                else if (obj instanceof Number)
+-                {
+-                    Number keys = (Number)obj;
+-                    maxFormKeys = keys.intValue();
+-                }
+-                else if (obj instanceof String)
+-                {
+-                    maxFormKeys = Integer.parseInt((String)obj);
+-                }
++                maxFormContentSize = lookupServerAttribute(ContextHandler.MAX_FORM_CONTENT_SIZE_KEY, maxFormContentSize);
++                maxFormKeys = lookupServerAttribute(ContextHandler.MAX_FORM_KEYS_KEY, maxFormKeys);
+             }
+ 
+             int contentLength = getContentLength();
+-            if (contentLength > maxFormContentSize && maxFormContentSize > 0)
+-            {
+-                throw new IllegalStateException("Form too large: " + contentLength + " > " + maxFormContentSize);
+-            }
++            if (maxFormContentSize >= 0 && contentLength > maxFormContentSize)
++                throw new IllegalStateException("Form is larger than max length " + maxFormContentSize);
++
+             InputStream in = getInputStream();
+             if (_input.isAsync())
+                 throw new IllegalStateException("Cannot extract parameters with async IO");
+ 
+-            UrlEncoded.decodeTo(in,params,getCharacterEncoding(),contentLength<0?maxFormContentSize:-1,maxFormKeys);
++            UrlEncoded.decodeTo(in, params, getCharacterEncoding(), maxFormContentSize, maxFormKeys);
+         }
+         catch (IOException e)
+         {
+@@ -561,6 +543,16 @@ public class Request implements HttpServletRequest
+         }
+     }
+ 
++    private int lookupServerAttribute(String key, int dftValue)
++    {
++        Object attribute = _channel.getServer().getAttribute(key);
++        if (attribute instanceof Number)
++            return ((Number)attribute).intValue();
++        else if (attribute instanceof String)
++            return Integer.parseInt((String)attribute);
++        return dftValue;
++    }
++
+     /* ------------------------------------------------------------ */
+     @Override
+     public AsyncContext getAsyncContext()
+@@ -2351,9 +2343,23 @@ public class Request implements HttpServletRequest
+             if (config == null)
+                 throw new IllegalStateException("No multipart config for servlet");
+ 
++            int maxFormContentSize = ContextHandler.DEFAULT_MAX_FORM_CONTENT_SIZE;
++            int maxFormKeys = ContextHandler.DEFAULT_MAX_FORM_KEYS;
++            if (_context != null)
++            {
++                ContextHandler contextHandler = _context.getContextHandler();
++                maxFormContentSize = contextHandler.getMaxFormContentSize();
++                maxFormKeys = contextHandler.getMaxFormKeys();
++            }
++            else
++            {
++                maxFormContentSize = lookupServerAttribute(ContextHandler.MAX_FORM_CONTENT_SIZE_KEY, maxFormContentSize);
++                maxFormKeys = lookupServerAttribute(ContextHandler.MAX_FORM_KEYS_KEY, maxFormKeys);
++            }
++
+             _multiParts = newMultiParts(getInputStream(),
+                                        getContentType(), config,
+-                                       (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null));
++                                       (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null),maxFormKeys);
+ 
+             setAttribute(__MULTIPARTS, _multiParts);
+             Collection<Part> parts = _multiParts.getParts(); //causes parsing
+@@ -2388,11 +2394,16 @@ public class Request implements HttpServletRequest
+             else
+                 defaultCharset = StandardCharsets.UTF_8;
+             
++            long formContentSize = 0;
+             ByteArrayOutputStream os = null;
+             for (Part p:parts)
+             {
+                 if (p.getSubmittedFileName() == null)
+                 {
++                    formContentSize = Math.addExact(formContentSize, p.getSize());
++                    if (maxFormContentSize >= 0 && formContentSize > maxFormContentSize)
++                        throw new IllegalStateException("Form is larger than max length " + maxFormContentSize);
++
+                     // Servlet Spec 3.0 pg 23, parts without filename must be put into params.
+                     String charset = null;
+                     if (p.getContentType() != null)
+@@ -2418,7 +2429,9 @@ public class Request implements HttpServletRequest
+     }
+ 
+     
+-    private MultiParts newMultiParts(ServletInputStream inputStream, String contentType, MultipartConfigElement config, Object object) throws IOException
++    private MultiParts newMultiParts(ServletInputStream inputStream, String
++            contentType, MultipartConfigElement config, Object object,
++            int maxParts) throws IOException
+     {
+         MultiPartFormDataCompliance compliance = getHttpChannel().getHttpConfiguration().getMultipartFormDataCompliance();
+         if(LOG.isDebugEnabled())
+@@ -2428,12 +2441,14 @@ public class Request implements HttpServletRequest
+         {
+             case RFC7578:
+                 return new MultiParts.MultiPartsHttpParser(getInputStream(), getContentType(), config,
+-                        (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null), this);
++                        (_context !=
++                         null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null), this, maxParts);
+                 
+             case LEGACY: 
+             default:
+                 return new MultiParts.MultiPartsUtilParser(getInputStream(), getContentType(), config,
+-                    (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null), this);
++                    (_context !=
++                     null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null), this, maxParts);
+                         
+         }
+     }
+diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
+index b6ca046..c4cbebd 100644
+--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
++++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
+@@ -132,6 +132,10 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
+      */
+     public static final String MANAGED_ATTRIBUTES = "org.eclipse.jetty.server.context.ManagedAttributes";
+ 
++    public static final String MAX_FORM_KEYS_KEY = "org.eclipse.jetty.server.Request.maxFormKeys";
++    public static final String MAX_FORM_CONTENT_SIZE_KEY = "org.eclipse.jetty.server.Request.maxFormContentSize";
++    public static final int DEFAULT_MAX_FORM_KEYS = 1000;
++    public static final int DEFAULT_MAX_FORM_CONTENT_SIZE = 200000;
+     /* ------------------------------------------------------------ */
+     /**
+      * Get the current ServletContext implementation.
+diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java
+index 17e7bb1..d45b8ff 100644
+--- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java
++++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java
+@@ -65,8 +65,11 @@ import org.eclipse.jetty.util.log.Logger;
+ public class MultiPartInputStreamParser
+ {
+     private static final Logger LOG = Log.getLogger(MultiPartInputStreamParser.class);
++    private static final int DEFAULT_MAX_FORM_KEYS = 1000;
+     public static final MultipartConfigElement  __DEFAULT_MULTIPART_CONFIG = new MultipartConfigElement(System.getProperty("java.io.tmpdir"));
+-    public static final MultiMap<Part> EMPTY_MAP = new MultiMap(Collections.emptyMap());
++    public static final MultiMap<Part> EMPTY_MAP = new MultiMap<>(Collections.emptyMap());
++    private final int _maxParts;
++    private int _numParts;
+     protected InputStream _in;
+     protected MultipartConfigElement _config;
+     protected String _contentType;
+@@ -411,9 +414,23 @@ public class MultiPartInputStreamParser
+      */
+     public MultiPartInputStreamParser (InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir)
+     {
++        this(in, contentType, config, contextTmpDir, DEFAULT_MAX_FORM_KEYS);
++    }
++
++    /**
++     * @param in Request input stream
++     * @param contentType Content-Type header
++     * @param config MultipartConfigElement
++     * @param contextTmpDir javax.servlet.context.tempdir
++     * @param maxParts the maximum number of parts that can be parsed from the multipart content (0 for no parts allowed, -1 for unlimited parts).
++     */
++    public MultiPartInputStreamParser(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir, int maxParts)
++
++     {
+         _contentType = contentType;
+         _config = config;
+         _contextTmpDir = contextTmpDir;
++        _maxParts = maxParts;
+         if (_contextTmpDir == null)
+             _contextTmpDir = new File (System.getProperty("java.io.tmpdir"));
+ 
+@@ -712,6 +729,11 @@ public class MultiPartInputStreamParser
+                     continue;
+                 }
+ 
++                // Check if we can create a new part.
++                _numParts++;
++                if (_maxParts >= 0 && _numParts > _maxParts)
++                    throw new IllegalStateException(String.format("Form with too many parts [%d > %d]", _numParts, _maxParts));
++
+                 //Have a new Part
+                 MultiPart part = new MultiPart(name, filename);
+                 part.setHeaders(headers);


=====================================
debian/patches/CVE-2023-26049.patch
=====================================
@@ -0,0 +1,831 @@
+From: Markus Koschany <apo at debian.org>
+Date: Tue, 26 Sep 2023 23:42:03 +0200
+Subject: CVE-2023-26049
+
+Origin: https://github.com/eclipse/jetty.project/pull/9352
+---
+ .../org/eclipse/jetty/http/CookieCompliance.java   |   2 +-
+ .../org/eclipse/jetty/server/CookieCutter.java     | 205 ++++++++++-----
+ .../org/eclipse/jetty/server/CookieCutterTest.java | 280 ++++++++++++++++-----
+ .../java/org/eclipse/jetty/server/RequestTest.java |   2 +
+ 4 files changed, 361 insertions(+), 128 deletions(-)
+
+diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/CookieCompliance.java b/jetty-http/src/main/java/org/eclipse/jetty/http/CookieCompliance.java
+index b2d339c..d514c15 100644
+--- a/jetty-http/src/main/java/org/eclipse/jetty/http/CookieCompliance.java
++++ b/jetty-http/src/main/java/org/eclipse/jetty/http/CookieCompliance.java
+@@ -22,4 +22,4 @@ package org.eclipse.jetty.http;
+  * The compliance for Cookie handling.
+  *
+  */
+-public enum CookieCompliance { RFC6265, RFC2965 }
++public enum CookieCompliance { RFC6265, RFC2965, RFC6265_LEGACY }
+diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/CookieCutter.java b/jetty-server/src/main/java/org/eclipse/jetty/server/CookieCutter.java
+index 5dce1cf..e28d262 100644
+--- a/jetty-server/src/main/java/org/eclipse/jetty/server/CookieCutter.java
++++ b/jetty-server/src/main/java/org/eclipse/jetty/server/CookieCutter.java
+@@ -107,23 +107,24 @@ public class CookieCutter
+         _lastCookies=null;
+         _fieldList.add(_fields++,f);
+     }
+-    
+-    
++
+     protected void parseFields()
+     {
+-        _lastCookies=null;
+-        _cookies=null;
+-        
++        _lastCookies = null;
++        _cookies = null;
++
+         List<Cookie> cookies = new ArrayList<>();
+ 
+         int version = 0;
+ 
+         // delete excess fields
+-        while (_fieldList.size()>_fields)
++        while (_fieldList.size() > _fields)
++        {
+             _fieldList.remove(_fields);
+-        
+-        StringBuilder unquoted=null;
+-        
++        }
++
++        StringBuilder unquoted = null;
++
+         // For each cookie field
+         for (String hdr : _fieldList)
+         {
+@@ -132,25 +133,31 @@ public class CookieCutter
+ 
+             Cookie cookie = null;
+ 
+-            boolean invalue=false;
+-            boolean inQuoted=false;
+-            boolean quoted=false;
+-            boolean escaped=false;
+-            int tokenstart=-1;
+-            int tokenend=-1;
++            boolean invalue = false;
++            boolean inQuoted = false;
++            boolean quoted = false;
++            boolean escaped = false;
++            boolean reject = false;
++            int tokenstart = -1;
++            int tokenend = -1;
+             for (int i = 0, length = hdr.length(); i <= length; i++)
+             {
+-                char c = i==length?0:hdr.charAt(i);
+-             
+-                // System.err.printf("i=%d/%d c=%s v=%b q=%b/%b e=%b u=%s s=%d e=%d \t%s=%s%n" ,i,length,c==0?"|":(""+c),invalue,inQuoted,quoted,escaped,unquoted,tokenstart,tokenend,name,value);
+-                
++                char c = i == length ? 0 : hdr.charAt(i);
++
+                 // Handle quoted values for name or value
+                 if (inQuoted)
+                 {
++                    boolean eol = c == 0 && i == hdr.length();
++                    if (!eol && _compliance != CookieCompliance.RFC2965 && isRFC6265RejectedCharacter(inQuoted, c))
++                    {
++                        reject = true;
++                        continue;
++                    }
++
+                     if (escaped)
+                     {
+-                        escaped=false;
+-                        if (c>0)
++                        escaped = false;
++                        if (c > 0)
+                             unquoted.append(c);
+                         else
+                         {
+@@ -160,7 +167,7 @@ public class CookieCutter
+                         }
+                         continue;
+                     }
+-                    
++
+                     switch (c)
+                     {
+                         case '"':
+@@ -175,15 +182,24 @@ public class CookieCutter
+                             continue;
+ 
+                         case 0:
+-                            // unterminated quote, let's ignore quotes
++                            // unterminated quote
++                            if (_compliance == CookieCompliance.RFC6265)
++                                continue;
++                            // let's ignore quotes
+                             unquoted.setLength(0);
+                             inQuoted = false;
+                             i--;
+                             continue;
+-                            
++
++                        case ';':
++                            if (_compliance == CookieCompliance.RFC6265)
++                                reject = true;
++                            else
++                                unquoted.append(c);
++                            continue;
++
+                         default:
+                             unquoted.append(c);
+-                            continue;
+                     }
+                 }
+                 else
+@@ -191,7 +207,14 @@ public class CookieCutter
+                     // Handle name and value state machines
+                     if (invalue)
+                     {
+-                        // parse the value
++                        boolean eol = c == 0 && i == hdr.length();
++                        if (!eol && _compliance == CookieCompliance.RFC6265 && isRFC6265RejectedCharacter(inQuoted, c))
++                        {
++                            reject = true;
++                            continue;
++                        }
++
++                        // parse the cookie-value
+                         switch (c)
+                         {
+                             case ' ':
+@@ -199,19 +222,19 @@ public class CookieCutter
+                                 break;
+ 
+                             case ',':
+-                                if (_compliance!=CookieCompliance.RFC2965)
++                                if (_compliance != CookieCompliance.RFC2965)
+                                 {
+                                     if (quoted)
+                                     {
+                                         // must have been a bad internal quote. let's fix as best we can
+-                                        unquoted.append(hdr,tokenstart,i--);
++                                        unquoted.append(hdr, tokenstart, i--);
+                                         inQuoted = true;
+                                         quoted = false;
+                                         continue;
+                                     }
+-                                    if (tokenstart<0)
++                                    if (tokenstart < 0)
+                                         tokenstart = i;
+-                                    tokenend=i;
++                                    tokenend = i;
+                                     continue;
+                                 }
+                                 // fall through
+@@ -226,8 +249,8 @@ public class CookieCutter
+                                     unquoted.setLength(0);
+                                     quoted = false;
+                                 }
+-                                else if(tokenstart>=0)
+-                                    value = tokenend>=tokenstart?hdr.substring(tokenstart, tokenend+1):hdr.substring(tokenstart);
++                                else if (tokenstart >= 0)
++                                    value = tokenend >= tokenstart ? hdr.substring(tokenstart, tokenend + 1) : hdr.substring(tokenstart);
+                                 else
+                                     value = "";
+ 
+@@ -235,22 +258,22 @@ public class CookieCutter
+                                 {
+                                     if (name.startsWith("$"))
+                                     {
+-                                        if (_compliance==CookieCompliance.RFC2965)
++                                        if (_compliance == CookieCompliance.RFC2965)
+                                         {
+                                             String lowercaseName = name.toLowerCase(Locale.ENGLISH);
+-                                            switch(lowercaseName)
++                                            switch (lowercaseName)
+                                             {
+                                                 case "$path":
+-                                                    if (cookie!=null)
++                                                    if (cookie != null)
+                                                         cookie.setPath(value);
+                                                     break;
+                                                 case "$domain":
+-                                                    if (cookie!=null)
++                                                    if (cookie != null)
+                                                         cookie.setDomain(value);
+                                                     break;
+                                                 case "$port":
+-                                                    if (cookie!=null)
+-                                                        cookie.setComment("$port="+value);
++                                                    if (cookie != null)
++                                                        cookie.setComment("$port=" + value);
+                                                     break;
+                                                 case "$version":
+                                                     version = Integer.parseInt(value);
+@@ -265,7 +288,10 @@ public class CookieCutter
+                                         cookie = new Cookie(name, value);
+                                         if (version > 0)
+                                             cookie.setVersion(version);
+-                                        cookies.add(cookie);
++                                        if (!reject)
++                                        {
++                                            cookies.add(cookie);
++                                        }
+                                     }
+                                 }
+                                 catch (Exception e)
+@@ -275,46 +301,68 @@ public class CookieCutter
+ 
+                                 name = null;
+                                 tokenstart = -1;
+-                                invalue=false;
++                                invalue = false;
++                                reject = false;
+ 
+                                 break;
+                             }
+ 
+                             case '"':
+-                                if (tokenstart<0)
++                                if (tokenstart < 0)
+                                 {
+-                                    tokenstart=i;
+-                                    inQuoted=true;
+-                                    if (unquoted==null)
+-                                        unquoted=new StringBuilder();
++                                    tokenstart = i;
++                                    inQuoted = true;
++                                    if (unquoted == null)
++                                        unquoted = new StringBuilder();
+                                     break;
+                                 }
++                                else if (_compliance == CookieCompliance.RFC6265)
++                                {
++                                    reject = true;
++                                    continue;
++                                }
+                                 // fall through to default case
+ 
+                             default:
++                                if (_compliance == CookieCompliance.RFC6265 && quoted)
++                                {
++                                    reject = true;
++                                    continue;
++                                }
++
+                                 if (quoted)
+                                 {
+                                     // must have been a bad internal quote. let's fix as best we can
+-                                    unquoted.append(hdr,tokenstart,i--);
++                                    unquoted.append(hdr, tokenstart, i--);
+                                     inQuoted = true;
+                                     quoted = false;
+                                     continue;
+                                 }
+-                                if (tokenstart<0)
++
++                                if (_compliance == CookieCompliance.RFC6265_LEGACY && isRFC6265RejectedCharacter(inQuoted, c))
++                                    reject = true;
++
++                                if (tokenstart < 0)
+                                     tokenstart = i;
+-                                tokenend=i;
+-                                continue;
++                                tokenend = i;
+                         }
+                     }
+                     else
+                     {
+-                        // parse the name
++                        // parse the cookie-name
+                         switch (c)
+                         {
+                             case ' ':
+                             case '\t':
+                                 continue;
+ 
++                            case ';':
++                                // a cookie terminated with no '=' sign.
++                                tokenstart = -1;
++                                invalue = false;
++                                reject = false;
++                                continue;
++
+                             case '=':
+                                 if (quoted)
+                                 {
+@@ -322,8 +370,8 @@ public class CookieCutter
+                                     unquoted.setLength(0);
+                                     quoted = false;
+                                 }
+-                                else if(tokenstart>=0)
+-                                    name = tokenend>=tokenstart?hdr.substring(tokenstart, tokenend+1):hdr.substring(tokenstart);
++                                else if (tokenstart >= 0)
++                                    name = tokenend >= tokenstart ? hdr.substring(tokenstart, tokenend + 1) : hdr.substring(tokenstart);
+ 
+                                 tokenstart = -1;
+                                 invalue = true;
+@@ -333,14 +381,18 @@ public class CookieCutter
+                                 if (quoted)
+                                 {
+                                     // must have been a bad internal quote. let's fix as best we can
+-                                    unquoted.append(hdr,tokenstart,i--);
++                                    unquoted.append(hdr, tokenstart, i--);
+                                     inQuoted = true;
+                                     quoted = false;
+                                     continue;
+                                 }
+-                                if (tokenstart<0)
+-                                    tokenstart=i;
+-                                tokenend=i;
++
++                                if (_compliance != CookieCompliance.RFC2965 && isRFC6265RejectedCharacter(inQuoted, c))
++                                    reject = true;
++
++                                if (tokenstart < 0)
++                                    tokenstart = i;
++                                tokenend = i;
+                                 continue;
+                         }
+                     }
+@@ -348,8 +400,45 @@ public class CookieCutter
+             }
+         }
+ 
+-        _cookies = (Cookie[]) cookies.toArray(new Cookie[cookies.size()]);
+-        _lastCookies=_cookies;
++        _cookies = cookies.toArray(new Cookie[0]);
++        _lastCookies = _cookies;
++    }
++
++
++    protected boolean isRFC6265RejectedCharacter(boolean inQuoted, char c)
++    {
++        // LEGACY test
++        if (_compliance == CookieCompliance.RFC6265_LEGACY)
++        {
++            if (inQuoted)
++            {
++                // We only reject if a Control Character is encountered
++                if (Character.isISOControl(c))
++                    return true;
++            }
++            else
++            {
++                return Character.isISOControl(c) || // control characters
++                    c > 127 || // 8-bit characters
++                    c == ',' || // comma
++                    c == ';'; // semicolon
++            }
++            return false;
++        }
++
++        /* From RFC6265 - Section 4.1.1 - Syntax
++         *  cookie-octet  = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
++         *                  ; US-ASCII characters excluding CTLs,
++         *                  ; whitespace DQUOTE, comma, semicolon,
++         *                  ; and backslash
++         *
++         * Note: DQUOTE and semicolon are used as separator by the parser,
++         * so we can consider them authorized.
++         */
++        return c > 127 ||  // 8-bit characters
++            Character.isISOControl(c) || // control characters
++            c == ',' || // comma
++            c == '\\';  // backslash
+     }
+     
+ }
+diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/CookieCutterTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/CookieCutterTest.java
+index ec534a1..3e84ce6 100644
+--- a/jetty-server/src/test/java/org/eclipse/jetty/server/CookieCutterTest.java
++++ b/jetty-server/src/test/java/org/eclipse/jetty/server/CookieCutterTest.java
+@@ -1,6 +1,6 @@
+ //
+ //  ========================================================================
+-//  Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
++//  Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
+ //  ------------------------------------------------------------------------
+ //  All rights reserved. This program and the accompanying materials
+ //  are made available under the terms of the Eclipse Public License v1.0
+@@ -18,18 +18,21 @@
+ 
+ package org.eclipse.jetty.server;
+ 
+-import static org.hamcrest.Matchers.is;
+-import static org.hamcrest.MatcherAssert.assertThat;
+-
++import java.util.Arrays;
++import java.util.List;
+ import javax.servlet.http.Cookie;
+ 
+ import org.eclipse.jetty.http.CookieCompliance;
+-import org.junit.jupiter.api.Disabled;
+ import org.junit.jupiter.api.Test;
++import org.junit.jupiter.params.ParameterizedTest;
++import org.junit.jupiter.params.provider.MethodSource;
++
++import static org.hamcrest.MatcherAssert.assertThat;
++import static org.hamcrest.Matchers.is;
+ 
+ public class CookieCutterTest
+ {
+-    private Cookie[] parseCookieHeaders(CookieCompliance compliance,String... headers)
++    private Cookie[] parseCookieHeaders(CookieCompliance compliance, String... headers)
+     {
+         CookieCutter cutter = new CookieCutter(compliance);
+         for (String header : headers)
+@@ -38,7 +41,7 @@ public class CookieCutterTest
+         }
+         return cutter.getCookies();
+     }
+-    
++
+     private void assertCookie(String prefix, Cookie cookie,
+                               String expectedName,
+                               String expectedValue,
+@@ -50,142 +53,174 @@ public class CookieCutterTest
+         assertThat(prefix + ".version", cookie.getVersion(), is(expectedVersion));
+         assertThat(prefix + ".path", cookie.getPath(), is(expectedPath));
+     }
+-    
++
+     /**
+      * Example from RFC2109 and RFC2965
+      */
+     @Test
+-    public void testRFC_Single()
++    public void testRFCSingle()
+     {
+         String rawCookie = "$Version=\"1\"; Customer=\"WILE_E_COYOTE\"; $Path=\"/acme\"";
+-        
+-        Cookie cookies[] = parseCookieHeaders(CookieCompliance.RFC2965,rawCookie);
+-        
++
++        Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC2965, rawCookie);
++
+         assertThat("Cookies.length", cookies.length, is(1));
+         assertCookie("Cookies[0]", cookies[0], "Customer", "WILE_E_COYOTE", 1, "/acme");
+     }
+-    
++
++    /**
++     * Example from RFC2109 and RFC2965.
++     * <p>
++     * Lenient parsing, input has no spaces after ';' token.
++     * </p>
++     */
++    @Test
++    public void testRFCSingleLenientNoSpaces()
++    {
++        String rawCookie = "$Version=\"1\";Customer=\"WILE_E_COYOTE\";$Path=\"/acme\"";
++
++        Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC2965, rawCookie);
++
++        assertThat("Cookies.length", cookies.length, is(1));
++        assertCookie("Cookies[0]", cookies[0], "Customer", "WILE_E_COYOTE", 1, "/acme");
++    }
++
+     /**
+      * Example from RFC2109 and RFC2965
+      */
+     @Test
+-    public void testRFC_Double()
++    public void testRFCDouble()
+     {
+         String rawCookie = "$Version=\"1\"; " +
+-                "Customer=\"WILE_E_COYOTE\"; $Path=\"/acme\"; " +
+-                "Part_Number=\"Rocket_Launcher_0001\"; $Path=\"/acme\"";
+-        
+-        Cookie cookies[] = parseCookieHeaders(CookieCompliance.RFC2965,rawCookie);
+-        
++            "Customer=\"WILE_E_COYOTE\"; $Path=\"/acme\"; " +
++            "Part_Number=\"Rocket_Launcher_0001\"; $Path=\"/acme\"";
++
++        Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC2965, rawCookie);
++
+         assertThat("Cookies.length", cookies.length, is(2));
+         assertCookie("Cookies[0]", cookies[0], "Customer", "WILE_E_COYOTE", 1, "/acme");
+         assertCookie("Cookies[1]", cookies[1], "Part_Number", "Rocket_Launcher_0001", 1, "/acme");
+     }
+-    
++
+     /**
+      * Example from RFC2109 and RFC2965
+      */
+     @Test
+-    public void testRFC_Triple()
++    public void testRFCTriple()
+     {
+         String rawCookie = "$Version=\"1\"; " +
+-                "Customer=\"WILE_E_COYOTE\"; $Path=\"/acme\"; " +
+-                "Part_Number=\"Rocket_Launcher_0001\"; $Path=\"/acme\"; " +
+-                "Shipping=\"FedEx\"; $Path=\"/acme\"";
+-        
+-        Cookie cookies[] = parseCookieHeaders(CookieCompliance.RFC2965,rawCookie);
+-        
++            "Customer=\"WILE_E_COYOTE\"; $Path=\"/acme\"; " +
++            "Part_Number=\"Rocket_Launcher_0001\"; $Path=\"/acme\"; " +
++            "Shipping=\"FedEx\"; $Path=\"/acme\"";
++
++        Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC2965, rawCookie);
++
+         assertThat("Cookies.length", cookies.length, is(3));
+         assertCookie("Cookies[0]", cookies[0], "Customer", "WILE_E_COYOTE", 1, "/acme");
+         assertCookie("Cookies[1]", cookies[1], "Part_Number", "Rocket_Launcher_0001", 1, "/acme");
+         assertCookie("Cookies[2]", cookies[2], "Shipping", "FedEx", 1, "/acme");
+     }
+-    
++
+     /**
+      * Example from RFC2109 and RFC2965
+      */
+     @Test
+-    public void testRFC_PathExample()
++    public void testRFCPathExample()
+     {
+         String rawCookie = "$Version=\"1\"; " +
+-                "Part_Number=\"Riding_Rocket_0023\"; $Path=\"/acme/ammo\"; " +
+-                "Part_Number=\"Rocket_Launcher_0001\"; $Path=\"/acme\"";
+-        
+-        Cookie cookies[] = parseCookieHeaders(CookieCompliance.RFC2965,rawCookie);
+-        
++            "Part_Number=\"Riding_Rocket_0023\"; $Path=\"/acme/ammo\"; " +
++            "Part_Number=\"Rocket_Launcher_0001\"; $Path=\"/acme\"";
++
++        Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC2965, rawCookie);
++
+         assertThat("Cookies.length", cookies.length, is(2));
+         assertCookie("Cookies[0]", cookies[0], "Part_Number", "Riding_Rocket_0023", 1, "/acme/ammo");
+         assertCookie("Cookies[1]", cookies[1], "Part_Number", "Rocket_Launcher_0001", 1, "/acme");
+     }
+-    
++
+     /**
+      * Example from RFC2109
+      */
+     @Test
+-    public void testRFC2109_CookieSpoofingExample()
++    public void testRFC2109CookieSpoofingExample()
+     {
+         String rawCookie = "$Version=\"1\"; " +
+-                "session_id=\"1234\"; " +
+-                "session_id=\"1111\"; $Domain=\".cracker.edu\"";
+-        
+-        Cookie cookies[] = parseCookieHeaders(CookieCompliance.RFC2965,rawCookie);
+-        
++            "session_id=\"1234\"; " +
++            "session_id=\"1111\"; $Domain=\".cracker.edu\"";
++
++        Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC2965, rawCookie);
++
+         assertThat("Cookies.length", cookies.length, is(2));
+         assertCookie("Cookies[0]", cookies[0], "session_id", "1234", 1, null);
+         assertCookie("Cookies[1]", cookies[1], "session_id", "1111", 1, null);
+     }
+-    
++
+     /**
+      * Example from RFC2965
+      */
+     @Test
+-    public void testRFC2965_CookieSpoofingExample()
++    public void testRFC2965CookieSpoofingExample()
+     {
+         String rawCookie = "$Version=\"1\"; session_id=\"1234\", " +
+-                "$Version=\"1\"; session_id=\"1111\"; $Domain=\".cracker.edu\"";
+-
+-
+-        Cookie cookies[] = parseCookieHeaders(CookieCompliance.RFC2965,rawCookie);
++            "$Version=\"1\"; session_id=\"1111\"; $Domain=\".cracker.edu\"";
+ 
++        Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC2965, rawCookie);
+         assertThat("Cookies.length", cookies.length, is(2));
+         assertCookie("Cookies[0]", cookies[0], "session_id", "1234", 1, null);
+         assertCookie("Cookies[1]", cookies[1], "session_id", "1111", 1, null);
+ 
+-        cookies = parseCookieHeaders(CookieCompliance.RFC6265,rawCookie);
+-        assertThat("Cookies.length", cookies.length, is(2));
+-        assertCookie("Cookies[0]", cookies[0], "session_id", "1234\", $Version=\"1", 0, null);
+-        assertCookie("Cookies[1]", cookies[1], "session_id", "1111", 0, null);
++        cookies = parseCookieHeaders(CookieCompliance.RFC6265, rawCookie);
++        assertThat("Cookies.length", cookies.length, is(1));
++        assertCookie("Cookies[0]", cookies[0], "session_id", "1111", 0, null);
+     }
+-    
++
+     /**
+      * Example from RFC6265
+      */
+     @Test
+-    public void testRFC6265_SidExample()
++    public void testRFC6265SidExample()
+     {
+         String rawCookie = "SID=31d4d96e407aad42";
+-        
+-        Cookie cookies[] = parseCookieHeaders(CookieCompliance.RFC6265,rawCookie);
+-        
++
++        Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC6265, rawCookie);
++
+         assertThat("Cookies.length", cookies.length, is(1));
+         assertCookie("Cookies[0]", cookies[0], "SID", "31d4d96e407aad42", 0, null);
+     }
+-    
++
+     /**
+      * Example from RFC6265
+      */
+     @Test
+-    public void testRFC6265_SidLangExample()
++    public void testRFC6265SidLangExample()
+     {
+         String rawCookie = "SID=31d4d96e407aad42; lang=en-US";
+-        
+-        Cookie cookies[] = parseCookieHeaders(CookieCompliance.RFC6265,rawCookie);
+-        
++
++        Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC6265, rawCookie);
++
++        assertThat("Cookies.length", cookies.length, is(2));
++        assertCookie("Cookies[0]", cookies[0], "SID", "31d4d96e407aad42", 0, null);
++        assertCookie("Cookies[1]", cookies[1], "lang", "en-US", 0, null);
++    }
++
++    /**
++     * Example from RFC6265.
++     * <p>
++     * Lenient parsing, input has no spaces after ';' token.
++     * </p>
++     */
++    @Test
++    public void testRFC6265SidLangExampleLenient()
++    {
++        String rawCookie = "SID=31d4d96e407aad42;lang=en-US";
++
++        Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC6265, rawCookie);
++
+         assertThat("Cookies.length", cookies.length, is(2));
+         assertCookie("Cookies[0]", cookies[0], "SID", "31d4d96e407aad42", 0, null);
+         assertCookie("Cookies[1]", cookies[1], "lang", "en-US", 0, null);
+     }
+-    
++
+     /**
+      * Basic name=value, following RFC6265 rules
+      */
+@@ -193,13 +228,13 @@ public class CookieCutterTest
+     public void testKeyValue()
+     {
+         String rawCookie = "key=value";
+-        
+-        Cookie cookies[] = parseCookieHeaders(CookieCompliance.RFC6265,rawCookie);
+-        
++
++        Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC6265, rawCookie);
++
+         assertThat("Cookies.length", cookies.length, is(1));
+         assertCookie("Cookies[0]", cookies[0], "key", "value", 0, null);
+     }
+-    
++
+     /**
+      * Basic name=value, following RFC6265 rules
+      */
+@@ -207,9 +242,116 @@ public class CookieCutterTest
+     public void testDollarName()
+     {
+         String rawCookie = "$key=value";
+-        
+-        Cookie cookies[] = parseCookieHeaders(CookieCompliance.RFC6265,rawCookie);
+-        
++
++        Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC6265, rawCookie);
++
+         assertThat("Cookies.length", cookies.length, is(0));
+     }
++
++    @Test
++    public void testMultipleCookies()
++    {
++        String rawCookie = "testcookie; server.id=abcd; server.detail=cfg";
++
++        // The first cookie "testcookie" should be ignored, per RFC6265, as it's missing the "=" sign.
++
++        Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC6265, rawCookie);
++
++        assertThat("Cookies.length", cookies.length, is(2));
++        assertCookie("Cookies[0]", cookies[0], "server.id", "abcd", 0, null);
++        assertCookie("Cookies[1]", cookies[1], "server.detail", "cfg", 0, null);
++    }
++
++    @Test
++    public void testExcessiveSemicolons()
++    {
++        char[] excessive = new char[65535];
++        Arrays.fill(excessive, ';');
++        String rawCookie = "foo=bar; " + new String(excessive) + "; xyz=pdq";
++
++        Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC6265, rawCookie);
++
++        assertThat("Cookies.length", cookies.length, is(2));
++        assertCookie("Cookies[0]", cookies[0], "foo", "bar", 0, null);
++        assertCookie("Cookies[1]", cookies[1], "xyz", "pdq", 0, null);
++    }
++
++    @ParameterizedTest
++    @MethodSource("rfc6265Cookies")
++    public void testRFC6265CookieParsing(Param param)
++    {
++        Cookie[] cookies = parseCookieHeaders(CookieCompliance.RFC6265, param.input);
++
++        assertThat("Cookies.length (" + dump(cookies) + ")", cookies.length, is(param.expected.size()));
++        for (int i = 0; i < cookies.length; i++)
++        {
++            Cookie cookie = cookies[i];
++            assertThat("Cookies[" + i + "] (" + dump(cookies) + ")", cookie.getName() + "=" + cookie.getValue(), is(param.expected.get(i)));
++        }
++    }
++
++    public static List<Param> rfc6265Cookies()
++    {
++        return Arrays.asList(
++            new Param("A=1; B=2; C=3", "A=1", "B=2", "C=3"),
++            new Param("A=\"1\"; B=2; C=3", "A=1", "B=2", "C=3"),
++            new Param("A=\"1\"; B=\"2\"; C=\"3\"", "A=1", "B=2", "C=3"),
++            new Param("A=1; B=2; C=\"3", "A=1", "B=2"),
++            new Param("A=1 ; B=2; C=3", "A=1", "B=2", "C=3"),
++            new Param("A= 1; B=2; C=3", "A=1", "B=2", "C=3"),
++            new Param("A=\"1; B=2\"; C=3", "C=3"),
++            new Param("A=\"1; B=2; C=3"),
++            new Param("A=\"1 B=2\"; C=3", "A=1 B=2", "C=3"),
++            new Param("A=\"\"1; B=2; C=3", "B=2", "C=3"),
++            new Param("A=\"\" ; B=2; C=3", "A=", "B=2", "C=3"),
++            new Param("A=\"\"; B=2; C=3", "A=", "B=2", "C=3"),
++            new Param("A=1\"\"; B=2; C=3", "B=2", "C=3"),
++            new Param("A=1\"; B=2; C=3", "B=2", "C=3"),
++            new Param("A=1\"1; B=2; C=3", "B=2", "C=3"),
++            new Param("A=\" 1\"; B=2; C=3", "A= 1", "B=2", "C=3"),
++            new Param("A=\"1 \"; B=2; C=3", "A=1 ", "B=2", "C=3"),
++            new Param("A=\" 1 \"; B=2; C=3", "A= 1 ", "B=2", "C=3"),
++            new Param("A=\" 1 1 \"; B=2; C=3", "A= 1 1 ", "B=2", "C=3"),
++            new Param("A=1,; B=2; C=3", "B=2", "C=3"),
++            new Param("A=\"1,\"; B=2; C=3", "B=2", "C=3"),
++            new Param("A=\\1; B=2; C=3", "B=2", "C=3"),
++            new Param("A=\"\\1\"; B=2; C=3", "B=2", "C=3"),
++            new Param("A=1\u0007; B=2; C=3", "B=2", "C=3"),
++            new Param("A=\"1\u0007\"; B=2; C=3", "B=2", "C=3"),
++            new Param("€"),
++            new Param("@={}"),
++            new Param("$X=Y; N=V", "N=V"),
++            new Param("N=V; $X=Y", "N=V")
++        );
++    }
++
++    private static String dump(Cookie[] cookies)
++    {
++        StringBuilder sb = new StringBuilder();
++        for (Cookie cookie : cookies)
++        {
++            sb.append("<").append(cookie.getName()).append(">=<").append(cookie.getValue()).append("> | ");
++        }
++        if (sb.length() > 0)
++            sb.delete(sb.length() - 2, sb.length() - 1);
++        return sb.toString();
++    }
++
++    private static class Param
++    {
++        private final String input;
++        private final List<String> expected;
++
++        public Param(String input, String... expected)
++        {
++            this.input = input;
++            this.expected = Arrays.asList(expected);
++        }
++
++        @Override
++        public String toString()
++        {
++            return input + " -> " + expected.toString();
++        }
++    }
+ }
+diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java
+index 425a9ae..f119864 100644
+--- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java
++++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java
+@@ -61,6 +61,7 @@ import javax.servlet.http.HttpServletResponse;
+ import javax.servlet.http.Part;
+ 
+ import org.eclipse.jetty.http.BadMessageException;
++import org.eclipse.jetty.http.CookieCompliance;
+ import org.eclipse.jetty.http.HttpCompliance;
+ import org.eclipse.jetty.http.HttpTester;
+ import org.eclipse.jetty.http.MimeTypes;
+@@ -97,6 +98,7 @@ public class RequestTest
+         http.getHttpConfiguration().setRequestHeaderSize(512);
+         http.getHttpConfiguration().setResponseHeaderSize(512);
+         http.getHttpConfiguration().setOutputBufferSize(2048);
++        http.getHttpConfiguration().setRequestCookieCompliance(CookieCompliance.RFC6265_LEGACY);
+         http.getHttpConfiguration().addCustomizer(new ForwardedRequestCustomizer());
+         _connector = new LocalConnector(_server,http);
+         _server.addConnector(_connector);


=====================================
debian/patches/CVE-2023-36479.patch
=====================================
@@ -0,0 +1,50 @@
+From: Markus Koschany <apo at debian.org>
+Date: Wed, 27 Sep 2023 14:25:09 +0200
+Subject: CVE-2023-36479
+
+The org.eclipse.jetty.servlets.CGI Servlet should not be used anymore.
+Upstream recommends to use Fast CGI instead.
+
+Origin: https://github.com/eclipse/jetty.project/pull/9888
+---
+ .../src/main/java/org/eclipse/jetty/servlets/CGI.java         |  3 +++
+ .../test-jetty-webapp/src/main/webapp/WEB-INF/web.xml         | 11 -----------
+ 2 files changed, 3 insertions(+), 11 deletions(-)
+
+diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java
+index 6322290..55d8f9a 100644
+--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java
++++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CGI.java
+@@ -67,7 +67,10 @@ import org.eclipse.jetty.util.log.Logger;
+  * <dt>ignoreExitState</dt>
+  * <dd>If true then do not act on a non-zero exec exit status")</dd>
+  * </dl>
++ *
++ * @deprecated do not use, no replacement, will be removed in a future release.
+  */
++ at Deprecated
+ public class CGI extends HttpServlet
+ {
+     private static final long serialVersionUID = -6182088932884791074L;
+diff --git a/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml b/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml
+index 507771f..978595f 100644
+--- a/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml
++++ b/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml
+@@ -121,17 +121,6 @@
+     <url-pattern>/dispatch/*</url-pattern>
+   </servlet-mapping>
+   
+-  <servlet>
+-    <servlet-name>CGI</servlet-name>
+-    <servlet-class>org.eclipse.jetty.servlets.CGI</servlet-class>
+-    <load-on-startup>1</load-on-startup>
+-  </servlet>
+-  
+-  <servlet-mapping>
+-    <servlet-name>CGI</servlet-name>
+-    <url-pattern>/cgi-bin/*</url-pattern>
+-  </servlet-mapping>
+-  
+   <servlet>
+     <servlet-name>Chat</servlet-name>
+     <servlet-class>com.acme.ChatServlet</servlet-class>


=====================================
debian/patches/CVE-2023-40167.patch
=====================================
@@ -0,0 +1,256 @@
+From: Markus Koschany <apo at debian.org>
+Date: Tue, 26 Sep 2023 21:06:42 +0200
+Subject: CVE-2023-40167
+
+Origin: https://github.com/eclipse/jetty.project/commit/e4d596eafc887bcd813ae6e28295b5ce327def47
+---
+ .../java/org/eclipse/jetty/http/HttpParser.java    | 47 +++++++-------
+ .../org/eclipse/jetty/http/HttpParserTest.java     | 71 +++++-----------------
+ 2 files changed, 38 insertions(+), 80 deletions(-)
+
+diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
+index 2abc4b6..c045498 100644
+--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
++++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
+@@ -501,7 +501,7 @@ public class HttpParser
+     /* Quick lookahead for the start state looking for a request method or a HTTP version,
+      * otherwise skip white space until something else to parse.
+      */
+-    private boolean quickStart(ByteBuffer buffer)
++    private void quickStart(ByteBuffer buffer)
+     {
+         if (_requestHandler!=null)
+         {
+@@ -512,7 +512,7 @@ public class HttpParser
+                 buffer.position(buffer.position()+_methodString.length()+1);
+ 
+                 setState(State.SPACE1);
+-                return false;
++                return;
+             }
+         }
+         else if (_responseHandler!=null)
+@@ -522,7 +522,7 @@ public class HttpParser
+             {
+                 buffer.position(buffer.position()+_version.asString().length()+1);
+                 setState(State.SPACE1);
+-                return false;
++                return;
+             }
+         }
+ 
+@@ -543,7 +543,7 @@ public class HttpParser
+                     _string.setLength(0);
+                     _string.append(t.getChar());
+                     setState(_requestHandler!=null?State.METHOD:State.RESPONSE_VERSION);
+-                    return false;
++                    return;
+                 }
+                 case OTEXT:
+                 case SPACE:
+@@ -561,7 +561,6 @@ public class HttpParser
+                 throw new BadMessageException(HttpStatus.BAD_REQUEST_400);
+             }
+         }
+-        return false;
+     }
+ 
+     /* ------------------------------------------------------------------------------- */
+@@ -979,12 +978,13 @@ public class HttpParser
+                 switch (_header)
+                 {
+                     case CONTENT_LENGTH:
++                        long contentLength = convertContentLength(_valueString);
+                         if (_hasContentLength)
+                         {
+                             if(complianceViolation(MULTIPLE_CONTENT_LENGTHS))
+                                 throw new BadMessageException(HttpStatus.BAD_REQUEST_400,MULTIPLE_CONTENT_LENGTHS.description);
+-                            if (convertContentLength(_valueString)!=_contentLength)
+-                                throw new BadMessageException(HttpStatus.BAD_REQUEST_400,MULTIPLE_CONTENT_LENGTHS.description);
++                            if (contentLength != _contentLength)
++                                throw new BadMessageException(HttpStatus.BAD_REQUEST_400, MULTIPLE_CONTENT_LENGTHS.getDescription());
+                         }
+                         _hasContentLength = true;
+ 
+@@ -993,11 +993,8 @@ public class HttpParser
+ 
+                         if (_endOfContent != EndOfContent.CHUNKED_CONTENT)
+                         {
+-                            _contentLength=convertContentLength(_valueString);
+-                            if (_contentLength <= 0)
+-                                _endOfContent=EndOfContent.NO_CONTENT;
+-                            else
+-                                _endOfContent=EndOfContent.CONTENT_LENGTH;
++                            _contentLength = contentLength;
++                            _endOfContent = EndOfContent.CONTENT_LENGTH;
+                         }
+                         break;
+ 
+@@ -1085,15 +1082,21 @@ public class HttpParser
+     
+     private long convertContentLength(String valueString)
+     {
+-        try
+-        {
+-            return Long.parseLong(valueString);
+-        }
+-        catch(NumberFormatException e)
++        if (valueString == null || valueString.length() == 0)
++            throw new BadMessageException("Invalid Content-Length Value", new NumberFormatException());
++
++        long value = 0;
++        int length = valueString.length();
++
++        for (int i = 0; i < length; i++)
+         {
+-            LOG.ignore(e);
+-            throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Invalid Content-Length Value",e);
++            char c = valueString.charAt(i);
++            if (c < '0' || c > '9')
++                throw new BadMessageException("Invalid Content-Length Value", new NumberFormatException());
++
++            value = Math.addExact(Math.multiplyExact(value, 10L), c - '0');
+         }
++        return value;
+     }
+ 
+     /* ------------------------------------------------------------------------------- */
+@@ -1485,12 +1488,11 @@ public class HttpParser
+                 _methodString=null;
+                 _endOfContent=EndOfContent.UNKNOWN_CONTENT;
+                 _header=null;
+-                if (quickStart(buffer))
+-                    return true;
++                quickStart(buffer);
+             }
+ 
+             // Request/response line
+-            if (_state.ordinal()>= State.START.ordinal() && _state.ordinal()<State.HEADER.ordinal())
++            if (_state.ordinal() < State.HEADER.ordinal())
+             {
+                 if (parseLine(buffer))
+                     return true;
+@@ -1994,7 +1996,6 @@ public class HttpParser
+     }
+ 
+     /* ------------------------------------------------------------------------------- */
+-    @SuppressWarnings("serial")
+     private static class IllegalCharacterException extends BadMessageException
+     {
+         private IllegalCharacterException(State state,HttpTokens.Token token,ByteBuffer buffer)
+diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
+index dc340c1..c1d59cd 100644
+--- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
++++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
+@@ -23,6 +23,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
+ import static org.hamcrest.Matchers.contains;
+ import static org.hamcrest.Matchers.containsString;
+ import static org.hamcrest.Matchers.is;
++import static org.hamcrest.Matchers.notNullValue;
+ import static org.hamcrest.Matchers.nullValue;
+ import static org.junit.jupiter.api.Assertions.assertEquals;
+ import static org.junit.jupiter.api.Assertions.assertFalse;
+@@ -1653,7 +1654,7 @@ public class HttpParserTest
+     }
+ 
+     @Test
+-    public void testUnknownReponseVersion() throws Exception
++    public void testUnknownResponseVersion()
+     {
+         ByteBuffer buffer = BufferUtil.toBuffer(
+                 "HPPT/7.7 200 OK\r\n"
+@@ -1797,65 +1798,21 @@ public class HttpParserTest
+         assertEquals(HttpParser.State.CLOSED, parser.getState());
+     }
+ 
+-    @Test
+-    public void testBadContentLength0() throws Exception
+-    {
+-        ByteBuffer buffer = BufferUtil.toBuffer(
+-                "GET / HTTP/1.0\r\n"
+-                        + "Content-Length: abc\r\n"
+-                        + "Connection: close\r\n"
+-                        + "\r\n");
+-
+-        HttpParser.RequestHandler handler = new Handler();
+-        HttpParser parser = new HttpParser(handler);
+-
+-        parser.parseNext(buffer);
+-        assertEquals("GET", _methodOrVersion);
+-        assertEquals("Invalid Content-Length Value", _bad);
+-        assertFalse(buffer.hasRemaining());
+-        assertEquals(HttpParser.State.CLOSE, parser.getState());
+-        parser.atEOF();
+-        parser.parseNext(BufferUtil.EMPTY_BUFFER);
+-        assertEquals(HttpParser.State.CLOSED, parser.getState());
+-    }
+-
+-    @Test
+-    public void testBadContentLength1() throws Exception
+-    {
+-        ByteBuffer buffer = BufferUtil.toBuffer(
+-                "GET / HTTP/1.0\r\n"
+-                        + "Content-Length: 9999999999999999999999999999999999999999999999\r\n"
+-                        + "Connection: close\r\n"
+-                        + "\r\n");
+-
+-        HttpParser.RequestHandler handler = new Handler();
+-        HttpParser parser = new HttpParser(handler);
+-
+-        parser.parseNext(buffer);
+-        assertEquals("GET", _methodOrVersion);
+-        assertEquals("Invalid Content-Length Value", _bad);
+-        assertFalse(buffer.hasRemaining());
+-        assertEquals(HttpParser.State.CLOSE, parser.getState());
+-        parser.atEOF();
+-        parser.parseNext(BufferUtil.EMPTY_BUFFER);
+-        assertEquals(HttpParser.State.CLOSED, parser.getState());
+-    }
+ 
+-    @Test
+-    public void testBadContentLength2() throws Exception
++    public void testBadContentLengths(String contentLength)
+     {
+         ByteBuffer buffer = BufferUtil.toBuffer(
+-                "GET / HTTP/1.0\r\n"
+-                        + "Content-Length: 1.5\r\n"
+-                        + "Connection: close\r\n"
+-                        + "\r\n");
++            "GET /test HTTP/1.1\r\n" +
++                "Host: localhost\r\n" +
++                "Content-Length: " + contentLength + "\r\n" +
++                "\r\n" +
++                "1234567890\r\n");
+ 
+         HttpParser.RequestHandler handler = new Handler();
+-        HttpParser parser = new HttpParser(handler);
++        HttpParser parser = new HttpParser(handler, HttpCompliance.RFC2616_LEGACY);
++        parseAll(parser, buffer);
+ 
+-        parser.parseNext(buffer);
+-        assertEquals("GET", _methodOrVersion);
+-        assertEquals("Invalid Content-Length Value", _bad);
++        assertThat(_bad, notNullValue());
+         assertFalse(buffer.hasRemaining());
+         assertEquals(HttpParser.State.CLOSE, parser.getState());
+         parser.atEOF();
+@@ -2066,7 +2023,7 @@ public class HttpParserTest
+     @Test
+     public void testBadIPv6Host() throws Exception
+     {
+-        try(StacklessLogging s = new StacklessLogging(HttpParser.class))
++        try (StacklessLogging ignored = new StacklessLogging(HttpParser.class))
+         {
+             ByteBuffer buffer = BufferUtil.toBuffer(
+                 "GET / HTTP/1.1\r\n"
+@@ -2254,8 +2211,8 @@ public class HttpParserTest
+     private String _methodOrVersion;
+     private String _uriOrStatus;
+     private String _versionOrReason;
+-    private List<HttpField> _fields = new ArrayList<>();
+-    private List<HttpField> _trailers = new ArrayList<>();
++    private final List<HttpField> _fields = new ArrayList<>();
++    private final List<HttpField> _trailers = new ArrayList<>();
+     private String[] _hdr;
+     private String[] _val;
+     private int _headers;


=====================================
debian/patches/series
=====================================
@@ -12,3 +12,7 @@ CVE-2020-27223.patch
 CVE-2021-28165.patch
 CVE-2022-2047.patch
 CVE-2022-2048.patch
+CVE-2023-26048.patch
+CVE-2023-26049.patch
+CVE-2023-40167.patch
+CVE-2023-36479.patch



View it on GitLab: https://salsa.debian.org/java-team/jetty9/-/commit/6d98df40768f47dbc9c24ea3c9149a8686e9b297

-- 
View it on GitLab: https://salsa.debian.org/java-team/jetty9/-/commit/6d98df40768f47dbc9c24ea3c9149a8686e9b297
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20230930/2c9dd35e/attachment.htm>


More information about the pkg-java-commits mailing list