diff --git a/0001-Distro-jetty.home.patch b/0001-Distro-jetty.home.patch
new file mode 100644
index 0000000000000000000000000000000000000000..269e227d4e337ce0c30dc825f5ae2870b156468f
--- /dev/null
+++ b/0001-Distro-jetty.home.patch
@@ -0,0 +1,25 @@
+From 29d160bf916b4ab358a01496029f9aaa5fba66b3 Mon Sep 17 00:00:00 2001
+From: Mat Booth
+Date: Mon, 9 Sep 2019 12:42:10 +0100
+Subject: [PATCH 1/2] Distro jetty.home
+
+---
+ .../org/eclipse/jetty/start/config/CommandLineConfigSource.java | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/config/CommandLineConfigSource.java b/jetty-start/src/main/java/org/eclipse/jetty/start/config/CommandLineConfigSource.java
+index 30440c4..cb0ed3d 100644
+--- a/jetty-start/src/main/java/org/eclipse/jetty/start/config/CommandLineConfigSource.java
++++ b/jetty-start/src/main/java/org/eclipse/jetty/start/config/CommandLineConfigSource.java
+@@ -120,6 +120,8 @@ public class CommandLineConfigSource implements ConfigSource
+ try
+ {
+ Path home = new File(new URI(m.group(1))).getParentFile().toPath();
++ if (home.endsWith("/usr/share/java/jetty"))
++ home = new File(home.toString().replaceAll("java/jetty$", "jetty")).toPath();
+ setProperty(BaseHome.JETTY_HOME, home.toString(), ORIGIN_INTERNAL_FALLBACK);
+ return home;
+ }
+--
+2.26.2
+
diff --git a/0002-Port-to-servlet-api-4-5.patch b/0002-Port-to-servlet-api-4-5.patch
new file mode 100644
index 0000000000000000000000000000000000000000..5078549a35dd4c9b4d95365a98626ba2800cadf5
--- /dev/null
+++ b/0002-Port-to-servlet-api-4-5.patch
@@ -0,0 +1,76 @@
+From 65b5de2ef9ffc5eacb23c6c4834cc1c513f0eafa Mon Sep 17 00:00:00 2001
+From: Mat Booth
+Date: Wed, 19 Aug 2020 13:14:37 +0100
+Subject: [PATCH 2/2] Port to servlet-api 4/5
+
+---
+ .../jetty/server/handler/ContextHandler.java | 46 +++++++++++++++++++
+ 1 file changed, 46 insertions(+)
+
+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 7960b0f..4981755 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
+@@ -2760,6 +2760,13 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
+ return null;
+ }
+
++ public ServletRegistration.Dynamic addJspFile(String servletName, String jspFile)
++ {
++ // TODO new in 4.0
++ LOG.warn(UNIMPLEMENTED_USE_SERVLET_CONTEXT_HANDLER, "addJspFile(String, String)");
++ return null;
++ }
++
+ @Override
+ public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Class extends Servlet> servletClass)
+ {
+@@ -2930,6 +2937,45 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
+ {
+ return null;
+ }
++
++ public int getSessionTimeout()
++ {
++ // TODO new in 4.0
++ LOG.warn(UNIMPLEMENTED_USE_SERVLET_CONTEXT_HANDLER, "getSessionTimeout()");
++ return 0;
++ }
++
++ public void setSessionTimeout(int sessionTimeout)
++ {
++ // TODO new in 4.0
++ LOG.warn(UNIMPLEMENTED_USE_SERVLET_CONTEXT_HANDLER, "setSessionTimeout(int)");
++ }
++
++ public String getRequestCharacterEncoding()
++ {
++ // TODO new in 4.0
++ LOG.warn(UNIMPLEMENTED_USE_SERVLET_CONTEXT_HANDLER, "getRequestCharacterEncoding()");
++ return null;
++ }
++
++ public void setRequestCharacterEncoding(String encoding)
++ {
++ // TODO new in 4.0
++ LOG.warn(UNIMPLEMENTED_USE_SERVLET_CONTEXT_HANDLER, "setRequestCharacterEncoding(String)");
++ }
++
++ public String getResponseCharacterEncoding()
++ {
++ // TODO new in 4.0
++ LOG.warn(UNIMPLEMENTED_USE_SERVLET_CONTEXT_HANDLER, "getResponseCharacterEncoding()");
++ return null;
++ }
++
++ public void setResponseCharacterEncoding(String encoding)
++ {
++ // TODO new in 4.0
++ LOG.warn(UNIMPLEMENTED_USE_SERVLET_CONTEXT_HANDLER, "setResponseCharacterEncoding(String)");
++ }
+ }
+
+ /**
+--
+2.26.2
+
diff --git a/CVE-2020-27216.patch b/CVE-2020-27216.patch
deleted file mode 100755
index 6b8051ab615f29ede5f197fa434ccca0d8af871b..0000000000000000000000000000000000000000
--- a/CVE-2020-27216.patch
+++ /dev/null
@@ -1,477 +0,0 @@
-From: Markus Koschany
-Date: Sat, 3 Jul 2021 22:05:57 +0200
-Subject: CVE-2020-27216
-
-Origin: https://github.com/eclipse/jetty.project/commit/53e0e0e9b25a6309bf24ee3b10984f4145701edb
-Origin: https://github.com/eclipse/jetty.project/commit/9ad6beb80543b392c91653f6bfce233fc75b9d5f
----
- .../eclipse/jetty/webapp/WebInfConfiguration.java | 20 +--
- .../server/session/InfinispanTestSupport.java | 173 +++++++++++++--------
- .../test/java/org/eclipse/jetty/TestServer.java | 54 +++----
- 3 files changed, 135 insertions(+), 112 deletions(-)
-
-diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java
-index b94f788..19663bc 100644
---- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java
-+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java
-@@ -24,6 +24,8 @@ import java.net.URI;
- import java.net.URISyntaxException;
- import java.net.URL;
- import java.net.URLClassLoader;
-+import java.nio.file.Files;
-+import java.nio.file.Path;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.List;
-@@ -384,14 +386,10 @@ public class WebInfConfiguration extends AbstractConfiguration
- @Override
- public void cloneConfigure(WebAppContext template, WebAppContext context) throws Exception
- {
-- File tmpDir=File.createTempFile(WebInfConfiguration.getCanonicalNameForWebAppTmpDir(context),"",template.getTempDirectory().getParentFile());
-- if (tmpDir.exists())
-- {
-- IO.delete(tmpDir);
-- }
-- tmpDir.mkdir();
-- tmpDir.deleteOnExit();
-- context.setTempDirectory(tmpDir);
-+ Path tmpDir = Files.createTempDirectory(template.getTempDirectory().getParentFile().toPath(), WebInfConfiguration.getCanonicalNameForWebAppTmpDir(context));
-+ File tmpDirAsFile = tmpDir.toFile();
-+ tmpDirAsFile.deleteOnExit();
-+ context.setTempDirectory(tmpDirAsFile);
- }
-
-
-@@ -522,11 +520,7 @@ public class WebInfConfiguration extends AbstractConfiguration
- else
- {
- //ensure file will always be unique by appending random digits
-- tmpDir = File.createTempFile(temp, ".dir", parent);
-- //delete the file that was created
-- tmpDir.delete();
-- //and make a directory of the same name
-- tmpDir.mkdirs();
-+ tmpDir = Files.createTempDirectory(parent.toPath(), temp).toFile();
- }
- configureTempDirectory(tmpDir, context);
-
-diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSupport.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSupport.java
-index 57ecb1f..663e8dd 100644
---- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSupport.java
-+++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSupport.java
-@@ -1,6 +1,6 @@
- //
- // ========================================================================
--// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
-+// Copyright (c) 1995-2021 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
-@@ -16,38 +16,44 @@
- // ========================================================================
- //
-
--
- package org.eclipse.jetty.server.session;
-
--import static org.junit.jupiter.api.Assertions.assertEquals;
--import static org.junit.jupiter.api.Assertions.assertTrue;
--
- import java.io.File;
-+import java.lang.annotation.ElementType;
-+import java.nio.file.Files;
-+import java.nio.file.Path;
-+import java.util.Properties;
-
-+import org.eclipse.jetty.toolchain.test.FS;
- import org.eclipse.jetty.util.IO;
-+import org.hibernate.search.cfg.Environment;
-+import org.hibernate.search.cfg.SearchMapping;
- import org.infinispan.Cache;
--import org.infinispan.configuration.cache.Configuration;
- import org.infinispan.configuration.cache.ConfigurationBuilder;
-+import org.infinispan.configuration.cache.ConfigurationChildBuilder;
-+import org.infinispan.configuration.cache.Index;
- import org.infinispan.configuration.global.GlobalConfigurationBuilder;
- import org.infinispan.manager.DefaultCacheManager;
- import org.infinispan.manager.EmbeddedCacheManager;
-
-+import static org.junit.jupiter.api.Assertions.assertEquals;
-+import static org.junit.jupiter.api.Assertions.assertTrue;
-+
- /**
- * InfinispanTestSupport
-- *
-- *
- */
- public class InfinispanTestSupport
- {
-- public static final String DEFAULT_CACHE_NAME = "session_test_cache";
-- public Cache _cache;
--
-+ public static final String DEFAULT_CACHE_NAME = "session_test_cache";
-+ public Cache _cache;
-+
- public ConfigurationBuilder _builder;
-- private File _tmpdir;
-+ private File _tmpdir;
- private boolean _useFileStore;
-+ private boolean _serializeSessionData;
- private String _name;
-- public static EmbeddedCacheManager _manager;
--
-+ public static EmbeddedCacheManager _manager;
-+
- static
- {
- try
-@@ -59,53 +65,84 @@ public class InfinispanTestSupport
- e.printStackTrace();
- }
- }
--
--
--
--
-- public InfinispanTestSupport ()
-+
-+ public InfinispanTestSupport()
- {
-- this (null);
-+ this(null);
- }
--
-+
- public InfinispanTestSupport(String cacheName)
-- {
-+ {
- if (cacheName == null)
-- cacheName = DEFAULT_CACHE_NAME+System.currentTimeMillis();
--
-+ cacheName = DEFAULT_CACHE_NAME + System.currentTimeMillis();
-+
- _name = cacheName;
- _builder = new ConfigurationBuilder();
- }
--
-- public void setUseFileStore (boolean useFileStore)
-+
-+ public void setUseFileStore(boolean useFileStore)
- {
- _useFileStore = useFileStore;
- }
--
-- public Cache getCache ()
-+
-+ public void setSerializeSessionData(boolean serializeSessionData)
- {
-- return _cache;
-+ _serializeSessionData = serializeSessionData;
- }
-
-- public void setup () throws Exception
-+ public Cache getCache()
- {
-- if (_useFileStore)
-- {
-- _tmpdir = File.createTempFile("infini", "span");
-- _tmpdir.delete();
-- _tmpdir.mkdir();
-- Configuration config = _builder.persistence().addSingleFileStore().location(_tmpdir.getAbsolutePath()).storeAsBinary().build();
-- _manager.defineConfiguration(_name, config);
-- }
-- else
-- {
-- _manager.defineConfiguration(_name, _builder.build());
-- }
-- _cache = _manager.getCache(_name);
-+ return _cache;
- }
-
-+ public void setup(Path root) throws Exception
-+ {
-+ Path indexesDir = root.resolve("indexes");
-+ FS.ensureDirExists(indexesDir);
-+
-+ SearchMapping mapping = new SearchMapping();
-+ mapping.entity(SessionData.class).indexed().providedId().property("expiry", ElementType.FIELD).field();
-+ Properties properties = new Properties();
-+ properties.put(Environment.MODEL_MAPPING, mapping);
-+ properties.put("hibernate.search.default.indexBase", indexesDir.toString());
-+
-+ if (_useFileStore)
-+ {
-+ Path tmpDir = Files.createTempDirectory("infinispan");
-+ _tmpdir = tmpDir.toFile();
-+
-+ ConfigurationChildBuilder b = _builder.indexing()
-+ .index(Index.ALL)
-+ .addIndexedEntity(SessionData.class)
-+ .withProperties(properties)
-+ .persistence()
-+ .addSingleFileStore()
-+ .location(_tmpdir.getAbsolutePath());
-+ if (_serializeSessionData)
-+ {
-+ b = b.storeAsBinary().enable();
-+ }
-+
-+ _manager.defineConfiguration(_name, b.build());
-+ }
-+ else
-+ {
-+ ConfigurationChildBuilder b = _builder.indexing()
-+ .withProperties(properties)
-+ .index(Index.ALL)
-+ .addIndexedEntity(SessionData.class);
-+
-+ if (_serializeSessionData)
-+ {
-+ b = b.storeAsBinary().enable();
-+ }
-+
-+ _manager.defineConfiguration(_name, b.build());
-+ }
-+ _cache = _manager.getCache(_name);
-+ }
-
-- public void teardown () throws Exception
-+ public void teardown() throws Exception
- {
- _cache.clear();
- _manager.removeCache(_name);
-@@ -117,39 +154,41 @@ public class InfinispanTestSupport
- }
- }
- }
--
--
-+
- @SuppressWarnings("unchecked")
-- public void createSession (SessionData data)
-- throws Exception
-+ public void createSession(SessionData data)
-+ throws Exception
- {
-- _cache.put(data.getContextPath()+"_"+data.getVhost()+"_"+data.getId(), data);
-+ _cache.put(data.getContextPath() + "_" + data.getVhost() + "_" + data.getId(), data);
- }
-
--
-- public void createUnreadableSession (SessionData data)
-+ public void createUnreadableSession(SessionData data)
- {
--
-+
- }
--
--
-- public boolean checkSessionExists (SessionData data)
-- throws Exception
-+
-+ public boolean checkSessionExists(SessionData data)
-+ throws Exception
- {
-- return (_cache.get(data.getContextPath()+"_"+data.getVhost()+"_"+data.getId()) != null);
-+ return (_cache.get(data.getContextPath() + "_" + data.getVhost() + "_" + data.getId()) != null);
- }
--
--
-- public boolean checkSessionPersisted (SessionData data)
-- throws Exception
-+
-+ public boolean checkSessionPersisted(SessionData data)
-+ throws Exception
- {
-- Object obj = _cache.get(data.getContextPath()+"_"+data.getVhost()+"_"+data.getId());
-+
-+ //evicts the object from memory. Forces the cache to fetch the data from file
-+ if (_useFileStore)
-+ {
-+ _cache.evict(data.getContextPath() + "_" + data.getVhost() + "_" + data.getId());
-+ }
-+
-+ Object obj = _cache.get(data.getContextPath() + "_" + data.getVhost() + "_" + data.getId());
- if (obj == null)
- return false;
--
-+
- SessionData saved = (SessionData)obj;
--
--
-+
- //turn an Entity into a Session
- assertEquals(data.getId(), saved.getId());
- assertEquals(data.getContextPath(), saved.getContextPath());
-@@ -168,11 +207,11 @@ public class InfinispanTestSupport
- //same keys
- assertTrue(data.getKeys().equals(saved.getKeys()));
- //same values
-- for (String name:data.getKeys())
-+ for (String name : data.getKeys())
- {
- assertTrue(data.getAttribute(name).equals(saved.getAttribute(name)));
- }
--
-+
- return true;
- }
- }
-diff --git a/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java b/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java
-index a7af064..c1c5dc5 100644
---- a/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java
-+++ b/tests/test-webapps/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java
-@@ -1,6 +1,6 @@
- //
- // ========================================================================
--// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
-+// Copyright (c) 1995-2021 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,13 +18,11 @@
-
- package org.eclipse.jetty;
-
--import java.io.File;
- import java.io.IOException;
- import java.lang.management.ManagementFactory;
- import java.nio.file.FileSystems;
- import java.nio.file.Files;
- import java.nio.file.Path;
--
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-@@ -65,11 +63,11 @@ public class TestServer
- ((StdErrLog)Log.getLog()).setSource(false);
-
- // TODO don't depend on this file structure
-- Path jetty_root = FileSystems.getDefault().getPath(".").toAbsolutePath().normalize();
-- if (!Files.exists(jetty_root.resolve("VERSION.txt")))
-- jetty_root = FileSystems.getDefault().getPath("../../..").toAbsolutePath().normalize();
-- if (!Files.exists(jetty_root.resolve("VERSION.txt")))
-- throw new IllegalArgumentException(jetty_root.toString());
-+ Path jettyRoot = FileSystems.getDefault().getPath(".").toAbsolutePath().normalize();
-+ if (!Files.exists(jettyRoot.resolve("VERSION.txt")))
-+ jettyRoot = FileSystems.getDefault().getPath("../../..").toAbsolutePath().normalize();
-+ if (!Files.exists(jettyRoot.resolve("VERSION.txt")))
-+ throw new IllegalArgumentException(jettyRoot.toString());
-
- // Setup Threadpool
- QueuedThreadPool threadPool = new QueuedThreadPool();
-@@ -80,10 +78,9 @@ public class TestServer
- server.manage(threadPool);
-
- // Setup JMX
-- MBeanContainer mbContainer=new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
-+ MBeanContainer mbContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
- server.addBean(mbContainer);
- server.addBean(Log.getLog());
--
-
- // Common HTTP configuration
- HttpConfiguration config = new HttpConfiguration();
-@@ -92,21 +89,19 @@ public class TestServer
- config.addCustomizer(new SecureRequestCustomizer());
- config.setSendDateHeader(true);
- config.setSendServerVersion(true);
--
--
-+
- // Http Connector
- HttpConnectionFactory http = new HttpConnectionFactory(config);
-- ServerConnector httpConnector = new ServerConnector(server,http);
-+ ServerConnector httpConnector = new ServerConnector(server, http);
- httpConnector.setPort(8080);
- httpConnector.setIdleTimeout(30000);
- server.addConnector(httpConnector);
-
--
- // Handlers
- HandlerCollection handlers = new HandlerCollection();
- ContextHandlerCollection contexts = new ContextHandlerCollection();
- handlers.setHandlers(new Handler[]
-- { contexts, new DefaultHandler() });
-+ {contexts, new DefaultHandler()});
-
- // Add restart handler to test the ability to save sessions and restart
- RestartHandler restart = new RestartHandler();
-@@ -114,15 +109,14 @@ public class TestServer
-
- server.setHandler(restart);
-
--
- // Setup context
- HashLoginService login = new HashLoginService();
- login.setName("Test Realm");
-- login.setConfig(jetty_root.resolve("tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/etc/realm.properties").toString());
-+ login.setConfig(jettyRoot.resolve("tests/test-webapps/test-jetty-webapp/src/main/config/demo-base/etc/realm.properties").toString());
- server.addBean(login);
-
-- File log=File.createTempFile("jetty-yyyy_mm_dd", "log");
-- CustomRequestLog requestLog = new CustomRequestLog(log.toString());
-+ Path logPath = Files.createTempFile("jetty-yyyy_mm_dd", "log");
-+ CustomRequestLog requestLog = new CustomRequestLog(logPath.toString());
- server.setRequestLog(requestLog);
-
- server.setStopAtShutdown(true);
-@@ -130,23 +124,19 @@ public class TestServer
- WebAppContext webapp = new WebAppContext();
- webapp.setContextPath("/test");
- webapp.setParentLoaderPriority(true);
-- webapp.setResourceBase(jetty_root.resolve("tests/test-webapps/test-jetty-webapp/src/main/webapp").toString());
-- webapp.setAttribute("testAttribute","testValue");
-- File sessiondir=File.createTempFile("sessions",null);
-- if (sessiondir.exists())
-- sessiondir.delete();
-- sessiondir.mkdir();
-- sessiondir.deleteOnExit();
-+ webapp.setResourceBase(jettyRoot.resolve("tests/test-webapps/test-jetty-webapp/src/main/webapp").toString());
-+ webapp.setAttribute("testAttribute", "testValue");
-+ Path sessionDir = Files.createTempDirectory("sessions");
- DefaultSessionCache ss = new DefaultSessionCache(webapp.getSessionHandler());
- FileSessionDataStore sds = new FileSessionDataStore();
- ss.setSessionDataStore(sds);
-- sds.setStoreDir(sessiondir);
-+ sds.setStoreDir(sessionDir.toFile());
- webapp.getSessionHandler().setSessionCache(ss);
-
- contexts.addHandler(webapp);
-
- ContextHandler srcroot = new ContextHandler();
-- srcroot.setResourceBase(jetty_root.resolve("tests/test-webapps/test-jetty-webapp/src").toString());
-+ srcroot.setResourceBase(jettyRoot.resolve("tests/test-webapps/test-jetty-webapp/src").toString());
- srcroot.setHandler(new ResourceHandler());
- srcroot.setContextPath("/src");
- contexts.addHandler(srcroot);
-@@ -158,17 +148,17 @@ public class TestServer
-
- private static class RestartHandler extends HandlerWrapper
- {
-- /* ------------------------------------------------------------ */
-+
- /**
- * @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
- */
- @Override
- public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
- {
-- super.handle(target,baseRequest,request,response);
-+ super.handle(target, baseRequest, request, response);
- if (Boolean.valueOf(request.getParameter("restart")))
- {
-- final Server server=getServer();
-+ final Server server = getServer();
-
- new Thread()
- {
-@@ -182,7 +172,7 @@ public class TestServer
- Thread.sleep(100);
- server.start();
- }
-- catch(Exception e)
-+ catch (Exception e)
- {
- LOG.warn(e);
- }
diff --git a/CVE-2020-27223.patch b/CVE-2020-27223.patch
deleted file mode 100755
index 7d31ce49eb56789ae332820325ac68e8f54aac83..0000000000000000000000000000000000000000
--- a/CVE-2020-27223.patch
+++ /dev/null
@@ -1,1196 +0,0 @@
-From: Markus Koschany
-Date: Sat, 31 Jul 2021 17:21:57 +0200
-Subject: CVE-2020-27223
-
----
- .../java/org/eclipse/jetty/http/QuotedCSV.java | 280 ++-----------------
- .../org/eclipse/jetty/http/QuotedCSVParser.java | 303 +++++++++++++++++++++
- .../org/eclipse/jetty/http/QuotedQualityCSV.java | 140 ++++++----
- .../eclipse/jetty/http/QuotedQualityCSVTest.java | 143 +++++-----
- 4 files changed, 479 insertions(+), 387 deletions(-)
- create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java
-
-diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java
-index 9ca7dbe..a356213 100644
---- a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java
-+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSV.java
-@@ -1,6 +1,6 @@
- //
- // ========================================================================
--// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
-+// Copyright (c) 1995-2021 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
-@@ -22,236 +22,36 @@ import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
-
--import org.eclipse.jetty.util.QuotedStringTokenizer;
--
--/* ------------------------------------------------------------ */
- /**
- * Implements a quoted comma separated list of values
- * in accordance with RFC7230.
- * OWS is removed and quoted characters ignored for parsing.
-+ *
- * @see "https://tools.ietf.org/html/rfc7230#section-3.2.6"
- * @see "https://tools.ietf.org/html/rfc7230#section-7"
- */
--public class QuotedCSV implements Iterable
--{
-- private enum State { VALUE, PARAM_NAME, PARAM_VALUE};
--
-+public class QuotedCSV extends QuotedCSVParser implements Iterable
-+{
- protected final List _values = new ArrayList<>();
-- protected final boolean _keepQuotes;
--
-- /* ------------------------------------------------------------ */
-+
- public QuotedCSV(String... values)
- {
-- this(true,values);
-+ this(true, values);
- }
--
-- /* ------------------------------------------------------------ */
-- public QuotedCSV(boolean keepQuotes,String... values)
-- {
-- _keepQuotes=keepQuotes;
-- for (String v:values)
-- addValue(v);
-- }
--
-- /* ------------------------------------------------------------ */
-- /** Add and parse a value string(s)
-- * @param value A value that may contain one or more Quoted CSV items.
-- */
-- public void addValue(String value)
-+
-+ public QuotedCSV(boolean keepQuotes, String... values)
- {
-- if (value == null)
-- return;
--
-- StringBuffer buffer = new StringBuffer();
--
-- int l=value.length();
-- State state=State.VALUE;
-- boolean quoted=false;
-- boolean sloshed=false;
-- int nws_length=0;
-- int last_length=0;
-- int value_length=-1;
-- int param_name=-1;
-- int param_value=-1;
--
-- for (int i=0;i<=l;i++)
-+ super(keepQuotes);
-+ for (String v : values)
- {
-- char c=i==l?0:value.charAt(i);
--
-- // Handle quoting https://tools.ietf.org/html/rfc7230#section-3.2.6
-- if (quoted && c!=0)
-- {
-- if (sloshed)
-- sloshed=false;
-- else
-- {
-- switch(c)
-- {
-- case '\\':
-- sloshed=true;
-- if (!_keepQuotes)
-- continue;
-- break;
-- case '"':
-- quoted=false;
-- if (!_keepQuotes)
-- continue;
-- break;
-- }
-- }
--
-- buffer.append(c);
-- nws_length=buffer.length();
-- continue;
-- }
--
-- // Handle common cases
-- switch(c)
-- {
-- case ' ':
-- case '\t':
-- if (buffer.length()>last_length) // not leading OWS
-- buffer.append(c);
-- continue;
--
-- case '"':
-- quoted=true;
-- if (_keepQuotes)
-- {
-- if (state==State.PARAM_VALUE && param_value<0)
-- param_value=nws_length;
-- buffer.append(c);
-- }
-- else if (state==State.PARAM_VALUE && param_value<0)
-- param_value=nws_length;
-- nws_length=buffer.length();
-- continue;
--
-- case ';':
-- buffer.setLength(nws_length); // trim following OWS
-- if (state==State.VALUE)
-- {
-- parsedValue(buffer);
-- value_length=buffer.length();
-- }
-- else
-- parsedParam(buffer,value_length,param_name,param_value);
-- nws_length=buffer.length();
-- param_name=param_value=-1;
-- buffer.append(c);
-- last_length=++nws_length;
-- state=State.PARAM_NAME;
-- continue;
--
-- case ',':
-- case 0:
-- if (nws_length>0)
-- {
-- buffer.setLength(nws_length); // trim following OWS
-- switch(state)
-- {
-- case VALUE:
-- parsedValue(buffer);
-- value_length=buffer.length();
-- break;
-- case PARAM_NAME:
-- case PARAM_VALUE:
-- parsedParam(buffer,value_length,param_name,param_value);
-- break;
-- }
-- _values.add(buffer.toString());
-- }
-- buffer.setLength(0);
-- last_length=0;
-- nws_length=0;
-- value_length=param_name=param_value=-1;
-- state=State.VALUE;
-- continue;
--
-- case '=':
-- switch (state)
-- {
-- case VALUE:
-- // It wasn't really a value, it was a param name
-- value_length=param_name=0;
-- buffer.setLength(nws_length); // trim following OWS
-- String param = buffer.toString();
-- buffer.setLength(0);
-- parsedValue(buffer);
-- value_length=buffer.length();
-- buffer.append(param);
-- buffer.append(c);
-- last_length=++nws_length;
-- state=State.PARAM_VALUE;
-- continue;
--
-- case PARAM_NAME:
-- buffer.setLength(nws_length); // trim following OWS
-- buffer.append(c);
-- last_length=++nws_length;
-- state=State.PARAM_VALUE;
-- continue;
--
-- case PARAM_VALUE:
-- if (param_value<0)
-- param_value=nws_length;
-- buffer.append(c);
-- nws_length=buffer.length();
-- continue;
-- }
-- continue;
--
-- default:
-- {
-- switch (state)
-- {
-- case VALUE:
-- {
-- buffer.append(c);
-- nws_length=buffer.length();
-- continue;
-- }
--
-- case PARAM_NAME:
-- {
-- if (param_name<0)
-- param_name=nws_length;
-- buffer.append(c);
-- nws_length=buffer.length();
-- continue;
-- }
--
-- case PARAM_VALUE:
-- {
-- if (param_value<0)
-- param_value=nws_length;
-- buffer.append(c);
-- nws_length=buffer.length();
-- continue;
-- }
-- }
-- }
-- }
-+ addValue(v);
- }
- }
-
-- /**
-- * Called when a value has been parsed
-- * @param buffer Containing the trimmed value, which may be mutated
-- */
-- protected void parsedValue(StringBuffer buffer)
-- {
-- }
--
-- /**
-- * Called when a parameter has been parsed
-- * @param buffer Containing the trimmed value and all parameters, which may be mutated
-- * @param valueLength The length of the value
-- * @param paramName The index of the start of the parameter just parsed
-- * @param paramValue The index of the start of the parameter value just parsed, or -1
-- */
-- protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
-+ @Override
-+ protected void parsedValueAndParams(StringBuffer buffer)
- {
-+ _values.add(buffer.toString());
- }
-
- public int size()
-@@ -268,67 +68,21 @@ public class QuotedCSV implements Iterable
- {
- return _values;
- }
--
-+
- @Override
- public Iterator iterator()
- {
- return _values.iterator();
- }
--
-- public static String unquote(String s)
-- {
-- // handle trivial cases
-- int l=s.length();
-- if (s==null || l==0)
-- return s;
--
-- // Look for any quotes
-- int i=0;
-- for (;i list = new ArrayList<>();
- for (String s : this)
-+ {
- list.add(s);
-+ }
- return list.toString();
- }
- }
-diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java
-new file mode 100644
-index 0000000..7aefcf7
---- /dev/null
-+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java
-@@ -0,0 +1,303 @@
-+//
-+// ========================================================================
-+// Copyright (c) 1995-2021 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
-+// and Apache License v2.0 which accompanies this distribution.
-+//
-+// The Eclipse Public License is available at
-+// http://www.eclipse.org/legal/epl-v10.html
-+//
-+// The Apache License v2.0 is available at
-+// http://www.opensource.org/licenses/apache2.0.php
-+//
-+// You may elect to redistribute this code under either of these licenses.
-+// ========================================================================
-+//
-+
-+package org.eclipse.jetty.http;
-+
-+/**
-+ * Implements a quoted comma separated list parser
-+ * in accordance with RFC7230.
-+ * OWS is removed and quoted characters ignored for parsing.
-+ *
-+ * @see "https://tools.ietf.org/html/rfc7230#section-3.2.6"
-+ * @see "https://tools.ietf.org/html/rfc7230#section-7"
-+ */
-+public abstract class QuotedCSVParser
-+{
-+ private enum State
-+ {
-+ VALUE, PARAM_NAME, PARAM_VALUE
-+ }
-+
-+ protected final boolean _keepQuotes;
-+
-+ public QuotedCSVParser(boolean keepQuotes)
-+ {
-+ _keepQuotes = keepQuotes;
-+ }
-+
-+ public static String unquote(String s)
-+ {
-+ // handle trivial cases
-+ int l = s.length();
-+ if (s == null || l == 0)
-+ return s;
-+
-+ // Look for any quotes
-+ int i = 0;
-+ for (; i < l; i++)
-+ {
-+ char c = s.charAt(i);
-+ if (c == '"')
-+ break;
-+ }
-+ if (i == l)
-+ return s;
-+
-+ boolean quoted = true;
-+ boolean sloshed = false;
-+ StringBuffer buffer = new StringBuffer();
-+ buffer.append(s, 0, i);
-+ i++;
-+ for (; i < l; i++)
-+ {
-+ char c = s.charAt(i);
-+ if (quoted)
-+ {
-+ if (sloshed)
-+ {
-+ buffer.append(c);
-+ sloshed = false;
-+ }
-+ else if (c == '"')
-+ quoted = false;
-+ else if (c == '\\')
-+ sloshed = true;
-+ else
-+ buffer.append(c);
-+ }
-+ else if (c == '"')
-+ quoted = true;
-+ else
-+ buffer.append(c);
-+ }
-+ return buffer.toString();
-+ }
-+
-+ /**
-+ * Add and parse a value string(s)
-+ *
-+ * @param value A value that may contain one or more Quoted CSV items.
-+ */
-+ public void addValue(String value)
-+ {
-+ if (value == null)
-+ return;
-+
-+ StringBuffer buffer = new StringBuffer();
-+
-+ int l = value.length();
-+ State state = State.VALUE;
-+ boolean quoted = false;
-+ boolean sloshed = false;
-+ int nwsLength = 0;
-+ int lastLength = 0;
-+ int valueLength = -1;
-+ int paramName = -1;
-+ int paramValue = -1;
-+
-+ for (int i = 0; i <= l; i++)
-+ {
-+ char c = i == l ? 0 : value.charAt(i);
-+
-+ // Handle quoting https://tools.ietf.org/html/rfc7230#section-3.2.6
-+ if (quoted && c != 0)
-+ {
-+ if (sloshed)
-+ sloshed = false;
-+ else
-+ {
-+ switch (c)
-+ {
-+ case '\\':
-+ sloshed = true;
-+ if (!_keepQuotes)
-+ continue;
-+ break;
-+ case '"':
-+ quoted = false;
-+ if (!_keepQuotes)
-+ continue;
-+ break;
-+ }
-+ }
-+
-+ buffer.append(c);
-+ nwsLength = buffer.length();
-+ continue;
-+ }
-+
-+ // Handle common cases
-+ switch (c)
-+ {
-+ case ' ':
-+ case '\t':
-+ if (buffer.length() > lastLength) // not leading OWS
-+ buffer.append(c);
-+ continue;
-+
-+ case '"':
-+ quoted = true;
-+ if (_keepQuotes)
-+ {
-+ if (state == State.PARAM_VALUE && paramValue < 0)
-+ paramValue = nwsLength;
-+ buffer.append(c);
-+ }
-+ else if (state == State.PARAM_VALUE && paramValue < 0)
-+ paramValue = nwsLength;
-+ nwsLength = buffer.length();
-+ continue;
-+
-+ case ';':
-+ buffer.setLength(nwsLength); // trim following OWS
-+ if (state == State.VALUE)
-+ {
-+ parsedValue(buffer);
-+ valueLength = buffer.length();
-+ }
-+ else
-+ parsedParam(buffer, valueLength, paramName, paramValue);
-+ nwsLength = buffer.length();
-+ paramName = paramValue = -1;
-+ buffer.append(c);
-+ lastLength = ++nwsLength;
-+ state = State.PARAM_NAME;
-+ continue;
-+
-+ case ',':
-+ case 0:
-+ if (nwsLength > 0)
-+ {
-+ buffer.setLength(nwsLength); // trim following OWS
-+ switch (state)
-+ {
-+ case VALUE:
-+ parsedValue(buffer);
-+ valueLength = buffer.length();
-+ break;
-+ case PARAM_NAME:
-+ case PARAM_VALUE:
-+ parsedParam(buffer, valueLength, paramName, paramValue);
-+ break;
-+ }
-+ parsedValueAndParams(buffer);
-+ }
-+ buffer.setLength(0);
-+ lastLength = 0;
-+ nwsLength = 0;
-+ valueLength = paramName = paramValue = -1;
-+ state = State.VALUE;
-+ continue;
-+
-+ case '=':
-+ switch (state)
-+ {
-+ case VALUE:
-+ // It wasn't really a value, it was a param name
-+ valueLength = paramName = 0;
-+ buffer.setLength(nwsLength); // trim following OWS
-+ String param = buffer.toString();
-+ buffer.setLength(0);
-+ parsedValue(buffer);
-+ valueLength = buffer.length();
-+ buffer.append(param);
-+ buffer.append(c);
-+ lastLength = ++nwsLength;
-+ state = State.PARAM_VALUE;
-+ continue;
-+
-+ case PARAM_NAME:
-+ buffer.setLength(nwsLength); // trim following OWS
-+ buffer.append(c);
-+ lastLength = ++nwsLength;
-+ state = State.PARAM_VALUE;
-+ continue;
-+
-+ case PARAM_VALUE:
-+ if (paramValue < 0)
-+ paramValue = nwsLength;
-+ buffer.append(c);
-+ nwsLength = buffer.length();
-+ continue;
-+ }
-+ continue;
-+
-+ default:
-+ {
-+ switch (state)
-+ {
-+ case VALUE:
-+ {
-+ buffer.append(c);
-+ nwsLength = buffer.length();
-+ continue;
-+ }
-+
-+ case PARAM_NAME:
-+ {
-+ if (paramName < 0)
-+ paramName = nwsLength;
-+ buffer.append(c);
-+ nwsLength = buffer.length();
-+ continue;
-+ }
-+
-+ case PARAM_VALUE:
-+ {
-+ if (paramValue < 0)
-+ paramValue = nwsLength;
-+ buffer.append(c);
-+ nwsLength = buffer.length();
-+ continue;
-+ }
-+ }
-+ }
-+ }
-+ }
-+ }
-+
-+ /**
-+ * Called when a value and it's parameters has been parsed
-+ *
-+ * @param buffer Containing the trimmed value and parameters
-+ */
-+ protected void parsedValueAndParams(StringBuffer buffer)
-+ {
-+ }
-+
-+ /**
-+ * Called when a value has been parsed (prior to any parameters)
-+ *
-+ * @param buffer Containing the trimmed value, which may be mutated
-+ */
-+ protected void parsedValue(StringBuffer buffer)
-+ {
-+ }
-+
-+ /**
-+ * Called when a parameter has been parsed
-+ *
-+ * @param buffer Containing the trimmed value and all parameters, which may be mutated
-+ * @param valueLength The length of the value
-+ * @param paramName The index of the start of the parameter just parsed
-+ * @param paramValue The index of the start of the parameter value just parsed, or -1
-+ */
-+ protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
-+ {
-+ }
-+}
-diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
-index d148d9e..5bc9985 100644
---- a/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
-+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java
-@@ -1,6 +1,6 @@
- //
- // ========================================================================
--// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
-+// Copyright (c) 1995-2021 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
-@@ -21,14 +21,12 @@ package org.eclipse.jetty.http;
- import java.util.ArrayList;
- import java.util.Iterator;
- import java.util.List;
-+import java.util.Objects;
- import java.util.function.ToIntFunction;
-+import java.util.stream.Collectors;
-
- import org.eclipse.jetty.util.log.Log;
-
--import static java.lang.Integer.MIN_VALUE;
--
--/* ------------------------------------------------------------ */
--
- /**
- * Implements a quoted comma separated list of quality values
- * in accordance with RFC7230 and RFC7231.
-@@ -57,22 +55,19 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable
- return 3;
- };
-
-- private final List _quality = new ArrayList<>();
-+ private final List _qualities = new ArrayList<>();
-+ private QualityValue _lastQuality;
- private boolean _sorted = false;
- private final ToIntFunction _secondaryOrdering;
-
-- /* ------------------------------------------------------------ */
--
- /**
- * Sorts values with equal quality according to the length of the value String.
- */
- public QuotedQualityCSV()
- {
-- this((ToIntFunction)null);
-+ this((ToIntFunction)null);
- }
-
-- /* ------------------------------------------------------------ */
--
- /**
- * Sorts values with equal quality according to given order.
- *
-@@ -83,57 +78,71 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable
- this((s) ->
- {
- for (int i = 0; i < preferredOrder.length; ++i)
-+ {
- if (preferredOrder[i].equals(s))
- return preferredOrder.length - i;
-+ }
-
- if ("*".equals(s))
- return preferredOrder.length;
-
-- return MIN_VALUE;
-+ return 0;
- });
- }
-
-- /* ------------------------------------------------------------ */
--
- /**
- * Orders values with equal quality with the given function.
- *
-- * @param secondaryOrdering Function to apply an ordering other than specified by quality
-+ * @param secondaryOrdering Function to apply an ordering other than specified by quality, highest values are sorted first.
- */
- public QuotedQualityCSV(ToIntFunction secondaryOrdering)
- {
- this._secondaryOrdering = secondaryOrdering == null ? s -> 0 : secondaryOrdering;
- }
-
-- /* ------------------------------------------------------------ */
-+ @Override
-+ protected void parsedValueAndParams(StringBuffer buffer)
-+ {
-+ super.parsedValueAndParams(buffer);
-+
-+ // Collect full value with parameters
-+ _lastQuality = new QualityValue(_lastQuality._quality, buffer.toString(), _lastQuality._index);
-+ _qualities.set(_lastQuality._index, _lastQuality);
-+ }
-+
- @Override
- protected void parsedValue(StringBuffer buffer)
- {
- super.parsedValue(buffer);
-
-+ _sorted = false;
-+
-+ // This is the just the value, without parameters.
- // Assume a quality of ONE
-- _quality.add(1.0D);
-+ _lastQuality = new QualityValue(1.0D, buffer.toString(), _qualities.size());
-+ _qualities.add(_lastQuality);
- }
-
-- /* ------------------------------------------------------------ */
- @Override
- protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
- {
-+ _sorted = false;
-+
- if (paramName < 0)
- {
- if (buffer.charAt(buffer.length() - 1) == ';')
- buffer.setLength(buffer.length() - 1);
- }
- else if (paramValue >= 0 &&
-- buffer.charAt(paramName) == 'q' && paramValue > paramName &&
-- buffer.length() >= paramName && buffer.charAt(paramName + 1) == '=')
-+ buffer.charAt(paramName) == 'q' && paramValue > paramName &&
-+ buffer.length() >= paramName && buffer.charAt(paramName + 1) == '=')
- {
-- Double q;
-+ double q;
- try
- {
- q = (_keepQuotes && buffer.charAt(paramValue) == '"')
-- ? Double.valueOf(buffer.substring(paramValue + 1, buffer.length() - 1))
-- : Double.valueOf(buffer.substring(paramValue));
-+ ? Double.valueOf(buffer.substring(paramValue + 1, buffer.length() - 1))
-+ : Double.valueOf(buffer.substring(paramValue));
- }
- catch (Exception e)
- {
-@@ -143,8 +152,10 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable
- buffer.setLength(Math.max(0, paramName - 1));
-
- if (q != 1.0D)
-- // replace assumed quality
-- _quality.set(_quality.size() - 1, q);
-+ {
-+ _lastQuality = new QualityValue(q, buffer.toString(), _lastQuality._index);
-+ _qualities.set(_lastQuality._index, _lastQuality);
-+ }
- }
- }
-
-@@ -166,38 +177,73 @@ public class QuotedQualityCSV extends QuotedCSV implements Iterable
-
- protected void sort()
- {
-+ _values.clear();
-+ _qualities.stream()
-+ .filter((qv) -> qv._quality != 0.0D)
-+ .sorted()
-+ .map(QualityValue::getValue)
-+ .collect(Collectors.toCollection(() -> _values));
- _sorted = true;
-+ }
-+
-+ private class QualityValue implements Comparable
-+ {
-+ private final double _quality;
-+ private final String _value;
-+ private final int _index;
-
-- Double last = 0.0D;
-- int lastSecondaryOrder = Integer.MIN_VALUE;
-+ private QualityValue(double quality, String value, int index)
-+ {
-+ _quality = quality;
-+ _value = value;
-+ _index = index;
-+ }
-
-- for (int i = _values.size(); i-- > 0; )
-+ @Override
-+ public int hashCode()
- {
-- String v = _values.get(i);
-- Double q = _quality.get(i);
-+ return Double.hashCode(_quality) ^ Objects.hash(_value, _index);
-+ }
-
-- int compare = last.compareTo(q);
-- if (compare > 0 || (compare == 0 && _secondaryOrdering.applyAsInt(v) < lastSecondaryOrder))
-+ @Override
-+ public boolean equals(Object obj)
-+ {
-+ if (!(obj instanceof QualityValue))
-+ return false;
-+ QualityValue qv = (QualityValue)obj;
-+ return _quality == qv._quality && Objects.equals(_value, qv._value) && Objects.equals(_index, qv._index);
-+ }
-+
-+ private String getValue()
-+ {
-+ return _value;
-+ }
-+
-+ @Override
-+ public int compareTo(QualityValue o)
-+ {
-+ // sort highest quality first
-+ int compare = Double.compare(o._quality, _quality);
-+ if (compare == 0)
- {
-- _values.set(i, _values.get(i + 1));
-- _values.set(i + 1, v);
-- _quality.set(i, _quality.get(i + 1));
-- _quality.set(i + 1, q);
-- last = 0.0D;
-- lastSecondaryOrder = 0;
-- i = _values.size();
-- continue;
-+ // then sort secondary order highest first
-+ compare = Integer.compare(_secondaryOrdering.applyAsInt(o._value), _secondaryOrdering.applyAsInt(_value));
-+ if (compare == 0)
-+ // then sort index lowest first
-+ compare = -Integer.compare(o._index, _index);
- }
--
-- last = q;
-- lastSecondaryOrder = _secondaryOrdering.applyAsInt(v);
-+ return compare;
- }
-
-- int last_element = _quality.size();
-- while (last_element > 0 && _quality.get(--last_element).equals(0.0D))
-+ @Override
-+ public String toString()
- {
-- _quality.remove(last_element);
-- _values.remove(last_element);
-+ return String.format("%s@%x[%s,q=%f,i=%d]",
-+ getClass().getSimpleName(),
-+ hashCode(),
-+ _value,
-+ _quality,
-+ _index);
- }
- }
- }
-diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedQualityCSVTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedQualityCSVTest.java
-index f03657b..b941e95 100644
---- a/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedQualityCSVTest.java
-+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/QuotedQualityCSVTest.java
-@@ -1,6 +1,6 @@
- //
- // ========================================================================
--// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
-+// Copyright (c) 1995-2021 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,13 +18,12 @@
-
- package org.eclipse.jetty.http;
-
-+import java.util.ArrayList;
-+import java.util.List;
-
- import org.hamcrest.Matchers;
- import org.junit.jupiter.api.Test;
-
--import java.util.ArrayList;
--import java.util.List;
--
- import static org.hamcrest.MatcherAssert.assertThat;
- import static org.hamcrest.Matchers.contains;
-
-@@ -32,58 +31,58 @@ public class QuotedQualityCSVTest
- {
-
- @Test
-- public void test7231_5_3_2_example1()
-+ public void test7231Sec532Example1()
- {
- QuotedQualityCSV values = new QuotedQualityCSV();
- values.addValue(" audio/*; q=0.2, audio/basic");
-- assertThat(values,Matchers.contains("audio/basic","audio/*"));
-+ assertThat(values, Matchers.contains("audio/basic", "audio/*"));
- }
-
- @Test
-- public void test7231_5_3_2_example2()
-+ public void test7231Sec532Example2()
- {
- QuotedQualityCSV values = new QuotedQualityCSV();
- values.addValue("text/plain; q=0.5, text/html,");
- values.addValue("text/x-dvi; q=0.8, text/x-c");
-- assertThat(values,Matchers.contains("text/html","text/x-c","text/x-dvi","text/plain"));
-+ assertThat(values, Matchers.contains("text/html", "text/x-c", "text/x-dvi", "text/plain"));
- }
--
-+
- @Test
-- public void test7231_5_3_2_example3()
-+ public void test7231Sec532Example3()
- {
- QuotedQualityCSV values = new QuotedQualityCSV();
- values.addValue("text/*, text/plain, text/plain;format=flowed, */*");
--
-+
- // Note this sort is only on quality and not the most specific type as per 5.3.2
-- assertThat(values,Matchers.contains("text/*","text/plain","text/plain;format=flowed","*/*"));
-+ assertThat(values, Matchers.contains("text/*", "text/plain", "text/plain;format=flowed", "*/*"));
- }
--
-+
- @Test
-- public void test7231_5_3_2_example3_most_specific()
-+ public void test7231532Example3MostSpecific()
- {
- QuotedQualityCSV values = new QuotedQualityCSV(QuotedQualityCSV.MOST_SPECIFIC_MIME_ORDERING);
- values.addValue("text/*, text/plain, text/plain;format=flowed, */*");
--
-- assertThat(values,Matchers.contains("text/plain;format=flowed","text/plain","text/*","*/*"));
-+
-+ assertThat(values, Matchers.contains("text/plain;format=flowed", "text/plain", "text/*", "*/*"));
- }
--
-+
- @Test
-- public void test7231_5_3_2_example4()
-+ public void test7231Sec532Example4()
- {
- QuotedQualityCSV values = new QuotedQualityCSV();
- values.addValue("text/*;q=0.3, text/html;q=0.7, text/html;level=1,");
- values.addValue("text/html;level=2;q=0.4, */*;q=0.5");
-- assertThat(values,Matchers.contains(
-- "text/html;level=1",
-- "text/html",
-- "*/*",
-- "text/html;level=2",
-- "text/*"
-- ));
-+ assertThat(values, Matchers.contains(
-+ "text/html;level=1",
-+ "text/html",
-+ "*/*",
-+ "text/html;level=2",
-+ "text/*"
-+ ));
- }
--
-+
- @Test
-- public void test7231_5_3_4_example1()
-+ public void test7231Sec534Example1()
- {
- QuotedQualityCSV values = new QuotedQualityCSV();
- values.addValue("compress, gzip");
-@@ -91,16 +90,16 @@ public class QuotedQualityCSVTest
- values.addValue("*");
- values.addValue("compress;q=0.5, gzip;q=1.0");
- values.addValue("gzip;q=1.0, identity; q=0.5, *;q=0");
--
-- assertThat(values,Matchers.contains(
-- "compress",
-- "gzip",
-- "*",
-- "gzip",
-- "gzip",
-- "compress",
-- "identity"
-- ));
-+
-+ assertThat(values, Matchers.contains(
-+ "compress",
-+ "gzip",
-+ "*",
-+ "gzip",
-+ "gzip",
-+ "compress",
-+ "identity"
-+ ));
- }
-
- @Test
-@@ -108,66 +107,65 @@ public class QuotedQualityCSVTest
- {
- QuotedQualityCSV values = new QuotedQualityCSV();
- values.addValue(" value 0.5 ; p = v ; q =0.5 , value 1.0 ");
-- assertThat(values,Matchers.contains(
-- "value 1.0",
-- "value 0.5;p=v"));
-+ assertThat(values, Matchers.contains(
-+ "value 1.0",
-+ "value 0.5;p=v"));
- }
--
-+
- @Test
- public void testEmpty()
- {
- QuotedQualityCSV values = new QuotedQualityCSV();
- values.addValue(",aaaa, , bbbb ,,cccc,");
-- assertThat(values,Matchers.contains(
-- "aaaa",
-- "bbbb",
-- "cccc"));
-+ assertThat(values, Matchers.contains(
-+ "aaaa",
-+ "bbbb",
-+ "cccc"));
- }
--
-+
- @Test
- public void testQuoted()
- {
- QuotedQualityCSV values = new QuotedQualityCSV();
- values.addValue(" value 0.5 ; p = \"v ; q = \\\"0.5\\\" , value 1.0 \" ");
-- assertThat(values,Matchers.contains(
-- "value 0.5;p=\"v ; q = \\\"0.5\\\" , value 1.0 \""));
-+ assertThat(values, Matchers.contains(
-+ "value 0.5;p=\"v ; q = \\\"0.5\\\" , value 1.0 \""));
- }
--
-+
- @Test
- public void testOpenQuote()
- {
- QuotedQualityCSV values = new QuotedQualityCSV();
- values.addValue("value;p=\"v");
-- assertThat(values,Matchers.contains(
-- "value;p=\"v"));
-+ assertThat(values, Matchers.contains(
-+ "value;p=\"v"));
- }
--
-+
- @Test
- public void testQuotedQuality()
- {
- QuotedQualityCSV values = new QuotedQualityCSV();
- values.addValue(" value 0.5 ; p = v ; q = \"0.5\" , value 1.0 ");
-- assertThat(values,Matchers.contains(
-- "value 1.0",
-- "value 0.5;p=v"));
-+ assertThat(values, Matchers.contains(
-+ "value 1.0",
-+ "value 0.5;p=v"));
- }
--
-+
- @Test
- public void testBadQuality()
- {
- QuotedQualityCSV values = new QuotedQualityCSV();
- values.addValue("value0.5;p=v;q=0.5,value1.0,valueBad;q=X");
-- assertThat(values,Matchers.contains(
-- "value1.0",
-- "value0.5;p=v"));
-+ assertThat(values, Matchers.contains(
-+ "value1.0",
-+ "value0.5;p=v"));
- }
--
-+
- @Test
- public void testBad()
- {
- QuotedQualityCSV values = new QuotedQualityCSV();
-
--
- // None of these should throw exceptions
- values.addValue(null);
- values.addValue("");
-@@ -223,13 +221,10 @@ public class QuotedQualityCSVTest
- values.addValue("q=");
- values.addValue("q=,");
- values.addValue("q=;");
--
- }
-
-- /* ------------------------------------------------------------ */
--
-- private static final String[] preferBrotli = {"br","gzip"};
-- private static final String[] preferGzip = {"gzip","br"};
-+ private static final String[] preferBrotli = {"br", "gzip"};
-+ private static final String[] preferGzip = {"gzip", "br"};
- private static final String[] noFormats = {};
-
- @Test
-@@ -295,14 +290,13 @@ public class QuotedQualityCSVTest
- values.addValue("gzip, *");
- assertThat(values, contains("*", "gzip"));
- }
--
-
- @Test
- public void testSameQuality()
- {
- QuotedQualityCSV values = new QuotedQualityCSV();
- values.addValue("one;q=0.5,two;q=0.5,three;q=0.5");
-- assertThat(values.getValues(),Matchers.contains("one","two","three"));
-+ assertThat(values.getValues(), Matchers.contains("one", "two", "three"));
- }
-
- @Test
-@@ -310,10 +304,9 @@ public class QuotedQualityCSVTest
- {
- QuotedQualityCSV values = new QuotedQualityCSV();
- values.addValue("one,two;,three;x=y");
-- assertThat(values.getValues(),Matchers.contains("one","two","three;x=y"));
-+ assertThat(values.getValues(), Matchers.contains("one", "two", "three;x=y"));
- }
-
--
- @Test
- public void testQuality()
- {
-@@ -339,19 +332,15 @@ public class QuotedQualityCSVTest
- }
- };
-
--
- // The provided string is not legal according to some RFCs ( not a token because of = and not a parameter because not preceded by ; )
- // The string is legal according to RFC7239 which allows for just parameters (called forwarded-pairs)
- values.addValue("p=0.5,q=0.5");
-
--
- // The QuotedCSV implementation is lenient and adopts the later interpretation and thus sees q=0.5 and p=0.5 both as parameters
-- assertThat(results,contains("parsedValue: ", "parsedParam: p=0.5",
-- "parsedValue: ", "parsedParam: q=0.5"));
--
-+ assertThat(results, contains("parsedValue: ", "parsedParam: p=0.5",
-+ "parsedValue: ", "parsedParam: q=0.5"));
-
- // However the QuotedQualityCSV only handles the q parameter and that is consumed from the parameter string.
-- assertThat(values,contains("p=0.5", ""));
--
-+ assertThat(values, contains("p=0.5", ""));
- }
- }
diff --git a/CVE-2021-28165.patch b/CVE-2021-28165.patch
deleted file mode 100755
index 5d1f6a9cdaa8aa31af0c621a062c0093b5e2d502..0000000000000000000000000000000000000000
--- a/CVE-2021-28165.patch
+++ /dev/null
@@ -1,533 +0,0 @@
-From: Markus Koschany
-Date: Sat, 31 Jul 2021 17:24:07 +0200
-Subject: CVE-2021-28165
-
----
- .../org/eclipse/jetty/io/ssl/SslConnection.java | 12 +
- .../eclipse/jetty/server/ssl/SSLEngineTest.java | 267 +++++++++++++--------
- 2 files changed, 183 insertions(+), 96 deletions(-)
-
-diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java
-index a2c1fdc..c385f27 100644
---- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java
-+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java
-@@ -330,6 +330,11 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
- _decryptedEndPoint.onFillableFail(cause == null ? new IOException() : cause);
- }
-
-+ protected SSLEngineResult unwrap(SSLEngine sslEngine, ByteBuffer input, ByteBuffer output) throws SSLException
-+ {
-+ return sslEngine.unwrap(input, output);
-+ }
-+
- @Override
- public String toConnectionString()
- {
-@@ -602,8 +607,15 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
- return filled = -1;
-
- case BUFFER_UNDERFLOW:
-+ if (BufferUtil.space(_encryptedInput) == 0)
-+ {
-+ BufferUtil.clear(_encryptedInput);
-+ throw new SSLHandshakeException("Encrypted buffer max length exceeded");
-+ }
-+
- if (net_filled > 0)
- continue; // try filling some more
-+
- _underflown = true;
- if (net_filled < 0 && _sslEngine.getUseClientMode())
- {
-diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLEngineTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLEngineTest.java
-index ae6a5b6..aa1b9c9 100644
---- a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLEngineTest.java
-+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLEngineTest.java
-@@ -1,6 +1,6 @@
- //
- // ========================================================================
--// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
-+// Copyright (c) 1995-2021 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
-@@ -34,20 +34,31 @@ import java.net.Socket;
- import java.net.SocketException;
- import java.net.SocketTimeoutException;
- import java.net.URL;
--
-+import java.nio.ByteBuffer;
-+import java.util.Arrays;
-+import java.util.concurrent.atomic.AtomicLong;
-+import javax.net.SocketFactory;
- import javax.net.ssl.HostnameVerifier;
- import javax.net.ssl.HttpsURLConnection;
- import javax.net.ssl.SSLContext;
-+import javax.net.ssl.SSLEngine;
-+import javax.net.ssl.SSLEngineResult;
-+import javax.net.ssl.SSLException;
- import javax.net.ssl.SSLSession;
- import javax.servlet.ServletException;
- import javax.servlet.ServletOutputStream;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
-+import org.eclipse.jetty.io.EndPoint;
-+import org.eclipse.jetty.io.ssl.SslConnection;
-+import org.eclipse.jetty.server.ConnectionFactory;
-+import org.eclipse.jetty.server.Connector;
- import org.eclipse.jetty.server.HttpConnectionFactory;
- import org.eclipse.jetty.server.Request;
- import org.eclipse.jetty.server.Server;
- import org.eclipse.jetty.server.ServerConnector;
-+import org.eclipse.jetty.server.SslConnectionFactory;
- import org.eclipse.jetty.server.handler.AbstractHandler;
- import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
- import org.eclipse.jetty.util.IO;
-@@ -60,6 +71,7 @@ import org.junit.jupiter.api.Test;
- import static org.hamcrest.MatcherAssert.assertThat;
- import static org.hamcrest.Matchers.greaterThan;
- import static org.hamcrest.Matchers.is;
-+import static org.hamcrest.Matchers.lessThan;
- import static org.junit.jupiter.api.Assertions.assertEquals;
- import static org.junit.jupiter.api.Assertions.assertNotNull;
-
-@@ -69,41 +81,45 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
- public class SSLEngineTest
- {
- // Useful constants
-- private static final String HELLO_WORLD="Hello world. The quick brown fox jumped over the lazy dog. How now brown cow. The rain in spain falls mainly on the plain.\n";
-- private static final String JETTY_VERSION= Server.getVersion();
-- private static final String PROTOCOL_VERSION="2.0";
--
-- /** The request. */
-- private static final String REQUEST0_HEADER="POST /r0 HTTP/1.1\n"+"Host: localhost\n"+"Content-Type: text/xml\n"+"Content-Length: ";
-- private static final String REQUEST1_HEADER="POST /r1 HTTP/1.1\n"+"Host: localhost\n"+"Content-Type: text/xml\n"+"Connection: close\n"+"Content-Length: ";
-- private static final String REQUEST_CONTENT=
-- "\n"+
-- "\n"+
-- "";
--
-- private static final String REQUEST0=REQUEST0_HEADER+REQUEST_CONTENT.getBytes().length+"\n\n"+REQUEST_CONTENT;
-- private static final String REQUEST1=REQUEST1_HEADER+REQUEST_CONTENT.getBytes().length+"\n\n"+REQUEST_CONTENT;
--
-- /** The expected response. */
-- private static final String RESPONSE0="HTTP/1.1 200 OK\n"+
-- "Content-Length: "+HELLO_WORLD.length()+"\n"+
-- "Server: Jetty("+JETTY_VERSION+")\n"+
-- '\n'+
-+ private static final String HELLO_WORLD = "Hello world. The quick brown fox jumped over the lazy dog. How now brown cow. The rain in spain falls mainly on the plain.\n";
-+ private static final String JETTY_VERSION = Server.getVersion();
-+ private static final String PROTOCOL_VERSION = "2.0";
-+
-+ /**
-+ * The request.
-+ */
-+ private static final String REQUEST0_HEADER = "POST /r0 HTTP/1.1\n" + "Host: localhost\n" + "Content-Type: text/xml\n" + "Content-Length: ";
-+ private static final String REQUEST1_HEADER = "POST /r1 HTTP/1.1\n" + "Host: localhost\n" + "Content-Type: text/xml\n" + "Connection: close\n" + "Content-Length: ";
-+ private static final String REQUEST_CONTENT =
-+ "\n" +
-+ "\n" +
-+ "";
-+
-+ private static final String REQUEST0 = REQUEST0_HEADER + REQUEST_CONTENT.getBytes().length + "\n\n" + REQUEST_CONTENT;
-+ private static final String REQUEST1 = REQUEST1_HEADER + REQUEST_CONTENT.getBytes().length + "\n\n" + REQUEST_CONTENT;
-+
-+ /**
-+ * The expected response.
-+ */
-+ private static final String RESPONSE0 = "HTTP/1.1 200 OK\n" +
-+ "Content-Length: " + HELLO_WORLD.length() + "\n" +
-+ "Server: Jetty(" + JETTY_VERSION + ")\n" +
-+ '\n' +
- HELLO_WORLD;
--
-- private static final String RESPONSE1="HTTP/1.1 200 OK\n"+
-- "Connection: close\n"+
-- "Content-Length: "+HELLO_WORLD.length()+"\n"+
-- "Server: Jetty("+JETTY_VERSION+")\n"+
-- '\n'+
-+
-+ private static final String RESPONSE1 = "HTTP/1.1 200 OK\n" +
-+ "Connection: close\n" +
-+ "Content-Length: " + HELLO_WORLD.length() + "\n" +
-+ "Server: Jetty(" + JETTY_VERSION + ")\n" +
-+ '\n' +
- HELLO_WORLD;
-
-- private static final int BODY_SIZE=300;
-+ private static final int BODY_SIZE = 300;
-
- private Server server;
- private ServerConnector connector;
--
-+ private SslContextFactory sslContextFactory;
-
- @BeforeEach
- public void startServer() throws Exception
-@@ -114,11 +130,11 @@ public class SSLEngineTest
- sslContextFactory.setKeyStorePassword("storepwd");
- sslContextFactory.setKeyManagerPassword("keypwd");
-
-- server=new Server();
-+ server = new Server();
- HttpConnectionFactory http = new HttpConnectionFactory();
- http.setInputBufferSize(512);
- http.getHttpConfiguration().setRequestHeaderSize(512);
-- connector=new ServerConnector(server, sslContextFactory, http);
-+ connector = new ServerConnector(server, sslContextFactory, http);
- connector.setPort(0);
- connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration().setSendDateHeader(false);
-
-@@ -138,19 +154,19 @@ public class SSLEngineTest
- server.setHandler(new HelloWorldHandler());
- server.start();
-
-- SSLContext ctx=SSLContext.getInstance("TLS");
-- ctx.init(null,SslContextFactory.TRUST_ALL_CERTS,new java.security.SecureRandom());
-+ SSLContext ctx = SSLContext.getInstance("TLS");
-+ ctx.init(null, SslContextFactory.TRUST_ALL_CERTS, new java.security.SecureRandom());
-
-- int port=connector.getLocalPort();
-+ int port = connector.getLocalPort();
-
-- Socket client=ctx.getSocketFactory().createSocket("localhost",port);
-- OutputStream os=client.getOutputStream();
-+ Socket client = ctx.getSocketFactory().createSocket("localhost", port);
-+ OutputStream os = client.getOutputStream();
-
- String request =
-- "GET / HTTP/1.1\r\n"+
-- "Host: localhost:"+port+"\r\n"+
-- "Connection: close\r\n"+
-- "\r\n";
-+ "GET / HTTP/1.1\r\n" +
-+ "Host: localhost:" + port + "\r\n" +
-+ "Connection: close\r\n" +
-+ "\r\n";
-
- os.write(request.getBytes());
- os.flush();
-@@ -158,7 +174,7 @@ public class SSLEngineTest
- String response = IO.toString(client.getInputStream());
-
- assertThat(response, Matchers.containsString("200 OK"));
-- assertThat(response,Matchers.containsString(HELLO_WORLD));
-+ assertThat(response, Matchers.containsString(HELLO_WORLD));
- }
-
- @Test
-@@ -167,26 +183,81 @@ public class SSLEngineTest
- server.setHandler(new HelloWorldHandler());
- server.start();
-
-- SSLContext ctx=SSLContext.getInstance("TLS");
-- ctx.init(null,SslContextFactory.TRUST_ALL_CERTS,new java.security.SecureRandom());
-+ SSLContext ctx = SSLContext.getInstance("TLS");
-+ ctx.init(null, SslContextFactory.TRUST_ALL_CERTS, new java.security.SecureRandom());
-
-- int port=connector.getLocalPort();
-+ int port = connector.getLocalPort();
-
-- Socket client=ctx.getSocketFactory().createSocket("localhost",port);
-- OutputStream os=client.getOutputStream();
-+ Socket client = ctx.getSocketFactory().createSocket("localhost", port);
-+ OutputStream os = client.getOutputStream();
-
- String request =
-- "GET /?dump=102400 HTTP/1.1\r\n"+
-- "Host: localhost:"+port+"\r\n"+
-- "Connection: close\r\n"+
-- "\r\n";
-+ "GET /?dump=102400 HTTP/1.1\r\n" +
-+ "Host: localhost:" + port + "\r\n" +
-+ "Connection: close\r\n" +
-+ "\r\n";
-
- os.write(request.getBytes());
- os.flush();
-
- String response = IO.toString(client.getInputStream());
-
-- assertThat(response.length(),greaterThan(102400));
-+ assertThat(response.length(), greaterThan(102400));
-+ }
-+
-+ @Test
-+ public void testInvalidLargeTLSFrame() throws Exception
-+ {
-+ AtomicLong unwraps = new AtomicLong();
-+ ConnectionFactory http = connector.getConnectionFactory(HttpConnectionFactory.class);
-+ ConnectionFactory ssl = new SslConnectionFactory(sslContextFactory, http.getProtocol())
-+ {
-+ @Override
-+ protected SslConnection newSslConnection(Connector connector, EndPoint endPoint, SSLEngine engine)
-+ {
-+ return new SslConnection(connector.getByteBufferPool(), connector.getExecutor(), endPoint, engine, isDirectBuffersForEncryption(), isDirectBuffersForDecryption())
-+ {
-+ @Override
-+ protected SSLEngineResult unwrap(SSLEngine sslEngine, ByteBuffer input, ByteBuffer output) throws SSLException
-+ {
-+ unwraps.incrementAndGet();
-+ return super.unwrap(sslEngine, input, output);
-+ }
-+ };
-+ }
-+ };
-+ ServerConnector tlsConnector = new ServerConnector(server, 1, 1, ssl, http);
-+ server.addConnector(tlsConnector);
-+ server.setHandler(new HelloWorldHandler());
-+ server.start();
-+
-+ // Create raw TLS record.
-+ byte[] bytes = new byte[20005];
-+ Arrays.fill(bytes, (byte)1);
-+
-+ bytes[0] = 22; // record type
-+ bytes[1] = 3; // major version
-+ bytes[2] = 3; // minor version
-+ bytes[3] = 78; // record length 2 bytes / 0x4E20 / decimal 20,000
-+ bytes[4] = 32; // record length
-+ bytes[5] = 1; // message type
-+ bytes[6] = 0; // message length 3 bytes / 0x004E17 / decimal 19,991
-+ bytes[7] = 78;
-+ bytes[8] = 23;
-+
-+ SocketFactory socketFactory = SocketFactory.getDefault();
-+ try (Socket client = socketFactory.createSocket("localhost", tlsConnector.getLocalPort()))
-+ {
-+ client.getOutputStream().write(bytes);
-+
-+ // Sleep to see if the server spins.
-+ Thread.sleep(1000);
-+ assertThat(unwraps.get(), lessThan(128L));
-+
-+ // Read until -1 or read timeout.
-+ client.setSoTimeout(1000);
-+ IO.readBytes(client.getInputStream());
-+ }
- }
-
- @Test
-@@ -195,63 +266,64 @@ public class SSLEngineTest
- server.setHandler(new HelloWorldHandler());
- server.start();
-
-- final int loops=10;
-- final int numConns=20;
-+ final int loops = 10;
-+ final int numConns = 20;
-
-- Socket[] client=new Socket[numConns];
-+ Socket[] client = new Socket[numConns];
-
-- SSLContext ctx=SSLContext.getInstance("TLSv1.2");
-- ctx.init(null,SslContextFactory.TRUST_ALL_CERTS,new java.security.SecureRandom());
-+ SSLContext ctx = SSLContext.getInstance("TLSv1.2");
-+ ctx.init(null, SslContextFactory.TRUST_ALL_CERTS, new java.security.SecureRandom());
-
-- int port=connector.getLocalPort();
-+ int port = connector.getLocalPort();
-
- try
- {
-- for (int l=0;l -1)
-- bytes+=len;
-+ {
-+ bytes += len;
-+ }
- is.close();
-
-- assertEquals(BODY_SIZE,handler.bytes);
-- assertEquals(BODY_SIZE,bytes);
-+ assertEquals(BODY_SIZE, handler.bytes);
-+ assertEquals(BODY_SIZE, bytes);
- }
-
- /**
-@@ -327,30 +401,30 @@ public class SSLEngineTest
- */
- private static String readResponse(Socket client) throws IOException
- {
-- BufferedReader br=null;
-- StringBuilder sb=new StringBuilder(1000);
-+ BufferedReader br = null;
-+ StringBuilder sb = new StringBuilder(1000);
-
- try
- {
- client.setSoTimeout(5000);
-- br=new BufferedReader(new InputStreamReader(client.getInputStream()));
-+ br = new BufferedReader(new InputStreamReader(client.getInputStream()));
-
- String line;
-
-- while ((line=br.readLine())!=null)
-+ while ((line = br.readLine()) != null)
- {
- sb.append(line);
- sb.append('\n');
- }
- }
-- catch(SocketTimeoutException e)
-+ catch (SocketTimeoutException e)
- {
-- System.err.println("Test timedout: "+e.toString());
-+ System.err.println("Test timedout: " + e.toString());
- e.printStackTrace(); // added to see if we can get more info from failures on CI
- }
- finally
- {
-- if (br!=null)
-+ if (br != null)
- {
- br.close();
- }
-@@ -364,22 +438,24 @@ public class SSLEngineTest
- public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
- {
- // System.err.println("HANDLE "+request.getRequestURI());
-- String ssl_id = (String)request.getAttribute("javax.servlet.request.ssl_session_id");
-- assertNotNull(ssl_id);
--
-- if (request.getParameter("dump")!=null)
-+ String sslId = (String)request.getAttribute("javax.servlet.request.ssl_session_id");
-+ assertNotNull(sslId);
-+
-+ if (request.getParameter("dump") != null)
- {
-- ServletOutputStream out=response.getOutputStream();
-+ ServletOutputStream out = response.getOutputStream();
- byte[] buf = new byte[Integer.parseInt(request.getParameter("dump"))];
- // System.err.println("DUMP "+buf.length);
-- for (int i=0;i -1)
- {
-- bytes+=len;
-+ bytes += len;
- }
-
- OutputStream os = response.getOutputStream();
-@@ -412,5 +488,4 @@ public class SSLEngineTest
- response.flushBuffer();
- }
- }
--
- }
diff --git a/CVE-2021-28169.patch b/CVE-2021-28169.patch
deleted file mode 100755
index 8f39175d4b3f7c525c68a13a71f5cf3d1a2370e7..0000000000000000000000000000000000000000
--- a/CVE-2021-28169.patch
+++ /dev/null
@@ -1,493 +0,0 @@
-From: Markus Koschany
-Date: Sat, 3 Jul 2021 20:47:31 +0200
-Subject: CVE-2021-28169
-
-Origin: https://github.com/eclipse/jetty.project/commit/1c05b0bcb181c759e98b060bded0b9376976b055
----
- .../org/eclipse/jetty/server/ResourceService.java | 4 +-
- .../org/eclipse/jetty/servlets/ConcatServlet.java | 4 +-
- .../org/eclipse/jetty/servlets/WelcomeFilter.java | 8 +-
- .../eclipse/jetty/servlets/ConcatServletTest.java | 34 +++--
- .../eclipse/jetty/servlets/WelcomeFilterTest.java | 143 +++++++++++++++++++++
- .../jetty/webapp/WebAppDefaultServletTest.java | 142 ++++++++++++++++++++
- 6 files changed, 313 insertions(+), 22 deletions(-)
- create mode 100644 jetty-servlets/src/test/java/org/eclipse/jetty/servlets/WelcomeFilterTest.java
- create mode 100644 jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppDefaultServletTest.java
-
-diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java
-index 048bd71..737f461 100644
---- a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java
-+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java
-@@ -234,7 +234,7 @@ public class ResourceService
- // Find the content
- content=_contentFactory.getContent(pathInContext,response.getBufferSize());
- if (LOG.isDebugEnabled())
-- LOG.info("content={}",content);
-+ LOG.debug("content={}", content);
-
- // Not found?
- if (content==null || !content.getResource().exists())
-@@ -420,7 +420,7 @@ public class ResourceService
- return;
- }
-
-- RequestDispatcher dispatcher=context.getRequestDispatcher(welcome);
-+ RequestDispatcher dispatcher = context.getRequestDispatcher(URIUtil.encodePath(welcome));
- if (dispatcher!=null)
- {
- // Forward to the index
-diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ConcatServlet.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ConcatServlet.java
-index a4b7df0..f1d8e57 100644
---- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ConcatServlet.java
-+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/ConcatServlet.java
-@@ -62,6 +62,7 @@ import org.eclipse.jetty.util.URIUtil;
- * appropriate. This means that when not in development mode, the servlet must be
- * restarted before changed content will be served.
- */
-+@Deprecated
- public class ConcatServlet extends HttpServlet
- {
- private boolean _development;
-@@ -126,7 +127,8 @@ public class ConcatServlet extends HttpServlet
- }
- }
-
-- RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(path);
-+ // Use the original string and not the decoded path as the Dispatcher will decode again.
-+ RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(part);
- if (dispatcher != null)
- dispatchers.add(dispatcher);
- }
-diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/WelcomeFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/WelcomeFilter.java
-index e67a067..22ea603 100644
---- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/WelcomeFilter.java
-+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/WelcomeFilter.java
-@@ -28,6 +28,8 @@ import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import javax.servlet.http.HttpServletRequest;
-
-+import org.eclipse.jetty.util.URIUtil;
-+
- /* ------------------------------------------------------------ */
- /** Welcome Filter
- * This filter can be used to server an index file for a directory
-@@ -42,6 +44,7 @@ import javax.servlet.http.HttpServletRequest;
- *
- * Requests to "/some/directory" will be redirected to "/some/directory/".
- */
-+@Deprecated
- public class WelcomeFilter implements Filter
- {
- private String welcome;
-@@ -63,7 +66,10 @@ public class WelcomeFilter implements Filter
- {
- String path=((HttpServletRequest)request).getServletPath();
- if (welcome!=null && path.endsWith("/"))
-- request.getRequestDispatcher(path+welcome).forward(request,response);
-+ {
-+ String uriInContext = URIUtil.encodePath(URIUtil.addPaths(path, welcome));
-+ request.getRequestDispatcher(uriInContext).forward(request, response);
-+ }
- else
- chain.doFilter(request, response);
- }
-diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/ConcatServletTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/ConcatServletTest.java
-index 3fcb9af..f8ea087 100644
---- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/ConcatServletTest.java
-+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/ConcatServletTest.java
-@@ -1,6 +1,6 @@
- //
- // ========================================================================
--// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
-+// Copyright (c) 1995-2021 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,11 +18,6 @@
-
- package org.eclipse.jetty.servlets;
-
--import static org.junit.jupiter.api.Assertions.assertEquals;
--import static org.junit.jupiter.api.Assertions.assertNotNull;
--import static org.junit.jupiter.api.Assertions.assertNull;
--import static org.junit.jupiter.api.Assertions.assertTrue;
--
- import java.io.BufferedReader;
- import java.io.File;
- import java.io.IOException;
-@@ -31,7 +26,6 @@ import java.io.StringReader;
- import java.nio.charset.StandardCharsets;
- import java.nio.file.Files;
- import java.nio.file.Path;
--
- import javax.servlet.RequestDispatcher;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
-@@ -45,10 +39,14 @@ import org.eclipse.jetty.servlet.ServletHolder;
- import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
- import org.eclipse.jetty.webapp.WebAppContext;
- import org.junit.jupiter.api.AfterEach;
--
- import org.junit.jupiter.api.BeforeEach;
- import org.junit.jupiter.api.Test;
-
-+import static org.junit.jupiter.api.Assertions.assertEquals;
-+import static org.junit.jupiter.api.Assertions.assertNotNull;
-+import static org.junit.jupiter.api.Assertions.assertNull;
-+import static org.junit.jupiter.api.Assertions.assertTrue;
-+
- public class ConcatServletTest
- {
- private Server server;
-@@ -92,8 +90,8 @@ public class ConcatServletTest
- String resource1 = "/resource/one.js";
- String resource2 = "/resource/two.js";
- String uri = contextPath + concatPath + "?" + resource1 + "&" + resource2;
-- String request = "" +
-- "GET " + uri + " HTTP/1.1\r\n" +
-+ String request =
-+ "GET " + uri + " HTTP/1.1\r\n" +
- "Host: localhost\r\n" +
- "Connection: close\r\n" +
- "\r\n";
-@@ -139,8 +137,8 @@ public class ConcatServletTest
- // Having a path segment and then ".." triggers a special case
- // that the ConcatServlet must detect and avoid.
- String uri = contextPath + concatPath + "?/trick/../WEB-INF/one.js";
-- String request = "" +
-- "GET " + uri + " HTTP/1.1\r\n" +
-+ String request =
-+ "GET " + uri + " HTTP/1.1\r\n" +
- "Host: localhost\r\n" +
- "Connection: close\r\n" +
- "\r\n";
-@@ -149,8 +147,8 @@ public class ConcatServletTest
-
- // Make sure ConcatServlet behaves well if it's case insensitive.
- uri = contextPath + concatPath + "?/trick/../web-inf/one.js";
-- request = "" +
-- "GET " + uri + " HTTP/1.1\r\n" +
-+ request =
-+ "GET " + uri + " HTTP/1.1\r\n" +
- "Host: localhost\r\n" +
- "Connection: close\r\n" +
- "\r\n";
-@@ -159,8 +157,8 @@ public class ConcatServletTest
-
- // Make sure ConcatServlet behaves well if encoded.
- uri = contextPath + concatPath + "?/trick/..%2FWEB-INF%2Fone.js";
-- request = "" +
-- "GET " + uri + " HTTP/1.1\r\n" +
-+ request =
-+ "GET " + uri + " HTTP/1.1\r\n" +
- "Host: localhost\r\n" +
- "Connection: close\r\n" +
- "\r\n";
-@@ -169,8 +167,8 @@ public class ConcatServletTest
-
- // Make sure ConcatServlet cannot see file system files.
- uri = contextPath + concatPath + "?/trick/../../" + directoryFile.getName();
-- request = "" +
-- "GET " + uri + " HTTP/1.1\r\n" +
-+ request =
-+ "GET " + uri + " HTTP/1.1\r\n" +
- "Host: localhost\r\n" +
- "Connection: close\r\n" +
- "\r\n";
-diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/WelcomeFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/WelcomeFilterTest.java
-new file mode 100644
-index 0000000..65e6503
---- /dev/null
-+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/WelcomeFilterTest.java
-@@ -0,0 +1,143 @@
-+//
-+// ========================================================================
-+// Copyright (c) 1995-2021 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
-+// and Apache License v2.0 which accompanies this distribution.
-+//
-+// The Eclipse Public License is available at
-+// http://www.eclipse.org/legal/epl-v10.html
-+//
-+// The Apache License v2.0 is available at
-+// http://www.opensource.org/licenses/apache2.0.php
-+//
-+// You may elect to redistribute this code under either of these licenses.
-+// ========================================================================
-+//
-+
-+package org.eclipse.jetty.servlets;
-+
-+import java.io.OutputStream;
-+import java.nio.charset.StandardCharsets;
-+import java.nio.file.Files;
-+import java.nio.file.Path;
-+import java.util.EnumSet;
-+import java.util.stream.Stream;
-+import javax.servlet.DispatcherType;
-+
-+import org.eclipse.jetty.server.LocalConnector;
-+import org.eclipse.jetty.server.Server;
-+import org.eclipse.jetty.servlet.FilterHolder;
-+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
-+import org.eclipse.jetty.webapp.WebAppContext;
-+import org.junit.jupiter.api.AfterEach;
-+import org.junit.jupiter.api.BeforeEach;
-+import org.junit.jupiter.params.ParameterizedTest;
-+import org.junit.jupiter.params.provider.Arguments;
-+import org.junit.jupiter.params.provider.MethodSource;
-+
-+import static org.hamcrest.MatcherAssert.assertThat;
-+import static org.hamcrest.Matchers.containsString;
-+import static org.junit.jupiter.api.Assertions.assertNotNull;
-+
-+public class WelcomeFilterTest
-+{
-+ private Server server;
-+ private LocalConnector connector;
-+
-+ @BeforeEach
-+ public void prepareServer() throws Exception
-+ {
-+ server = new Server();
-+ connector = new LocalConnector(server);
-+ server.addConnector(connector);
-+
-+ Path directoryPath = MavenTestingUtils.getTargetTestingDir().toPath();
-+ Files.createDirectories(directoryPath);
-+ Path welcomeResource = directoryPath.resolve("welcome.html");
-+ try (OutputStream output = Files.newOutputStream(welcomeResource))
-+ {
-+ output.write("welcome page
".getBytes(StandardCharsets.UTF_8));
-+ }
-+
-+ Path otherResource = directoryPath.resolve("other.html");
-+ try (OutputStream output = Files.newOutputStream(otherResource))
-+ {
-+ output.write("other resource
".getBytes(StandardCharsets.UTF_8));
-+ }
-+
-+ Path hiddenDirectory = directoryPath.resolve("WEB-INF");
-+ Files.createDirectories(hiddenDirectory);
-+ Path hiddenResource = hiddenDirectory.resolve("one.js");
-+ try (OutputStream output = Files.newOutputStream(hiddenResource))
-+ {
-+ output.write("CONFIDENTIAL".getBytes(StandardCharsets.UTF_8));
-+ }
-+
-+ Path hiddenWelcome = hiddenDirectory.resolve("index.html");
-+ try (OutputStream output = Files.newOutputStream(hiddenWelcome))
-+ {
-+ output.write("CONFIDENTIAL".getBytes(StandardCharsets.UTF_8));
-+ }
-+
-+ WebAppContext context = new WebAppContext(server, directoryPath.toString(), "/");
-+ server.setHandler(context);
-+ String concatPath = "/*";
-+
-+ FilterHolder filterHolder = new FilterHolder(new WelcomeFilter());
-+ filterHolder.setInitParameter("welcome", "welcome.html");
-+ context.addFilter(filterHolder, concatPath, EnumSet.of(DispatcherType.REQUEST));
-+ server.start();
-+
-+ // Verify that I can get the file programmatically, as required by the spec.
-+ assertNotNull(context.getServletContext().getResource("/WEB-INF/one.js"));
-+ }
-+
-+ @AfterEach
-+ public void destroy() throws Exception
-+ {
-+ if (server != null)
-+ server.stop();
-+ }
-+
-+ public static Stream argumentsStream()
-+ {
-+ return Stream.of(
-+ // Normal requests for the directory are redirected to the welcome page.
-+ Arguments.of("/", new String[]{"HTTP/1.1 200 ", "welcome page
"}),
-+
-+ // Try a normal resource (will bypass the filter).
-+ Arguments.of("/other.html", new String[]{"HTTP/1.1 200 ", "other resource
"}),
-+
-+ // Cannot access files in WEB-INF.
-+ Arguments.of("/WEB-INF/one.js", new String[]{"HTTP/1.1 404 "}),
-+
-+ // Cannot serve welcome from WEB-INF.
-+ Arguments.of("/WEB-INF/", new String[]{"HTTP/1.1 404 "}),
-+
-+ // Try to trick the filter into serving a protected resource.
-+ Arguments.of("/WEB-INF/one.js#/", new String[]{"HTTP/1.1 404 "}),
-+ Arguments.of("/js/../WEB-INF/one.js#/", new String[]{"HTTP/1.1 404 "}),
-+
-+ // Test the URI is not double decoded in the dispatcher.
-+ Arguments.of("/%2557EB-INF/one.js%23/", new String[]{"HTTP/1.1 404 "})
-+ );
-+ }
-+
-+ @ParameterizedTest
-+ @MethodSource("argumentsStream")
-+ public void testWelcomeFilter(String uri, String[] contains) throws Exception
-+ {
-+ String request =
-+ "GET " + uri + " HTTP/1.1\r\n" +
-+ "Host: localhost\r\n" +
-+ "Connection: close\r\n" +
-+ "\r\n";
-+ String response = connector.getResponse(request);
-+ for (String s : contains)
-+ {
-+ assertThat(response, containsString(s));
-+ }
-+ }
-+}
-diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppDefaultServletTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppDefaultServletTest.java
-new file mode 100644
-index 0000000..933bb7a
---- /dev/null
-+++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppDefaultServletTest.java
-@@ -0,0 +1,142 @@
-+//
-+// ========================================================================
-+// Copyright (c) 1995-2021 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
-+// and Apache License v2.0 which accompanies this distribution.
-+//
-+// The Eclipse Public License is available at
-+// http://www.eclipse.org/legal/epl-v10.html
-+//
-+// The Apache License v2.0 is available at
-+// http://www.opensource.org/licenses/apache2.0.php
-+//
-+// You may elect to redistribute this code under either of these licenses.
-+// ========================================================================
-+//
-+
-+package org.eclipse.jetty.webapp;
-+
-+import java.io.OutputStream;
-+import java.nio.charset.StandardCharsets;
-+import java.nio.file.Files;
-+import java.nio.file.Path;
-+import java.util.stream.Stream;
-+
-+import org.eclipse.jetty.server.LocalConnector;
-+import org.eclipse.jetty.server.Server;
-+import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
-+import org.eclipse.jetty.util.IO;
-+import org.junit.jupiter.api.AfterEach;
-+import org.junit.jupiter.api.BeforeEach;
-+import org.junit.jupiter.params.ParameterizedTest;
-+import org.junit.jupiter.params.provider.Arguments;
-+import org.junit.jupiter.params.provider.MethodSource;
-+
-+import static org.hamcrest.MatcherAssert.assertThat;
-+import static org.hamcrest.Matchers.containsString;
-+import static org.junit.jupiter.api.Assertions.assertNotNull;
-+
-+public class WebAppDefaultServletTest
-+{
-+ private Server server;
-+ private LocalConnector connector;
-+
-+ @BeforeEach
-+ public void prepareServer() throws Exception
-+ {
-+ server = new Server();
-+ connector = new LocalConnector(server);
-+ server.addConnector(connector);
-+
-+ Path directoryPath = MavenTestingUtils.getTargetTestingDir().toPath();
-+ IO.delete(directoryPath.toFile());
-+ Files.createDirectories(directoryPath);
-+ Path welcomeResource = directoryPath.resolve("index.html");
-+ try (OutputStream output = Files.newOutputStream(welcomeResource))
-+ {
-+ output.write("welcome page
".getBytes(StandardCharsets.UTF_8));
-+ }
-+
-+ Path otherResource = directoryPath.resolve("other.html");
-+ try (OutputStream output = Files.newOutputStream(otherResource))
-+ {
-+ output.write("other resource
".getBytes(StandardCharsets.UTF_8));
-+ }
-+
-+ Path hiddenDirectory = directoryPath.resolve("WEB-INF");
-+ Files.createDirectories(hiddenDirectory);
-+ Path hiddenResource = hiddenDirectory.resolve("one.js");
-+ try (OutputStream output = Files.newOutputStream(hiddenResource))
-+ {
-+ output.write("this is confidential".getBytes(StandardCharsets.UTF_8));
-+ }
-+
-+ // Create directory to trick resource service.
-+ Path hackPath = directoryPath.resolve("%57EB-INF/one.js#/");
-+ Files.createDirectories(hackPath);
-+ try (OutputStream output = Files.newOutputStream(hackPath.resolve("index.html")))
-+ {
-+ output.write("this content does not matter".getBytes(StandardCharsets.UTF_8));
-+ }
-+
-+ Path standardHashDir = directoryPath.resolve("welcome#");
-+ Files.createDirectories(standardHashDir);
-+ try (OutputStream output = Files.newOutputStream(standardHashDir.resolve("index.html")))
-+ {
-+ output.write("standard hash dir welcome".getBytes(StandardCharsets.UTF_8));
-+ }
-+
-+ WebAppContext context = new WebAppContext(server, directoryPath.toString(), "/");
-+ server.setHandler(context);
-+ server.start();
-+
-+ // Verify that I can get the file programmatically, as required by the spec.
-+ assertNotNull(context.getServletContext().getResource("/WEB-INF/one.js"));
-+ }
-+
-+ @AfterEach
-+ public void destroy() throws Exception
-+ {
-+ if (server != null)
-+ server.stop();
-+ }
-+
-+ public static Stream argumentsStream()
-+ {
-+ return Stream.of(
-+ Arguments.of("/WEB-INF/", new String[]{"HTTP/1.1 404 "}),
-+ Arguments.of("/welcome%23/", new String[]{"HTTP/1.1 200 ", "standard hash dir welcome"}),
-+
-+ // Normal requests for the directory are redirected to the welcome page.
-+ Arguments.of("/", new String[]{"HTTP/1.1 200 ", "welcome page
"}),
-+
-+ // We can be served other resources.
-+ Arguments.of("/other.html", new String[]{"HTTP/1.1 200 ", "other resource
"}),
-+
-+ // The ContextHandler will filter these ones out as as WEB-INF is a protected target.
-+ Arguments.of("/WEB-INF/one.js#/", new String[]{"HTTP/1.1 404 "}),
-+ Arguments.of("/js/../WEB-INF/one.js#/", new String[]{"HTTP/1.1 404 "}),
-+
-+ // Test the URI is not double decoded by the dispatcher that serves the welcome file (we get index.html not one.js).
-+ Arguments.of("/%2557EB-INF/one.js%23/", new String[]{"HTTP/1.1 200 ", "this content does not matter"})
-+ );
-+ }
-+
-+ @ParameterizedTest
-+ @MethodSource("argumentsStream")
-+ public void testResourceService(String uri, String[] contains) throws Exception
-+ {
-+ String request =
-+ "GET " + uri + " HTTP/1.1\r\n" +
-+ "Host: localhost\r\n" +
-+ "Connection: close\r\n" +
-+ "\r\n";
-+ String response = connector.getResponse(request);
-+ for (String s : contains)
-+ {
-+ assertThat(response, containsString(s));
-+ }
-+ }
-+}
diff --git a/CVE-2021-34428.patch b/CVE-2021-34428.patch
deleted file mode 100755
index 5090be080a75b3620112126284585a7d28e1325d..0000000000000000000000000000000000000000
--- a/CVE-2021-34428.patch
+++ /dev/null
@@ -1,657 +0,0 @@
-From: Markus Koschany
-Date: Sat, 3 Jul 2021 20:28:06 +0200
-Subject: CVE-2021-34428
-
-Origin: https://github.com/eclipse/jetty.project/commit/cd6462a6252d083b3c9ea2684aab0b4c9669ed19
----
- .../org/eclipse/jetty/server/session/Session.java | 9 +-
- .../server/session/TestHttpSessionListener.java | 24 +-
- .../jetty/server/session/SessionListenerTest.java | 367 +++++++++++++++------
- 3 files changed, 291 insertions(+), 109 deletions(-)
-
-diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java
-index a34bc0f..d667560 100644
---- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java
-+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/Session.java
-@@ -506,6 +506,7 @@ public class Session implements SessionHandler.SessionIf
- {
- try (Lock lock = _lock.lock())
- {
-+ checkValidForRead();
- return _sessionData.getLastAccessed();
- }
- }
-@@ -972,14 +973,18 @@ public class Session implements SessionHandler.SessionIf
- // do the invalidation
- _handler.callSessionDestroyedListeners(this);
- }
-+ catch (Exception e)
-+ {
-+ LOG.warn("Error during Session destroy listener", e);
-+ }
- finally
- {
- // call the attribute removed listeners and finally mark it
- // as invalid
- finishInvalidate();
-+ // tell id mgr to remove sessions with same id from all contexts
-+ _handler.getSessionIdManager().invalidateAll(_sessionData.getId());
- }
-- // tell id mgr to remove sessions with same id from all contexts
-- _handler.getSessionIdManager().invalidateAll(_sessionData.getId());
- }
- }
- catch (Exception e)
-diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpSessionListener.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpSessionListener.java
-index 770627b..dd8982f 100644
---- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpSessionListener.java
-+++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpSessionListener.java
-@@ -35,16 +35,18 @@ public class TestHttpSessionListener implements HttpSessionListener
- public List createdSessions = new ArrayList<>();
- public List destroyedSessions = new ArrayList<>();
- public boolean accessAttribute = false;
-- public Exception ex = null;
-+ public boolean lastAccessTime = false;
-+ public Exception attributeException = null;
-+ public Exception accessTimeException = null;
-
-- public TestHttpSessionListener(boolean access)
-+ public TestHttpSessionListener(boolean accessAttribute, boolean lastAccessTime)
- {
-- accessAttribute = access;
-+ this.accessAttribute = accessAttribute;
-+ this.lastAccessTime = lastAccessTime;
- }
-
- public TestHttpSessionListener()
- {
-- accessAttribute = false;
- }
-
- public void sessionDestroyed(HttpSessionEvent se)
-@@ -58,7 +60,19 @@ public class TestHttpSessionListener implements HttpSessionListener
- }
- catch (Exception e)
- {
-- ex = e;
-+ attributeException = e;
-+ }
-+ }
-+
-+ if (lastAccessTime)
-+ {
-+ try
-+ {
-+ se.getSession().getLastAccessedTime();
-+ }
-+ catch (Exception e)
-+ {
-+ accessTimeException = e;
- }
- }
- }
-diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionListenerTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionListenerTest.java
-index ba83986..363d1e3 100644
---- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionListenerTest.java
-+++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionListenerTest.java
-@@ -1,6 +1,6 @@
- //
- // ========================================================================
--// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
-+// Copyright (c) 1995-2021 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,19 +18,17 @@
-
- package org.eclipse.jetty.server.session;
-
--import static org.hamcrest.MatcherAssert.assertThat;
--import static org.hamcrest.Matchers.isIn;
--import static org.junit.jupiter.api.Assertions.assertEquals;
--import static org.junit.jupiter.api.Assertions.assertNotEquals;
--import static org.junit.jupiter.api.Assertions.assertNotNull;
--import static org.junit.jupiter.api.Assertions.assertNull;
--import static org.junit.jupiter.api.Assertions.assertTrue;
--
- import java.io.IOException;
-+import java.io.InputStream;
-+import java.io.OutputStream;
- import java.io.Serializable;
- import java.net.HttpCookie;
-+import java.net.URL;
-+import java.net.URLClassLoader;
-+import java.nio.file.Files;
-+import java.nio.file.Path;
-+import java.util.Collection;
- import java.util.concurrent.TimeUnit;
--
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
-@@ -38,53 +36,140 @@ import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
- import javax.servlet.http.HttpSessionBindingEvent;
- import javax.servlet.http.HttpSessionBindingListener;
-+import javax.servlet.http.HttpSessionEvent;
-+import javax.servlet.http.HttpSessionListener;
-
- import org.eclipse.jetty.client.HttpClient;
- import org.eclipse.jetty.client.api.ContentResponse;
- import org.eclipse.jetty.client.api.Request;
-+import org.eclipse.jetty.server.Server;
- import org.eclipse.jetty.servlet.ServletContextHandler;
- import org.eclipse.jetty.servlet.ServletHolder;
-+import org.eclipse.jetty.toolchain.test.IO;
-+import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
-+import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
-+import org.eclipse.jetty.util.component.LifeCycle;
-+import org.eclipse.jetty.webapp.WebAppContext;
- import org.junit.jupiter.api.Test;
-+import org.junit.jupiter.api.extension.ExtendWith;
-+import org.junit.jupiter.api.Disabled;
-+
-+import static org.hamcrest.MatcherAssert.assertThat;
-+import static org.hamcrest.Matchers.greaterThan;
-+//import static org.hamcrest.Matchers.in;
-+import static org.hamcrest.Matchers.is;
-+import static org.junit.jupiter.api.Assertions.assertEquals;
-+import static org.junit.jupiter.api.Assertions.assertFalse;
-+import static org.junit.jupiter.api.Assertions.assertNotEquals;
-+import static org.junit.jupiter.api.Assertions.assertNotNull;
-+import static org.junit.jupiter.api.Assertions.assertNull;
-+import static org.junit.jupiter.api.Assertions.assertTrue;
-
- /**
- * SessionListenerTest
- *
- * Test that session listeners are called.
- */
-+@ExtendWith(WorkDirExtension.class)
- public class SessionListenerTest
- {
-+ public WorkDir workDir;
-+
- /**
- * Test that listeners are called when a session is deliberately invalidated.
-- *
-- * @throws Exception
- */
-+ @Disabled
- @Test
- public void testListenerWithInvalidation() throws Exception
- {
- String contextPath = "";
- String servletMapping = "/server";
- int inactivePeriod = 6;
-- int scavengePeriod = -1;
-+ int scavengePeriod = -1;
-
- DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
- cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT);
-- SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
-- ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(scavengePeriod);
-+ TestSessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
-+ storeFactory.setGracePeriodSec(scavengePeriod);
-
-- TestServer server = new TestServer(0, inactivePeriod, scavengePeriod,
-- cacheFactory, storeFactory);
-+ TestServer server = new TestServer(0, inactivePeriod, scavengePeriod,
-+ cacheFactory, storeFactory);
- ServletContextHandler context = server.addContext(contextPath);
-- TestHttpSessionListener listener = new TestHttpSessionListener(true);
-+ TestHttpSessionListener listener = new TestHttpSessionListener(true, true);
- context.getSessionHandler().addEventListener(listener);
- TestServlet servlet = new TestServlet();
- ServletHolder holder = new ServletHolder(servlet);
- context.addServlet(holder, servletMapping);
-+
-+ try
-+ {
-+ server.start();
-+ int port1 = server.getPort();
-+
-+ HttpClient client = new HttpClient();
-+ client.start();
-+ try
-+ {
-+ String url = "http://localhost:" + port1 + contextPath + servletMapping;
-+ // Create the session
-+ ContentResponse response1 = client.GET(url + "?action=init");
-+ assertEquals(HttpServletResponse.SC_OK, response1.getStatus());
-+ String sessionCookie = response1.getHeaders().get("Set-Cookie");
-+ assertNotNull(sessionCookie);
-+ assertTrue(TestServlet.bindingListener.bound);
-+
-+ String sessionId = TestServer.extractSessionId(sessionCookie);
-+ //assertThat(sessionId, is(in(listener.createdSessions)));
-+
-+ // Make a request which will invalidate the existing session
-+ Request request2 = client.newRequest(url + "?action=test");
-+ ContentResponse response2 = request2.send();
-+ assertEquals(HttpServletResponse.SC_OK, response2.getStatus());
-+
-+ assertTrue(TestServlet.bindingListener.unbound);
-+ assertTrue(listener.destroyedSessions.contains(sessionId));
-+ }
-+ finally
-+ {
-+ LifeCycle.stop(client);
-+ }
-+ }
-+ finally
-+ {
-+ LifeCycle.stop(server);
-+ }
-+ }
-
-+ /**
-+ * Test that if a session listener throws an exception during sessionDestroyed the session is still invalidated
-+ */
-+ @Test
-+ public void testListenerWithInvalidationException() throws Exception
-+ {
-+ String contextPath = "";
-+ String servletMapping = "/server";
-+ int inactivePeriod = 6;
-+ int scavengePeriod = -1;
-+
-+ DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
-+ cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT);
-+ TestSessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
-+ storeFactory.setGracePeriodSec(scavengePeriod);
-+
-+ TestServer server = new TestServer(0, inactivePeriod, scavengePeriod,
-+ cacheFactory, storeFactory);
-+ ServletContextHandler context = server.addContext(contextPath);
-+ ThrowingSessionListener listener = new ThrowingSessionListener();
-+ context.getSessionHandler().addEventListener(listener);
-+ TestServlet servlet = new TestServlet();
-+ ServletHolder holder = new ServletHolder(servlet);
-+ context.addServlet(holder, servletMapping);
-+
- try
- {
- server.start();
- int port1 = server.getPort();
--
-+
- HttpClient client = new HttpClient();
- client.start();
- try
-@@ -92,42 +177,59 @@ public class SessionListenerTest
- String url = "http://localhost:" + port1 + contextPath + servletMapping;
- // Create the session
- ContentResponse response1 = client.GET(url + "?action=init");
-- assertEquals(HttpServletResponse.SC_OK,response1.getStatus());
-+ assertEquals(HttpServletResponse.SC_OK, response1.getStatus());
- String sessionCookie = response1.getHeaders().get("Set-Cookie");
-- assertTrue(sessionCookie != null);
-- assertTrue (TestServlet.bindingListener.bound);
--
-+ assertNotNull(sessionCookie);
-+ assertTrue(TestServlet.bindingListener.bound);
-+
- String sessionId = TestServer.extractSessionId(sessionCookie);
-- assertThat(sessionId, isIn(listener.createdSessions));
--
-+
- // Make a request which will invalidate the existing session
- Request request2 = client.newRequest(url + "?action=test");
- ContentResponse response2 = request2.send();
-- assertEquals(HttpServletResponse.SC_OK,response2.getStatus());
-+ assertEquals(HttpServletResponse.SC_OK, response2.getStatus());
-
-- assertTrue (TestServlet.bindingListener.unbound);
-- assertTrue (listener.destroyedSessions.contains(sessionId));
-+ assertTrue(TestServlet.bindingListener.unbound);
-+
-+ //check session no longer exists
-+ assertFalse(context.getSessionHandler().getSessionCache().contains(sessionId));
-+ assertFalse(context.getSessionHandler().getSessionCache().getSessionDataStore().exists(sessionId));
- }
- finally
- {
-- client.stop();
-+ LifeCycle.stop(client);
- }
- }
- finally
- {
-- server.stop();
-+ LifeCycle.stop(server);
- }
- }
-
--
- /**
-- * Test that listeners are called when a session expires.
-- *
-- * @throws Exception
-+ * Test that listeners are called when a session expires
-+ * and that the listener is able to access webapp classes.
- */
-+ @Disabled
- @Test
- public void testSessionExpiresWithListener() throws Exception
- {
-+ Path foodir = workDir.getEmptyPathDir();
-+ Path fooClass = foodir.resolve("Foo.class");
-+
-+ //Use a class that would only be known to the webapp classloader
-+ try (InputStream foostream = Thread.currentThread().getContextClassLoader().getResourceAsStream("Foo.clazz");
-+ OutputStream out = Files.newOutputStream(fooClass))
-+ {
-+ IO.copy(foostream, out);
-+ }
-+
-+ assertTrue(Files.exists(fooClass));
-+ assertThat(Files.size(fooClass), greaterThan(0L));
-+
-+ URL[] foodirUrls = new URL[]{foodir.toUri().toURL()};
-+ URLClassLoader contextClassLoader = new URLClassLoader(foodirUrls, Thread.currentThread().getContextClassLoader());
-+
- String contextPath = "/";
- String servletMapping = "/server";
- int inactivePeriod = 3;
-@@ -135,58 +237,66 @@ public class SessionListenerTest
-
- DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
- cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT);
-- SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
-- ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(scavengePeriod);
-+ TestSessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
-+ storeFactory.setGracePeriodSec(scavengePeriod);
-
- TestServer server1 = new TestServer(0, inactivePeriod, scavengePeriod,
-- cacheFactory, storeFactory);
-+ cacheFactory, storeFactory);
- TestServlet servlet = new TestServlet();
- ServletHolder holder = new ServletHolder(servlet);
- ServletContextHandler context = server1.addContext(contextPath);
-+ context.setClassLoader(contextClassLoader);
- context.addServlet(holder, servletMapping);
-- TestHttpSessionListener listener = new TestHttpSessionListener(true);
-+ //TestHttpSessionListener listener = new TestHttpSessionListenerWithWebappClasses(true, true);
-+ TestHttpSessionListener listener = null;
- context.getSessionHandler().addEventListener(listener);
--
-- server1.start();
-- int port1 = server1.getPort();
-
- try
- {
-+ server1.start();
-+ int port1 = server1.getPort();
-+
- HttpClient client = new HttpClient();
-- client.start();
-- String url = "http://localhost:" + port1 + contextPath + servletMapping.substring(1);
-+ try
-+ {
-+ client.start();
-+ String url = "http://localhost:" + port1 + contextPath + servletMapping.substring(1);
-
-- //make a request to set up a session on the server
-- ContentResponse response1 = client.GET(url + "?action=init");
-- assertEquals(HttpServletResponse.SC_OK,response1.getStatus());
-- String sessionCookie = response1.getHeaders().get("Set-Cookie");
-- assertTrue(sessionCookie != null);
--
-- String sessionId = TestServer.extractSessionId(sessionCookie);
-+ //make a request to set up a session on the server
-+ ContentResponse response1 = client.GET(url + "?action=init");
-+ assertEquals(HttpServletResponse.SC_OK, response1.getStatus());
-+ String sessionCookie = response1.getHeaders().get("Set-Cookie");
-+ assertNotNull(sessionCookie);
-+
-+ String sessionId = TestServer.extractSessionId(sessionCookie);
-+
-+ //assertThat(sessionId, is(in(listener.createdSessions)));
-
-- assertThat(sessionId, isIn(listener.createdSessions));
--
-- //and wait until the session should have expired
-- Thread.currentThread().sleep(TimeUnit.SECONDS.toMillis(inactivePeriod+(scavengePeriod)));
-+ //and wait until the session should have expired
-+ Thread.sleep(TimeUnit.SECONDS.toMillis(inactivePeriod + (2 * scavengePeriod)));
-
-- assertThat(sessionId, isIn(listener.destroyedSessions));
-+ //assertThat(sessionId, is(in(listener.destroyedSessions)));
-
-- assertNull(listener.ex);
-+ assertNull(listener.attributeException);
-+ assertNull(listener.accessTimeException);
-+ }
-+ finally
-+ {
-+ LifeCycle.stop(client);
-+ }
- }
- finally
- {
- server1.stop();
-- }
-+ }
- }
--
-+
- /**
- * Check that a session that is expired cannot be reused, and expiry listeners are called for it
-- *
-- * @throws Exception
- */
- @Test
- public void testExpiredSession() throws Exception
-- {
-+ {
- String contextPath = "/";
- String servletMapping = "/server";
- int inactivePeriod = 4;
-@@ -194,65 +304,122 @@ public class SessionListenerTest
-
- DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
- cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT);
-- SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
-- ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(scavengePeriod);
-+ TestSessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
-+ storeFactory.setGracePeriodSec(scavengePeriod);
-
- TestServer server1 = new TestServer(0, inactivePeriod, scavengePeriod,
-- cacheFactory, storeFactory);
-+ cacheFactory, storeFactory);
- SimpleTestServlet servlet = new SimpleTestServlet();
- ServletHolder holder = new ServletHolder(servlet);
- ServletContextHandler context = server1.addContext(contextPath);
- context.addServlet(holder, servletMapping);
-- TestHttpSessionListener listener = new TestHttpSessionListener();
--
-+ TestHttpSessionListener listener = new TestHttpSessionListener(true, true);
-+
- context.getSessionHandler().addEventListener(listener);
--
-- server1.start();
-- int port1 = server1.getPort();
-
- try
-- {
-+ {
-+ server1.start();
-+ int port1 = server1.getPort();
-+
- //save a session that has already expired
- long now = System.currentTimeMillis();
-- SessionData data = context.getSessionHandler().getSessionCache().getSessionDataStore().newSessionData("1234", now-10, now-5, now-10, 30000);
-+ SessionData data = context.getSessionHandler().getSessionCache().getSessionDataStore().newSessionData("1234", now - 10, now - 5, now - 10, 30000);
- data.setExpiry(100); //make it expired a long time ago
- context.getSessionHandler().getSessionCache().getSessionDataStore().store("1234", data);
--
-+
- HttpClient client = new HttpClient();
-- client.start();
-+ try
-+ {
-+ client.start();
-+
-+ port1 = server1.getPort();
-+ String url = "http://localhost:" + port1 + contextPath + servletMapping.substring(1);
-+
-+ //make another request using the id of the expired session
-+ Request request = client.newRequest(url + "?action=test");
-+ request.cookie(new HttpCookie("JSESSIONID", "1234"));
-+ ContentResponse response = request.send();
-+ assertEquals(HttpServletResponse.SC_OK, response.getStatus());
-+
-+ //should be a new session id
-+ String cookie2 = response.getHeaders().get("Set-Cookie");
-+ assertNotEquals("1234", TestServer.extractSessionId(cookie2));
-
-- port1 = server1.getPort();
-- String url = "http://localhost:" + port1 + contextPath + servletMapping.substring(1);
--
-- //make another request using the id of the expired session
-- Request request = client.newRequest(url + "?action=test");
-- request.cookie(new HttpCookie("JSESSIONID", "1234"));
-- ContentResponse response = request.send();
-- assertEquals(HttpServletResponse.SC_OK,response.getStatus());
--
-- //should be a new session id
-- String cookie2 = response.getHeaders().get("Set-Cookie");
-- assertNotEquals("1234", TestServer.extractSessionId(cookie2));
--
-- assertTrue (listener.destroyedSessions.contains("1234"));
--
-- assertNull(listener.ex);
-+ assertTrue(listener.destroyedSessions.contains("1234"));
-
-+ assertNull(listener.attributeException);
-+ assertNull(listener.accessTimeException);
-+ }
-+ finally
-+ {
-+ LifeCycle.stop(client);
-+ }
- }
- finally
- {
- server1.stop();
-- }
-+ }
-+ }
-+
-+ public static class MyHttpSessionListener implements HttpSessionListener
-+ {
-+ @Override
-+ public void sessionCreated(HttpSessionEvent se)
-+ {
-+ }
-+
-+ @Override
-+ public void sessionDestroyed(HttpSessionEvent se)
-+ {
-+ }
- }
-
--
--
-+ public static class ThrowingSessionListener implements HttpSessionListener
-+ {
-+
-+ @Override
-+ public void sessionCreated(HttpSessionEvent se)
-+ {
-+ }
-+
-+ @Override
-+ public void sessionDestroyed(HttpSessionEvent se)
-+ {
-+ throw new IllegalStateException("Exception during sessionDestroyed");
-+ }
-+
-+ }
-+
-+ @Test
-+ public void testSessionListeners()
-+ {
-+ Server server = new Server();
-+ try
-+ {
-+ WebAppContext wac = new WebAppContext();
-+
-+ wac.setServer(server);
-+ server.setHandler(wac);
-+ wac.addEventListener(new MyHttpSessionListener());
-+
-+ Collection listeners = wac.getSessionHandler().getBeans(MyHttpSessionListener.class);
-+ assertNotNull(listeners);
-+
-+ assertEquals(1, listeners.size());
-+ }
-+ finally
-+ {
-+ LifeCycle.stop(server);
-+ }
-+ }
-+
- public static class MySessionBindingListener implements HttpSessionBindingListener, Serializable
- {
- private static final long serialVersionUID = 1L;
- boolean unbound = false;
- boolean bound = false;
--
-+
- public void valueUnbound(HttpSessionBindingEvent event)
- {
- unbound = true;
-@@ -263,38 +430,34 @@ public class SessionListenerTest
- bound = true;
- }
- }
--
--
--
-+
- public static class TestServlet extends HttpServlet
- {
- private static final long serialVersionUID = 1L;
- public static final MySessionBindingListener bindingListener = new MySessionBindingListener();
--
-
- @Override
- protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException
- {
- String action = request.getParameter("action");
--
-+
- if ("init".equals(action))
- {
- HttpSession session = request.getSession(true);
- session.setAttribute("foo", bindingListener);
- assertNotNull(session);
--
- }
- else if ("test".equals(action))
- {
- HttpSession session = request.getSession(false);
- assertNotNull(session);
--
-+
- //invalidate existing session
- session.invalidate();
- }
- }
- }
--
-+
- public static class SimpleTestServlet extends HttpServlet
- {
- private static final long serialVersionUID = 1L;
-@@ -306,7 +469,7 @@ public class SessionListenerTest
- if ("test".equals(action))
- {
- HttpSession session = request.getSession(true);
-- assertTrue(session != null);
-+ assertNotNull(session);
- }
- }
- }
diff --git a/CVE-2022-2047.patch b/CVE-2022-2047.patch
deleted file mode 100644
index 64a7a9a538a2d51eac7d5ef77ca8fadd7e6b75ae..0000000000000000000000000000000000000000
--- a/CVE-2022-2047.patch
+++ /dev/null
@@ -1,326 +0,0 @@
-From: Markus Koschany
-Date: Wed, 17 Aug 2022 12:58:27 +0200
-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(-)
-
-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
---- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java
-+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpRequest.java
-@@ -177,6 +177,8 @@ public class HttpRequest implements Request
- String rawPath = uri.getRawPath();
- if (rawPath == null)
- rawPath = "";
-+ if (!rawPath.startsWith("/"))
-+ rawPath = "/" + rawPath;
- this.path = rawPath;
- String query = uri.getRawQuery();
- if (query != null)
-@@ -855,14 +857,14 @@ public class HttpRequest implements Request
- return result;
- }
-
-- private URI newURI(String uri)
-+ private URI newURI(String path)
- {
- try
- {
- // Handle specially the "OPTIONS *" case, since it is possible to create a URI from "*" (!).
-- if ("*".equals(uri))
-+ if ("*".equals(path))
- return null;
-- URI result = new URI(uri);
-+ URI result = new URI(path);
- return result.isOpaque() ? null : result;
- }
- catch (URISyntaxException x)
-diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
-index 9c43512..5a97bdd 100644
---- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
-+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java
-@@ -189,7 +189,7 @@ public class HttpURI
- _uri=uri;
-
- if (HttpMethod.CONNECT.is(method))
-- _path=uri;
-+ parse(State.HOST, uri, 0, uri.length());
- else
- parse(uri.startsWith("/")?State.PATH:State.START,uri,0,uri.length());
- }
-@@ -720,17 +720,30 @@ public class HttpURI
- */
- public void setAuthority(String host, int port)
- {
-+ if (host != null && !isPathValidForAuthority(_path))
-+ throw new IllegalArgumentException("Relative path with authority");
- _host=host;
- _port=port;
- _uri=null;
- }
-
-+ private boolean isPathValidForAuthority(String path)
-+ {
-+ if (path == null)
-+ return true;
-+ if (path.isEmpty() || "*".equals(path))
-+ return true;
-+ return path.startsWith("/");
-+ }
-+
- /* ------------------------------------------------------------ */
- /**
- * @param path the path
- */
- public void setPath(String path)
- {
-+ if (hasAuthority() && !isPathValidForAuthority(path))
-+ throw new IllegalArgumentException("Relative path with authority");
- _uri=null;
- _path=path;
- _decodedPath=null;
-@@ -739,6 +752,8 @@ public class HttpURI
- /* ------------------------------------------------------------ */
- public void setPathQuery(String path)
- {
-+ if (hasAuthority() && !isPathValidForAuthority(path))
-+ throw new IllegalArgumentException("Relative path with authority");
- _uri=null;
- _path=null;
- _decodedPath=null;
-@@ -747,7 +762,13 @@ public class HttpURI
- if (path!=null)
- parse(State.PATH,path,0,path.length());
- }
--
-+
-+ private boolean hasAuthority()
-+ {
-+ return _host != null;
-+ }
-+
-+
- /* ------------------------------------------------------------ */
- public void setQuery(String query)
- {
-diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java
-index 63a58cf..6c3e65f 100644
---- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java
-+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java
-@@ -32,6 +32,15 @@ import java.nio.charset.StandardCharsets;
- import org.eclipse.jetty.util.MultiMap;
- 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 static org.junit.jupiter.api.Assertions.assertEquals;
-+import static org.junit.jupiter.api.Assertions.assertThrows;
-+import static org.junit.jupiter.api.Assertions.assertTrue;
-+import static org.junit.jupiter.api.Assertions.fail;
-+import static org.junit.jupiter.api.Assumptions.assumeTrue;
-+
- public class HttpURITest
- {
- @Test
-@@ -100,6 +109,32 @@ public class HttpURITest
- assertThat(uri.getPath(),is("/bar"));
- }
-
-+ @Test
-+ public void testCONNECT()
-+ {
-+ HttpURI uri = new HttpURI();
-+
-+ uri.parseRequestTarget("CONNECT", "host:80");
-+ assertThat(uri.getHost(), is("host"));
-+ assertThat(uri.getPort(), is(80));
-+ assertThat(uri.getPath(), nullValue());
-+
-+ uri.parseRequestTarget("CONNECT", "host");
-+ assertThat(uri.getHost(), is("host"));
-+ assertThat(uri.getPort(), is(-1));
-+ assertThat(uri.getPath(), nullValue());
-+
-+ uri.parseRequestTarget("CONNECT", "192.168.0.1:8080");
-+ assertThat(uri.getHost(), is("192.168.0.1"));
-+ assertThat(uri.getPort(), is(8080));
-+ assertThat(uri.getPath(), nullValue());
-+
-+ uri.parseRequestTarget("CONNECT", "[::1]:8080");
-+ assertThat(uri.getHost(), is("[::1]"));
-+ assertThat(uri.getPort(), is(8080));
-+ assertThat(uri.getPath(), nullValue());
-+ }
-+
- @Test
- public void testExtB() throws Exception
- {
-@@ -222,4 +257,64 @@ public class HttpURITest
- assertEquals(uri.getAuthority(), "example.com:8888");
- assertEquals(uri.getUser(), "user:password");
- }
-+
-+ @Test
-+ public void testRelativePathWithAuthority()
-+ {
-+ assertThrows(IllegalArgumentException.class, () ->
-+ {
-+ HttpURI httpURI = new HttpURI();
-+ httpURI.setAuthority("host", 0);
-+ httpURI.setPath("path");
-+ });
-+ assertThrows(IllegalArgumentException.class, () ->
-+ {
-+ HttpURI httpURI = new HttpURI();
-+ httpURI.setAuthority("host", 8080);
-+ httpURI.setPath(";p=v/url");
-+ });
-+ assertThrows(IllegalArgumentException.class, () ->
-+ {
-+ HttpURI httpURI = new HttpURI();
-+ httpURI.setAuthority("host", 0);
-+ httpURI.setPath(";");
-+ });
-+
-+ assertThrows(IllegalArgumentException.class, () ->
-+ {
-+ HttpURI httpURI = new HttpURI();
-+ httpURI.setPath("path");
-+ httpURI.setAuthority("host", 0);
-+ });
-+ assertThrows(IllegalArgumentException.class, () ->
-+ {
-+ HttpURI httpURI = new HttpURI();
-+ httpURI.setPath(";p=v/url");
-+ httpURI.setAuthority("host", 8080);
-+ });
-+ assertThrows(IllegalArgumentException.class, () ->
-+ {
-+ HttpURI httpURI = new HttpURI();
-+ httpURI.setPath(";");
-+ httpURI.setAuthority("host", 0);
-+ });
-+
-+ HttpURI uri = new HttpURI();
-+ uri.setPath("*");
-+ uri.setAuthority("host", 0);
-+ assertEquals("//host*", uri.toString());
-+ uri = new HttpURI();
-+ uri.setAuthority("host", 0);
-+ uri.setPath("*");
-+ assertEquals("//host*", uri.toString());
-+
-+ uri = new HttpURI();
-+ uri.setPath("");
-+ uri.setAuthority("host", 0);
-+ assertEquals("//host", uri.toString());
-+ uri = new HttpURI();
-+ uri.setAuthority("host", 0);
-+ uri.setPath("");
-+ assertEquals("//host", uri.toString());
-+ }
- }
-diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java
-index 6b7d39e..d3dd5c8 100644
---- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java
-+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/ConnectHandler.java
-@@ -197,7 +197,7 @@ public class ConnectHandler extends HandlerWrapper
- {
- if (HttpMethod.CONNECT.is(request.getMethod()))
- {
-- String serverAddress = request.getRequestURI();
-+ String serverAddress = baseRequest.getHttpURI().getAuthority();
- if (LOG.isDebugEnabled())
- LOG.debug("CONNECT request for {}", serverAddress);
-
-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 b15bcc7..5b996bb 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
-@@ -1778,9 +1778,19 @@ public class Request implements HttpServletRequest
-
- setMethod(request.getMethod());
- HttpURI uri = request.getURI();
-- _originalURI = uri.isAbsolute()&&request.getHttpVersion()!=HttpVersion.HTTP_2?uri.toString():uri.getPathQuery();
-+ String encoded;
-+ if (HttpMethod.CONNECT.is(request.getMethod()))
-+ {
-+ _originalURI = uri.getAuthority();
-+ encoded = "/";
-+ }
-+ else
-+ {
-+ _originalURI = uri.isAbsolute() && request.getHttpVersion() != HttpVersion.HTTP_2 ? uri.toString() : uri.getPathQuery();
-+ encoded = uri.getPath();
-+ }
-+
-
-- String encoded = uri.getPath();
- String path;
- if (encoded==null)
- {
-diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java
-index 918a112..22391f7 100644
---- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java
-+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java
-@@ -365,7 +365,7 @@ public class HttpConnectionTest
- public void testBadPathDotDotPath() throws Exception
- {
- String response=connector.getResponse("GET /ooops/../../path HTTP/1.0\r\nHost: localhost:80\r\n\n");
-- checkContains(response,0,"HTTP/1.1 400 Bad URI");
-+ checkContains(response,0,"HTTP/1.1 400");
- }
-
- @Test
-@@ -380,28 +380,28 @@ public class HttpConnectionTest
- public void testBadPathEncodedDotDotPath() throws Exception
- {
- String response=connector.getResponse("GET /ooops/%2e%2e/%2e%2e/path HTTP/1.0\r\nHost: localhost:80\r\n\n");
-- checkContains(response,0,"HTTP/1.1 400 Bad URI");
-+ checkContains(response,0,"HTTP/1.1 400");
- }
-
- @Test
- public void testBadDotDotPath() throws Exception
- {
- String response=connector.getResponse("GET ../path HTTP/1.0\r\nHost: localhost:80\r\n\n");
-- checkContains(response,0,"HTTP/1.1 400 Bad URI");
-+ checkContains(response,0,"HTTP/1.1 400");
- }
-
- @Test
- public void testBadSlashDotDotPath() throws Exception
- {
- String response=connector.getResponse("GET /../path HTTP/1.0\r\nHost: localhost:80\r\n\n");
-- checkContains(response,0,"HTTP/1.1 400 Bad URI");
-+ checkContains(response,0,"HTTP/1.1 400");
- }
-
- @Test
- public void testEncodedBadDotDotPath() throws Exception
- {
- String response=connector.getResponse("GET %2e%2e/path HTTP/1.0\r\nHost: localhost:80\r\n\n");
-- checkContains(response,0,"HTTP/1.1 400 Bad URI");
-+ checkContains(response,0,"HTTP/1.1 400");
- }
-
- @Test
-@@ -1168,7 +1168,7 @@ public class HttpConnectionTest
- "12345\r\n"+
- "0;\r\n" +
- "\r\n");
-- checkContains(response,offset,"HTTP/1.1 400 Bad Request");
-+ checkContains(response,offset,"HTTP/1.1 400");
- }
- catch (Exception e)
- {
diff --git a/CVE-2022-2048.patch b/CVE-2022-2048.patch
deleted file mode 100644
index 42fbca2762365eea0d6ce5b5d7a1da54f154583c..0000000000000000000000000000000000000000
--- a/CVE-2022-2048.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From: Markus Koschany
-Date: Wed, 17 Aug 2022 12:59:00 +0200
-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
-
-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
---- 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
-@@ -143,13 +143,11 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable, Writ
- }
- catch (BadMessageException x)
- {
-- onBadMessage(x);
-- return null;
-+ return () -> onBadMessage(x);
- }
- catch (Throwable x)
- {
-- onBadMessage(new BadMessageException(HttpStatus.INTERNAL_SERVER_ERROR_500, null, x));
-- return null;
-+ return () -> onBadMessage(new BadMessageException(HttpStatus.INTERNAL_SERVER_ERROR_500, null, x));
- }
- }
-
-@@ -175,13 +173,11 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable, Writ
- }
- catch (BadMessageException x)
- {
-- onBadMessage(x);
-- return null;
-+ return () -> onBadMessage(x);
- }
- catch (Throwable x)
- {
-- onBadMessage(new BadMessageException(HttpStatus.INTERNAL_SERVER_ERROR_500, null, x));
-- return null;
-+ return () -> onBadMessage(new BadMessageException(HttpStatus.INTERNAL_SERVER_ERROR_500, null, x));
- }
- }
-
diff --git a/CVE-2023-26048.patch b/CVE-2023-26048.patch
deleted file mode 100644
index e423fa4153d300d5eeb5a921ce148d2bc84ff23f..0000000000000000000000000000000000000000
--- a/CVE-2023-26048.patch
+++ /dev/null
@@ -1,537 +0,0 @@
-From: Markus Koschany
-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 EMPTY_MAP = new MultiMap<>(Collections.emptyMap());
-+ private final MultiMap _parts;
-+ private final int _maxParts;
-+ private int _numParts = 0;
- private InputStream _in;
- private MultipartConfigElement _config;
- private String _contentType;
-- private MultiMap _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 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 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 EMPTY_MAP = new MultiMap(Collections.emptyMap());
-+ public static final MultiMap 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);
diff --git a/CVE-2023-26049.patch b/CVE-2023-26049.patch
deleted file mode 100644
index b11fdc84745b937c575d1e03cfcb8bc53c470419..0000000000000000000000000000000000000000
--- a/CVE-2023-26049.patch
+++ /dev/null
@@ -1,831 +0,0 @@
-From: Markus Koschany
-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 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.
-+ *
-+ * Lenient parsing, input has no spaces after ';' token.
-+ *
-+ */
-+ @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.
-+ *
-+ * Lenient parsing, input has no spaces after ';' token.
-+ *
-+ */
-+ @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 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 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);
diff --git a/CVE-2023-36479.patch b/CVE-2023-36479.patch
deleted file mode 100644
index 898be762e7dc179f95f7a9e48bfa7633918503ca..0000000000000000000000000000000000000000
--- a/CVE-2023-36479.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From: Markus Koschany
-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;
- * ignoreExitState
- * If true then do not act on a non-zero exec exit status")
- *
-+ *
-+ * @deprecated do not use, no replacement, will be removed in a future release.
- */
-+@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 @@
- /dispatch/*
-
-
--
-- CGI
-- org.eclipse.jetty.servlets.CGI
-- 1
--
--
--
-- CGI
-- /cgi-bin/*
--
--
-
- Chat
- com.acme.ChatServlet
diff --git a/CVE-2023-40167.patch b/CVE-2023-40167.patch
deleted file mode 100644
index 9bc23da3a9139ec737071c93b885caf64606c6d0..0000000000000000000000000000000000000000
--- a/CVE-2023-40167.patch
+++ /dev/null
@@ -1,256 +0,0 @@
-From: Markus Koschany
-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() _fields = new ArrayList<>();
-- private List _trailers = new ArrayList<>();
-+ private final List _fields = new ArrayList<>();
-+ private final List _trailers = new ArrayList<>();
- private String[] _hdr;
- private String[] _val;
- private int _headers;
diff --git a/CVE-2024-6762.patch b/CVE-2024-6762.patch
deleted file mode 100644
index 3bae7196e67be30c1999b4f3c359ae35d735693a..0000000000000000000000000000000000000000
--- a/CVE-2024-6762.patch
+++ /dev/null
@@ -1,60 +0,0 @@
-From c9fb33ab85959921ff3183311587af02772dda89 Mon Sep 17 00:00:00 2001
-From: Lachlan Roberts
-Date: Mon, 1 May 2023 14:40:35 +1000
-Subject: [PATCH 1/2] deprecate PushSessionCacheFilter
-
-Signed-off-by: Lachlan Roberts
----
- .../java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java
-index 4fa0ea1028cb..9950dce98bda 100644
---- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java
-+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java
-@@ -41,6 +41,7 @@
- import org.eclipse.jetty.util.log.Log;
- import org.eclipse.jetty.util.log.Logger;
-
-+@Deprecated
- public class PushSessionCacheFilter implements Filter
- {
- private static final String TARGET_ATTR = "PushCacheFilter.target";
-
-From 2588cedddca989b6b96e6954ae6e8fc8f3e1c487 Mon Sep 17 00:00:00 2001
-From: Lachlan Roberts
-Date: Tue, 2 May 2023 12:02:12 +1000
-Subject: [PATCH 2/2] update javadoc and add log warning message for
- PushSessionCacheFilter
-
-Signed-off-by: Lachlan Roberts
----
- .../eclipse/jetty/servlets/PushSessionCacheFilter.java | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java
-index 9950dce98bda..81b85cb2b85e 100644
---- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java
-+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/PushSessionCacheFilter.java
-@@ -41,6 +41,9 @@
- import org.eclipse.jetty.util.log.Log;
- import org.eclipse.jetty.util.log.Logger;
-
-+/**
-+ * @deprecated no replacement for this deprecated http feature
-+ */
- @Deprecated
- public class PushSessionCacheFilter implements Filter
- {
-@@ -50,6 +53,11 @@ public class PushSessionCacheFilter implements Filter
- private final ConcurrentMap _cache = new ConcurrentHashMap<>();
- private long _associateDelay = 5000L;
-
-+ public PushSessionCacheFilter()
-+ {
-+ LOG.warn(PushSessionCacheFilter.class.getSimpleName() + " is an example class not suitable for production.");
-+ }
-+
- @Override
- public void init(FilterConfig config) throws ServletException
- {
diff --git a/README.en.md b/README.en.md
deleted file mode 100644
index a53c4f009bc5192b462f7390044c75c8050ee96e..0000000000000000000000000000000000000000
--- a/README.en.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# jetty
-
-#### Description
-{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
-
-#### Software Architecture
-Software architecture description
-
-#### Installation
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Instructions
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Contribution
-
-1. Fork the repository
-2. Create Feat_xxx branch
-3. Commit your code
-4. Create Pull Request
-
-
-#### Gitee Feature
-
-1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
-2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
-3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
-4. The most valuable open source project [GVP](https://gitee.com/gvp)
-5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
-6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
diff --git a/README.md b/README.md
deleted file mode 100644
index 55676973371fdb93abc782b06dd70d5cf8c858b6..0000000000000000000000000000000000000000
--- a/README.md
+++ /dev/null
@@ -1,39 +0,0 @@
-# jetty
-
-#### 介绍
-{**以下是码云平台说明,您可以替换此简介**
-码云是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台
-无论是个人、团队、或是企业,都能够用码云实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
-
-#### 软件架构
-软件架构说明
-
-
-#### 安装教程
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### 使用说明
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### 参与贡献
-
-1. Fork 本仓库
-2. 新建 Feat_xxx 分支
-3. 提交代码
-4. 新建 Pull Request
-
-
-#### 码云特技
-
-1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
-2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com)
-3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目
-4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目
-5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
-6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
diff --git a/jetty-9.4.16.v20190411.tar.gz b/jetty-9.4.40.v20210413.tar.gz
similarity index 68%
rename from jetty-9.4.16.v20190411.tar.gz
rename to jetty-9.4.40.v20210413.tar.gz
index 0e76c17d4f0a6952b3fa1360e1483f3f8fee9925..6d63985260de2624dd43d02c09e52a3bdb59f4a8 100644
Binary files a/jetty-9.4.16.v20190411.tar.gz and b/jetty-9.4.40.v20210413.tar.gz differ
diff --git a/jetty.spec b/jetty.spec
index e54216488373c3e47aea187ad3dbb02ebd802be7..5d45f8f0def6592fab568d56baec6cc5cb14f7d7 100644
--- a/jetty.spec
+++ b/jetty.spec
@@ -1,3 +1,33 @@
+# Copyright (c) 2000-2007, JPackage Project
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the
+# distribution.
+# 3. Neither the name of the JPackage Project nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
%global jtuid 110
%global username %{name}
%global confdir %{_sysconfdir}/%{name}
@@ -8,146 +38,219 @@
%global rundir %{_localstatedir}/run/%{name}
%global jettylibdir %{_localstatedir}/lib/%{name}
%global appdir %{jettylibdir}/webapps
-%global addver .v20190411
-%bcond_with jp_minimal
-Name: jetty
-Version: 9.4.16
-Release: 8
-Summary: Java Webserver and Servlet Container
-License: Apache-2.0 OR EPL-1.0
-URL: http://www.eclipse.org/jetty/
-Source0: https://github.com/eclipse/%{name}.project/archive/%{name}-%{version}%{addver}.tar.gz
-Source1: jetty.sh
-Source3: jetty.logrotate
-Source5: %{name}.service
-Source6: LICENSE-MIT
-Patch0: CVE-2020-27216.patch
-Patch1: CVE-2020-27223.patch
-Patch2: CVE-2021-28165.patch
-Patch3: CVE-2021-28169.patch
-Patch4: CVE-2021-34428.patch
-Patch5: CVE-2022-2047.patch
-Patch6: CVE-2022-2048.patch
-Patch7: CVE-2023-26048.patch
-Patch8: CVE-2023-26049.patch
-Patch9: CVE-2023-36479.patch
-Patch10: CVE-2023-40167.patch
-Patch11: CVE-2024-6762.patch
-
-BuildRequires: maven-local mvn(javax.servlet:javax.servlet-api) < 4.0.0
-BuildRequires: mvn(org.apache.felix:maven-bundle-plugin)
-BuildRequires: mvn(org.apache.maven.plugins:maven-shade-plugin)
-BuildRequires: mvn(org.codehaus.mojo:build-helper-maven-plugin) mvn(org.slf4j:slf4j-api)
+
+
+%global addver .v20210413
+
+# minimal version required to build eclipse and thermostat
+# eclipse needs: util, server, http, continuation, io, security, servlet
+# thermostat needs: server, jaas, webapp
+# above modules need: jmx, xml
+%bcond_without jp_minimal
+
+Name: jetty
+Version: 9.4.40
+Release: 13%{?dist}
+Summary: Java Webserver and Servlet Container
+
+# Jetty is dual licensed under both ASL 2.0 and EPL 1.0, see NOTICE.txt
+License: ASL 2.0 or EPL-1.0
+URL: http://www.eclipse.org/jetty/
+Source0: https://github.com/eclipse/%{name}.project/archive/%{name}-%{version}%{addver}.tar.gz
+Source1: jetty.sh
+Source3: jetty.logrotate
+Source5: %{name}.service
+# MIT license text taken from Utf8Appendable.java
+Source6: LICENSE-MIT
+
+Patch1: 0001-Distro-jetty.home.patch
+Patch2: 0002-Port-to-servlet-api-4-5.patch
+
+BuildRequires: maven-local
+BuildRequires: mvn(javax.servlet:javax.servlet-api)
+BuildRequires: mvn(org.apache.felix:maven-bundle-plugin)
+BuildRequires: mvn(org.apache.maven.plugins:maven-shade-plugin)
+BuildRequires: mvn(org.codehaus.mojo:build-helper-maven-plugin)
+BuildRequires: mvn(org.slf4j:slf4j-api)
+
%if %{without jp_minimal}
-BuildRequires: maven-local mvn(com.github.jnr:jnr-unixsocket)
-BuildRequires: mvn(javax.annotation:javax.annotation-api) mvn(javax.enterprise:cdi-api)
-BuildRequires: mvn(javax.servlet:javax.servlet-api) < 4.0.0
-BuildRequires: mvn(javax.servlet.jsp:javax.servlet.jsp-api) mvn(javax.servlet:jstl)
-BuildRequires: mvn(javax.transaction:javax.transaction-api)
-BuildRequires: mvn(javax.websocket:javax.websocket-api)
-BuildRequires: mvn(javax.websocket:javax.websocket-client-api) mvn(org.apache.ant:ant)
-BuildRequires: mvn(org.apache.ant:ant-launcher) mvn(org.apache.felix:maven-bundle-plugin)
-BuildRequires: mvn(org.apache.maven:maven-artifact) mvn(org.apache.maven:maven-core)
-BuildRequires: mvn(org.apache.maven:maven-plugin-api) mvn(org.apache.maven:maven-project)
-BuildRequires: mvn(org.apache.maven.plugins:maven-antrun-plugin)
-BuildRequires: mvn(org.apache.maven.plugins:maven-assembly-plugin)
-BuildRequires: mvn(org.apache.maven.plugins:maven-dependency-plugin)
-BuildRequires: mvn(org.apache.maven.plugins:maven-failsafe-plugin)
-BuildRequires: mvn(org.apache.maven.plugins:maven-plugin-plugin)
-BuildRequires: mvn(org.apache.maven.plugins:maven-remote-resources-plugin)
-BuildRequires: mvn(org.apache.maven.plugins:maven-shade-plugin)
-BuildRequires: mvn(org.apache.maven.plugins:maven-war-plugin)
-BuildRequires: mvn(org.apache.maven.plugin-tools:maven-plugin-annotations)
-BuildRequires: mvn(org.apache.maven.plugin-tools:maven-plugin-tools-api)
-BuildRequires: mvn(org.apache.maven.shared:maven-artifact-transfer)
-BuildRequires: mvn(org.apache.taglibs:taglibs-standard-impl)
-BuildRequires: mvn(org.apache.taglibs:taglibs-standard-spec)
-BuildRequires: mvn(org.apache.tomcat:tomcat-jasper)
-BuildRequires: mvn(org.codehaus.mojo:build-helper-maven-plugin)
-BuildRequires: mvn(org.codehaus.mojo:exec-maven-plugin) mvn(org.eclipse.equinox.http:servlet)
-BuildRequires: mvn(org.eclipse.jetty.alpn:alpn-api)
-BuildRequires: mvn(org.eclipse.jetty.orbit:javax.mail.glassfish)
-BuildRequires: mvn(org.eclipse.jetty.orbit:javax.security.auth.message)
-BuildRequires: mvn(org.eclipse.jetty.toolchain:jetty-assembly-descriptors)
-BuildRequires: mvn(org.eclipse.jetty.toolchain:jetty-schemas)
-BuildRequires: mvn(org.eclipse.jetty.toolchain:jetty-test-helper)
-BuildRequires: mvn(org.eclipse.osgi:org.eclipse.osgi)
-BuildRequires: mvn(org.eclipse.osgi:org.eclipse.osgi.services)
-BuildRequires: mvn(org.infinispan:infinispan-core)
-BuildRequires: mvn(org.jboss.weld.servlet:weld-servlet-core)
-BuildRequires: mvn(org.mongodb:mongo-java-driver) mvn(org.ow2.asm:asm)
-BuildRequires: mvn(org.ow2.asm:asm-commons) mvn(org.slf4j:slf4j-api)
-BuildRequires: mvn(org.springframework:spring-beans)
-BuildRequires: java-1.8.0-openjdk-headless java-1.8.0-openjdk
-BuildRequires: mvn(org.eclipse.jetty.toolchain:jetty-artifact-remote-resources)
-BuildRequires: mvn(org.eclipse.jetty.toolchain:jetty-distribution-remote-resources)
-BuildRequires: mvn(org.eclipse.jetty.toolchain:jetty-test-policy) maven-javadoc-plugin
-BuildRequires: glassfish-el systemd junit5
-BuildRequires: jboss-websocket-1.0-api
-Requires: jboss-websocket-1.0-api
-Requires: java-1.8.0-openjdk-headless
-Requires: glassfish-servlet-api < 4.0.0
-%endif # without jp_minimal
-BuildArch: noarch
+BuildRequires: maven-local
+BuildRequires: mvn(com.github.jnr:jnr-unixsocket)
+BuildRequires: mvn(javax.annotation:javax.annotation-api)
+BuildRequires: mvn(javax.enterprise:cdi-api)
+BuildRequires: mvn(javax.servlet:javax.servlet-api)
+BuildRequires: mvn(javax.servlet.jsp:javax.servlet.jsp-api)
+BuildRequires: mvn(javax.servlet:jstl)
+BuildRequires: mvn(javax.transaction:javax.transaction-api)
+BuildRequires: mvn(javax.websocket:javax.websocket-api)
+BuildRequires: mvn(javax.websocket:javax.websocket-client-api)
+BuildRequires: mvn(org.apache.ant:ant)
+BuildRequires: mvn(org.apache.ant:ant-launcher)
+BuildRequires: mvn(org.apache.felix:maven-bundle-plugin)
+BuildRequires: mvn(org.apache.maven:maven-artifact)
+BuildRequires: mvn(org.apache.maven:maven-core)
+BuildRequires: mvn(org.apache.maven:maven-plugin-api)
+BuildRequires: mvn(org.apache.maven:maven-project)
+BuildRequires: mvn(org.apache.maven.plugins:maven-antrun-plugin)
+BuildRequires: mvn(org.apache.maven.plugins:maven-assembly-plugin)
+BuildRequires: mvn(org.apache.maven.plugins:maven-dependency-plugin)
+BuildRequires: mvn(org.apache.maven.plugins:maven-failsafe-plugin)
+BuildRequires: mvn(org.apache.maven.plugins:maven-plugin-plugin)
+BuildRequires: mvn(org.apache.maven.plugins:maven-remote-resources-plugin)
+BuildRequires: mvn(org.apache.maven.plugins:maven-shade-plugin)
+BuildRequires: mvn(org.apache.maven.plugins:maven-war-plugin)
+BuildRequires: mvn(org.apache.maven.plugin-tools:maven-plugin-annotations)
+BuildRequires: mvn(org.apache.maven.plugin-tools:maven-plugin-tools-api)
+BuildRequires: mvn(org.apache.maven.shared:maven-artifact-transfer)
+BuildRequires: mvn(org.apache.taglibs:taglibs-standard-impl)
+BuildRequires: mvn(org.apache.taglibs:taglibs-standard-spec)
+BuildRequires: mvn(org.apache.tomcat:tomcat-jasper)
+BuildRequires: mvn(org.codehaus.mojo:build-helper-maven-plugin)
+BuildRequires: mvn(org.codehaus.mojo:exec-maven-plugin)
+BuildRequires: mvn(org.eclipse.jetty.alpn:alpn-api)
+BuildRequires: mvn(org.eclipse.jetty.orbit:javax.mail.glassfish)
+BuildRequires: mvn(org.eclipse.jetty.orbit:javax.security.auth.message)
+BuildRequires: mvn(org.eclipse.jetty.toolchain:jetty-assembly-descriptors)
+BuildRequires: mvn(org.eclipse.jetty.toolchain:jetty-schemas)
+BuildRequires: mvn(org.eclipse.jetty.toolchain:jetty-test-helper)
+BuildRequires: mvn(org.jboss.weld.servlet:weld-servlet-core)
+BuildRequires: mvn(org.mongodb:mongo-java-driver)
+BuildRequires: mvn(org.ow2.asm:asm)
+BuildRequires: mvn(org.ow2.asm:asm-commons)
+BuildRequires: mvn(org.slf4j:slf4j-api)
+
+BuildRequires: mvn(org.mortbay.jetty.alpn:alpn-boot)
+BuildRequires: mvn(org.eclipse.jetty.toolchain:jetty-artifact-remote-resources)
+BuildRequires: mvn(org.eclipse.jetty.toolchain:jetty-distribution-remote-resources)
+BuildRequires: mvn(org.eclipse.jetty.toolchain:jetty-test-policy)
+#BuildRequires: mvn(org.eclipse.jetty.toolchain.setuid:jetty-setuid-java)
+BuildRequires: maven-javadoc-plugin
+BuildRequires: glassfish-el
+BuildRequires: systemd
+BuildRequires: junit5
+
+# duplicate providers, choose one
+BuildRequires: jboss-websocket-1.0-api
+Requires: jboss-websocket-1.0-api
+%endif
+
+BuildArch: noarch
+ExclusiveArch: %{java_arches} noarch loongarch64 aarch64 x86_64
+
+# jp_minimal doesn't have main package
%if %{without jp_minimal}
-Requires: javapackages-tools %{name}-annotations = %{version}-%{release}
-Requires: %{name}-ant = %{version}-%{release} %{name}-client = %{version}-%{release}
-Requires: %{name}-continuation = %{version}-%{release}
-Requires: %{name}-deploy = %{version}-%{release}
-Requires: %{name}-fcgi-client = %{version}-%{release}
-Requires: %{name}-fcgi-server = %{version}-%{release}
-Requires: %{name}-http = %{version}-%{release} %{name}-http-spi = %{version}-%{release}
-Requires: %{name}-io = %{version}-%{release} %{name}-jaas = %{version}-%{release}
-Requires: %{name}-jaspi = %{version}-%{release} %{name}-jmx = %{version}-%{release}
-Requires: %{name}-jndi = %{version}-%{release} %{name}-jsp = %{version}-%{release}
-Requires: %{name}-jspc-maven-plugin = %{version}-%{release}
-Requires: %{name}-maven-plugin = %{version}-%{release}
-Requires: %{name}-plus = %{version}-%{release} %{name}-proxy = %{version}-%{release}
-Requires: %{name}-rewrite = %{version}-%{release}
-Requires: %{name}-security = %{version}-%{release} %{name}-server = %{version}-%{release}
-Requires: %{name}-servlet = %{version}-%{release}
-Requires: %{name}-servlets = %{version}-%{release} %{name}-spring = %{version}-%{release}
-Requires: %{name}-start = %{version}-%{release}
-Requires: %{name}-unixsocket = %{version}-%{release} %{name}-util = %{version}-%{release}
-Requires: %{name}-util-ajax = %{version}-%{release}
-Requires: %{name}-webapp = %{version}-%{release} %{name}-xml = %{version}-%{release}
-Requires: %{name}-infinispan = %{version}-%{release} %{name}-cdi = %{version}-%{release}
-Requires: %{name}-websocket-api = %{version}-%{release}
-Requires: %{name}-websocket-client = %{version}-%{release}
-Requires: %{name}-websocket-common = %{version}-%{release}
-Requires: %{name}-websocket-server = %{version}-%{release}
-Requires: %{name}-websocket-servlet = %{version}-%{release}
-Requires: %{name}-javax-websocket-client-impl = %{version}-%{release}
-Requires: %{name}-javax-websocket-server-impl = %{version}-%{release}
-Requires: %{name}-nosql = %{version}-%{release}
-Requires: %{name}-httpservice = %{version}-%{release}
-Requires: %{name}-osgi-boot = %{version}-%{release}
-Requires: %{name}-osgi-boot-warurl = %{version}-%{release}
-Requires: %{name}-osgi-boot-jsp = %{version}-%{release}
-Requires: %{name}-osgi-alpn = %{version}-%{release}
-Requires: %{name}-quickstart = %{version}-%{release} %{name}-jstl = %{version}-%{release}
-Requires: %{name}-alpn-client = %{version}-%{release}
-Requires: %{name}-alpn-server = %{version}-%{release}
-Requires: %{name}-http2-client = %{version}-%{release}
-Requires: %{name}-http2-common = %{version}-%{release}
-Requires: %{name}-http2-hpack = %{version}-%{release}
-Requires: %{name}-http2-http-client-transport = %{version}-%{release}
-Requires: %{name}-http2-server = %{version}-%{release}
+# Explicit requires for javapackages-tools since jetty.sh script
+# uses /usr/share/java-utils/java-functions
+Requires: javapackages-tools
+Requires: %{name}-annotations = %{version}-%{release}
+Requires: %{name}-ant = %{version}-%{release}
+Requires: %{name}-client = %{version}-%{release}
+Requires: %{name}-continuation = %{version}-%{release}
+Requires: %{name}-deploy = %{version}-%{release}
+Requires: %{name}-fcgi-client = %{version}-%{release}
+Requires: %{name}-fcgi-server = %{version}-%{release}
+Requires: %{name}-http = %{version}-%{release}
+Requires: %{name}-http-spi = %{version}-%{release}
+Requires: %{name}-io = %{version}-%{release}
+Requires: %{name}-jaas = %{version}-%{release}
+Requires: %{name}-jaspi = %{version}-%{release}
+Requires: %{name}-jmx = %{version}-%{release}
+Requires: %{name}-jndi = %{version}-%{release}
+Requires: %{name}-jsp = %{version}-%{release}
+Requires: %{name}-jspc-maven-plugin = %{version}-%{release}
+Requires: %{name}-maven-plugin = %{version}-%{release}
+Requires: %{name}-plus = %{version}-%{release}
+Requires: %{name}-proxy = %{version}-%{release}
+Requires: %{name}-rewrite = %{version}-%{release}
+Requires: %{name}-security = %{version}-%{release}
+Requires: %{name}-server = %{version}-%{release}
+Requires: %{name}-servlet = %{version}-%{release}
+Requires: %{name}-servlets = %{version}-%{release}
+Requires: %{name}-start = %{version}-%{release}
+Requires: %{name}-unixsocket = %{version}-%{release}
+Requires: %{name}-util = %{version}-%{release}
+Requires: %{name}-util-ajax = %{version}-%{release}
+Requires: %{name}-webapp = %{version}-%{release}
+Requires: %{name}-xml = %{version}-%{release}
+Requires: %{name}-cdi = %{version}-%{release}
+Requires: %{name}-websocket-api = %{version}-%{release}
+Requires: %{name}-websocket-client = %{version}-%{release}
+Requires: %{name}-websocket-common = %{version}-%{release}
+Requires: %{name}-websocket-server = %{version}-%{release}
+Requires: %{name}-websocket-servlet = %{version}-%{release}
+Requires: %{name}-javax-websocket-client-impl = %{version}-%{release}
+Requires: %{name}-javax-websocket-server-impl = %{version}-%{release}
+Requires: %{name}-nosql = %{version}-%{release}
+Requires: %{name}-quickstart = %{version}-%{release}
+Requires: %{name}-jstl = %{version}-%{release}
+Requires: %{name}-alpn-client = %{version}-%{release}
+Requires: %{name}-alpn-server = %{version}-%{release}
+Requires: %{name}-http2-client = %{version}-%{release}
+Requires: %{name}-http2-common = %{version}-%{release}
+Requires: %{name}-http2-hpack = %{version}-%{release}
+Requires: %{name}-http2-http-client-transport = %{version}-%{release}
+Requires: %{name}-http2-server = %{version}-%{release}
+
Requires(pre): shadow-utils
%{?systemd_ordering}
-Provides: group(%username) = %jtuid
-Provides: user(%username) = %jtuid
-%endif # without jp_minimal
-Obsoletes: %{name}-manual < 9.4.0-0.4
-Obsoletes: %{name}-ajp < 9.4.0-0.4
-Obsoletes: %{name}-nested < 9.4.0-0.4
-Obsoletes: %{name}-overlay-deployer < 9.4.0-0.4
-Obsoletes: %{name}-policy < 9.4.0-0.4
-Obsoletes: %{name}-websocket-mux-extension < 9.4.0-0.4
-Obsoletes: %{name}-runner < 9.4.0-0.4
-Obsoletes: %{name}-osgi-npn < 9.4.0-0.4
-Obsoletes: %{name}-monitor < 9.4.0-0.4
-Obsoletes: %{name}-hazelcast < 9.4.14-1
+
+
+Provides: group(%username) = %jtuid
+Provides: user(%username) = %jtuid
+%endif
+
+# Hazelcast in Fedora is too old for jetty to build against (Added in F29)
+Obsoletes: %{name}-hazelcast < 9.4.18-1
+# Infinispan in Fedora is too old for jetty to build against (Added in F31)
+Obsoletes: %{name}-infinispan < 9.4.18-1
+# Eclipse no longer available (Added in F31)
+Obsoletes: %{name}-osgi-alpn < 9.4.18-1
+Obsoletes: %{name}-osgi-boot < 9.4.18-1
+Obsoletes: %{name}-osgi-boot-jsp < 9.4.18-1
+Obsoletes: %{name}-osgi-boot-warurl < 9.4.18-1
+# Spring framework removed from Fedora (Added in F32)
+Obsoletes: %{name}-spring < 9.4.24-1
+
+%if %{with jp_minimal}
+# Remove left-over packages that would have broken deps when built in minimal mode
+Obsoletes: %{name}-project < 9.4.20-1
+Obsoletes: %{name}-annotations < 9.4.20-1
+Obsoletes: %{name}-ant < 9.4.20-1
+Obsoletes: %{name}-cdi < 9.4.20-1
+Obsoletes: %{name}-deploy < 9.4.20-1
+Obsoletes: %{name}-fcgi-client < 9.4.20-1
+Obsoletes: %{name}-fcgi-server < 9.4.20-1
+Obsoletes: %{name}-http-spi < 9.4.20-1
+Obsoletes: %{name}-jaspi < 9.4.20-1
+Obsoletes: %{name}-jndi < 9.4.20-1
+Obsoletes: %{name}-jsp < 9.4.20-1
+Obsoletes: %{name}-jstl < 9.4.20-1
+Obsoletes: %{name}-jspc-maven-plugin < 9.4.20-1
+Obsoletes: %{name}-maven-plugin < 9.4.20-1
+Obsoletes: %{name}-plus < 9.4.20-1
+Obsoletes: %{name}-proxy < 9.4.20-1
+Obsoletes: %{name}-quickstart < 9.4.20-1
+Obsoletes: %{name}-rewrite < 9.4.20-1
+Obsoletes: %{name}-servlets < 9.4.20-1
+Obsoletes: %{name}-start < 9.4.20-1
+Obsoletes: %{name}-unixsocket < 9.4.20-1
+Obsoletes: %{name}-websocket-api < 9.4.20-1
+Obsoletes: %{name}-websocket-client < 9.4.20-1
+Obsoletes: %{name}-websocket-common < 9.4.20-1
+Obsoletes: %{name}-websocket-server < 9.4.20-1
+Obsoletes: %{name}-websocket-servlet < 9.4.20-1
+Obsoletes: %{name}-javax-websocket-client-impl < 9.4.20-1
+Obsoletes: %{name}-javax-websocket-server-impl < 9.4.20-1
+Obsoletes: %{name}-alpn-client < 9.4.20-1
+Obsoletes: %{name}-alpn-server < 9.4.20-1
+Obsoletes: %{name}-http2-client < 9.4.20-1
+Obsoletes: %{name}-http2-common < 9.4.20-1
+Obsoletes: %{name}-http2-hpack < 9.4.20-1
+Obsoletes: %{name}-http2-http-client-transport < 9.4.20-1
+Obsoletes: %{name}-http2-server < 9.4.20-1
+Obsoletes: %{name}-nosql < 9.4.20-1
+%endif
+
%description
%global desc \
Jetty is a 100% Java HTTP Server and Servlet Container. This means that you\
@@ -164,317 +267,337 @@ Jetty is available on all Java supported platforms.
\
This package contains
+# packages in jp_minimal set
%package client
-Summary: client module for Jetty
+Summary: client module for Jetty
+
%description client
%{extdesc} %{summary}.
%package continuation
-Summary: continuation module for Jetty
+Summary: continuation module for Jetty
+
%description continuation
%{extdesc} %{summary}.
%package http
-Summary: http module for Jetty
+Summary: http module for Jetty
+
%description http
%{extdesc} %{summary}.
%package http-spi
-Summary: http-spi module for Jetty
+Summary: http-spi module for Jetty
+
%description http-spi
%{extdesc} %{summary}.
%package io
-Summary: io module for Jetty
-Obsoletes: %{name}-websocket < 9.4.0-0.4
+Summary: io module for Jetty
+
%description io
%{extdesc} %{summary}.
%package jaas
-Summary: jaas module for Jetty
+Summary: jaas module for Jetty
+
%description jaas
%{extdesc} %{summary}.
%package jsp
-Summary: jsp module for Jetty
-Requires: glassfish-el
-Requires: glassfish-servlet-api < 4.0.0
+Summary: jsp module for Jetty
+Requires: glassfish-el
+
%description jsp
%{extdesc} %{summary}.
%package security
-Summary: security module for Jetty
+Summary: security module for Jetty
+
%description security
%{extdesc} %{summary}.
%package server
-Summary: server module for Jetty
-Requires: glassfish-servlet-api < 4.0.0
+Summary: server module for Jetty
+
%description server
%{extdesc} %{summary}.
%package servlet
-Summary: servlet module for Jetty
+Summary: servlet module for Jetty
+# Eclipse no longer available (Added in F31)
+Obsoletes: %{name}-httpservice < 9.4.18-1
+
%description servlet
%{extdesc} %{summary}.
%package util
-Summary: util module for Jetty
-License: (Apache-2.0 OR EPL-1.0) AND MIT
+Summary: util module for Jetty
+# Utf8Appendable.java is additionally under MIT license
+License: (ASL 2.0 or EPL-1.0) and MIT
+
%description util
%{extdesc} %{summary}.
+%package util-ajax
+Summary: util-ajax module for Jetty
+
+%description util-ajax
+%{extdesc} %{summary}.
+
%package webapp
-Summary: webapp module for Jetty
+Summary: webapp module for Jetty
+
%description webapp
%{extdesc} %{summary}.
%package jmx
-Summary: jmx module for Jetty
+Summary: jmx module for Jetty
+
%description jmx
%{extdesc} %{summary}.
%package xml
-Summary: xml module for Jetty
+Summary: xml module for Jetty
+
%description xml
%{extdesc} %{summary}.
-%if %{without jp_minimal}
+
+
+%if %{without jp_minimal}
%package project
-Summary: POM files for Jetty
-Obsoletes: %{name}-websocket-parent < 9.4.0-0.4
-Provides: %{name}-websocket-parent = %{version}-%{release}
-Obsoletes: %{name}-osgi-project < 9.4.0-0.4
-Provides: %{name}-osgi-project = %{version}-%{release}
+Summary: POM files for Jetty
+Obsoletes: %{name}-websocket-parent < 9.4.0-0.4
+Provides: %{name}-websocket-parent = %{version}-%{release}
+Obsoletes: %{name}-osgi-project < 9.4.0-0.4
+Provides: %{name}-osgi-project = %{version}-%{release}
+
%description project
%{extdesc} %{summary}.
%package deploy
-Summary: deploy module for Jetty
+Summary: deploy module for Jetty
+
%description deploy
%{extdesc} %{summary}.
%package annotations
-Summary: annotations module for Jetty
+Summary: annotations module for Jetty
+
%description annotations
%{extdesc} %{summary}.
%package ant
-Summary: ant module for Jetty
+Summary: ant module for Jetty
+
%description ant
%{extdesc} %{summary}.
%package cdi
-Summary: Jetty CDI Configuration
+Summary: Jetty CDI Configuration
+
%description cdi
%{extdesc} %{summary}.
%package fcgi-client
-Summary: FastCGI client module for Jetty
+Summary: FastCGI client module for Jetty
+
%description fcgi-client
%{extdesc} %{summary}.
%package fcgi-server
-Summary: FastCGI client module for Jetty
-Requires: glassfish-servlet-api < 4.0.0
-%description fcgi-server
-%{extdesc} %{summary}.
+Summary: FastCGI client module for Jetty
-%package infinispan
-Summary: infinispan module for Jetty
-%description infinispan
+%description fcgi-server
%{extdesc} %{summary}.
%package jaspi
-Summary: jaspi module for Jetty
+Summary: jaspi module for Jetty
+
%description jaspi
%{extdesc} %{summary}.
%package jndi
-Summary: jndi module for Jetty
+Summary: jndi module for Jetty
+
%description jndi
%{extdesc} %{summary}.
%package jspc-maven-plugin
-Summary: jspc-maven-plugin module for Jetty
+Summary: jspc-maven-plugin module for Jetty
+
%description jspc-maven-plugin
%{extdesc} %{summary}.
%package maven-plugin
-Summary: maven-plugin module for Jetty
+Summary: maven-plugin module for Jetty
+
%description maven-plugin
%{extdesc} %{summary}.
%package plus
-Summary: plus module for Jetty
+Summary: plus module for Jetty
+
%description plus
%{extdesc} %{summary}.
%package proxy
-Summary: proxy module for Jetty
+Summary: proxy module for Jetty
+
%description proxy
%{extdesc} %{summary}.
%package rewrite
-Summary: rewrite module for Jetty
-Requires: glassfish-servlet-api < 4.0.0
+Summary: rewrite module for Jetty
+
%description rewrite
%{extdesc} %{summary}.
%package servlets
-Summary: servlets module for Jetty
-%description servlets
-%{extdesc} %{summary}.
+Summary: servlets module for Jetty
-%package spring
-Summary: spring module for Jetty
-%description spring
+%description servlets
%{extdesc} %{summary}.
%package start
-Summary: start module for Jetty
+Summary: start module for Jetty
+
%description start
%{extdesc} %{summary}.
%package unixsocket
-Summary: unixsocket module for Jetty
-%description unixsocket
-%{extdesc} %{summary}.
+Summary: unixsocket module for Jetty
-%package util-ajax
-Summary: util-ajax module for Jetty
-%description util-ajax
+%description unixsocket
%{extdesc} %{summary}.
%package websocket-api
-Summary: websocket-api module for Jetty
+Summary: websocket-api module for Jetty
+
%description websocket-api
%{extdesc} %{summary}.
%package websocket-client
-Summary: websocket-client module for Jetty
+Summary: websocket-client module for Jetty
+
%description websocket-client
%{extdesc} %{summary}.
%package websocket-common
-Summary: websocket-common module for Jetty
+Summary: websocket-common module for Jetty
+
%description websocket-common
%{extdesc} %{summary}.
%package websocket-server
-Summary: websocket-server module for Jetty
+Summary: websocket-server module for Jetty
+
%description websocket-server
%{extdesc} %{summary}.
%package websocket-servlet
-Summary: websocket-servlet module for Jetty
-Requires: glassfish-servlet-api < 4.0.0
+Summary: websocket-servlet module for Jetty
+
%description websocket-servlet
%{extdesc} %{summary}.
%package javax-websocket-client-impl
-Summary: javax-websocket-client-impl module for Jetty
+Summary: javax-websocket-client-impl module for Jetty
+
%description javax-websocket-client-impl
%{extdesc} %{summary}.
%package javax-websocket-server-impl
-Summary: javax-websocket-server-impl module for Jetty
+Summary: javax-websocket-server-impl module for Jetty
+
%description javax-websocket-server-impl
%{extdesc} %{summary}.
%package nosql
-Summary: nosql module for Jetty
-%description nosql
-%{extdesc} %{summary}.
-
-%package httpservice
-Summary: httpservice module for Jetty
-Requires: glassfish-servlet-api < 4.0.0
-%description httpservice
-%{extdesc} %{summary}.
+Summary: nosql module for Jetty
-%package osgi-boot
-Summary: osgi-boot module for Jetty
-%description osgi-boot
-%{extdesc} %{summary}.
-
-%package osgi-boot-warurl
-Summary: osgi-boot-warurl module for Jetty
-%description osgi-boot-warurl
-%{extdesc} %{summary}.
-
-%package osgi-boot-jsp
-Summary: osgi-boot-jsp module for Jetty
-Requires: glassfish-servlet-api < 4.0.0
-%description osgi-boot-jsp
-%{extdesc} %{summary}.
-
-%package osgi-alpn
-Summary: osgi-alpn module for Jetty
-%description osgi-alpn
+%description nosql
%{extdesc} %{summary}.
%package quickstart
-Summary: quickstart module for Jetty
+Summary: quickstart module for Jetty
+
%description quickstart
%{extdesc} %{summary}.
%package alpn-client
-Summary: alpn-client module for Jetty
+Summary: alpn-client module for Jetty
+
%description alpn-client
%{extdesc} %{summary}.
%package alpn-server
-Summary: alpn-server module for Jetty
+Summary: alpn-server module for Jetty
+
%description alpn-server
%{extdesc} %{summary}.
%package http2-client
-Summary: http2-client module for Jetty
+Summary: http2-client module for Jetty
+
%description http2-client
%{extdesc} %{summary}.
%package http2-common
-Summary: http2-common module for Jetty
+Summary: http2-common module for Jetty
+
%description http2-common
%{extdesc} %{summary}.
%package http2-hpack
-Summary: http2-hpack module for Jetty
+Summary: http2-hpack module for Jetty
+
%description http2-hpack
%{extdesc} %{summary}.
%package http2-http-client-transport
-Summary: http2-http-client-transport module for Jetty
+Summary: http2-http-client-transport module for Jetty
+
%description http2-http-client-transport
%{extdesc} %{summary}.
%package http2-server
-Summary: http2-server module for Jetty
+Summary: http2-server module for Jetty
+
%description http2-server
%{extdesc} %{summary}.
%package jstl
-Summary: jstl module for Jetty
+Summary: jstl module for Jetty
+
%description jstl
%{extdesc} %{summary}.
-%endif # without jp_minimal
-%package javadoc
-Summary: Javadoc for %{name}
-License: (Apache-2.0 OR EPL-1.0) AND MIT
-%description javadoc
+%endif
+
+%package javadoc
+Summary: Javadoc for %{name}
+# some MIT-licensed code (from Utf8Appendable) is used to generate javadoc
+License: (ASL 2.0 or EPL-1.0) and MIT
+
+%description javadoc
%{summary}.
%prep
-%autosetup -n %{name}.project-%{name}-%{version}%{addver} -p1
+%setup -q -n %{name}.project-%{name}-%{version}%{addver}
+
+%patch -P1 -p1
+%patch -P2 -p1
+
find . -name "*.?ar" -exec rm {} \;
find . -name "*.class" -exec rm {} \;
-%pom_remove_plugin -r :findbugs-maven-plugin
+
+# Plugins irrelevant or harmful to building the package
+%pom_remove_plugin -r :maven-checkstyle-plugin
+%pom_remove_plugin -r :spotbugs-maven-plugin
%pom_remove_plugin -r :maven-enforcer-plugin
-%pom_remove_plugin -r :clirr-maven-plugin
%pom_remove_plugin -r :maven-eclipse-plugin
-%pom_remove_plugin -r :maven-pmd-plugin
%pom_remove_plugin -r :license-maven-plugin
%pom_remove_plugin -r :maven-site-plugin
%pom_remove_plugin -r :maven-source-plugin
@@ -483,58 +606,110 @@ find . -name "*.class" -exec rm {} \;
%pom_remove_plugin -r :maven-release-plugin
%pom_remove_plugin -r :buildnumber-maven-plugin
%pom_remove_plugin -r :h2spec-maven-plugin
+
+# Unnecessary pom flattening can be skipped
%pom_remove_plugin -r :flatten-maven-plugin jetty-bom
-%pom_remove_plugin -r :maven-dependency-plugin jetty-http2/http2-http-client-transport
-%pom_remove_plugin -r :maven-dependency-plugin jetty-http2/http2-alpn-tests
-%pom_remove_plugin -r :maven-dependency-plugin tests/test-http-client-transport
-%pom_remove_plugin -r :maven-dependency-plugin tests/test-webapps/test-http2-webapp
+
%pom_disable_module aggregates/jetty-all
-%pom_xpath_replace "pom:groupId[text()='ant']" "org.apache.ant" jetty-ant/pom.xml
+
+# Reflective use of classes that might not be present in the JDK should be optional OSGi-wise
+%pom_xpath_inject "pom:configuration/pom:instructions" \
+"sun.misc;resolution:=optional,com.sun.nio.file;resolution:=optional,*"
+
%pom_remove_dep "com.sun.net.httpserver:http" jetty-http-spi
+
%pom_change_dep -r org.mortbay.jasper:apache-jsp org.apache.tomcat:tomcat-jasper
+
%pom_add_dep 'org.junit.jupiter:junit-jupiter-engine:${junit.version}' tests/test-sessions/test-sessions-common
+
+# provided by glassfish-jsp-api that has newer version
%pom_change_dep -r javax.servlet.jsp:jsp-api javax.servlet.jsp:javax.servlet.jsp-api
+
+# txt artifact - not installable
%pom_remove_plugin ":jetty-version-maven-plugin"
%pom_xpath_remove "pom:artifactItem[pom:classifier='version']" jetty-home
+
+# Disable building source release
%pom_xpath_remove 'pom:execution[pom:id="sources"]' jetty-home
+
+# Unwanted JS in javadoc
sed -i '/^\s*\*.*