CVE-2019-10241
CVE-2019-10241
This commit is contained in:
parent
17e1bc4acb
commit
3bea1bc93f
446
CVE-2020-27216.patch
Normal file → Executable file
446
CVE-2020-27216.patch
Normal file → Executable file
@ -1,22 +1,17 @@
|
||||
From 53e0e0e9b25a6309bf24ee3b10984f4145701edb Mon Sep 17 00:00:00 2001
|
||||
From: Joakim Erdfelt <joakim.erdfelt@gmail.com>
|
||||
Date: Thu, 15 Oct 2020 17:39:30 -0500
|
||||
Subject: [PATCH] Merge pull request from GHSA-g3wg-6mcf-8jj6
|
||||
From: Markus Koschany <apo@debian.org>
|
||||
Date: Sat, 3 Jul 2021 22:05:57 +0200
|
||||
Subject: CVE-2020-27216
|
||||
|
||||
* Issue #5451 - Improving temp directory creation.
|
||||
|
||||
+ Using new Files.createTempDirectory() instead
|
||||
of nonsense around File.createTempFile()
|
||||
|
||||
Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
|
||||
|
||||
* Fixes #5451 - Restoring File.deleteOnExit
|
||||
Origin: https://github.com/eclipse/jetty.project/commit/53e0e0e9b25a6309bf24ee3b10984f4145701edb
|
||||
Origin: https://github.com/eclipse/jetty.project/commit/9ad6beb80543b392c91653f6bfce233fc75b9d5f
|
||||
---
|
||||
.../jetty/webapp/WebInfConfiguration.java | 20 +++++++------------
|
||||
1 file changed, 7 insertions(+), 13 deletions(-)
|
||||
.../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..f39432d 100644
|
||||
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;
|
||||
@ -60,6 +55,423 @@ index b94f788..f39432d 100644
|
||||
}
|
||||
configureTempDirectory(tmpDir, context);
|
||||
|
||||
--
|
||||
2.23.0
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1,545 +0,0 @@
|
||||
From 8011c48685e78850a88e7cc06650f678a375037d Mon Sep 17 00:00:00 2001
|
||||
From: Greg Wilkins <gregw@webtide.com>
|
||||
Date: Thu, 28 Feb 2019 18:37:02 +1100
|
||||
Subject: [PATCH 1/4] Issue #3404 Updated QCSV Double usage
|
||||
|
||||
Signed-off-by: Greg Wilkins <gregw@webtide.com>
|
||||
---
|
||||
.../eclipse/jetty/http/QuotedQualityCSV.java | 58 ++++++++++---------
|
||||
1 file changed, 30 insertions(+), 28 deletions(-)
|
||||
|
||||
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 61cee88bfd5..c7047c57a4b 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
|
||||
@@ -25,6 +25,8 @@
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
+import org.eclipse.jetty.util.log.Log;
|
||||
+
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Implements a quoted comma separated list of quality values
|
||||
@@ -37,21 +39,16 @@
|
||||
*/
|
||||
public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
|
||||
{
|
||||
- private final static Double ZERO=new Double(0.0);
|
||||
- private final static Double ONE=new Double(1.0);
|
||||
-
|
||||
+ private final static Double ZERO = 0.0D;
|
||||
+ private final static Double ONE = 1.0D;
|
||||
|
||||
/**
|
||||
- * Function to apply a most specific MIME encoding secondary ordering
|
||||
+ * Lambda to apply a most specific MIME encoding secondary ordering
|
||||
*/
|
||||
- public static Function<String, Integer> MOST_SPECIFIC = new Function<String, Integer>()
|
||||
+ public static Function<String, Integer> MOST_SPECIFIC = s ->
|
||||
{
|
||||
- @Override
|
||||
- public Integer apply(String s)
|
||||
- {
|
||||
- String[] elements = s.split("/");
|
||||
- return 1000000*elements.length+1000*elements[0].length()+elements[elements.length-1].length();
|
||||
- }
|
||||
+ String[] elements = s.split("/");
|
||||
+ return 1000000*elements.length+1000*elements[0].length()+elements[elements.length-1].length();
|
||||
};
|
||||
|
||||
private final List<Double> _quality = new ArrayList<>();
|
||||
@@ -74,7 +71,8 @@ public QuotedQualityCSV()
|
||||
*/
|
||||
public QuotedQualityCSV(String[] preferredOrder)
|
||||
{
|
||||
- this((s) -> {
|
||||
+ this((s) ->
|
||||
+ {
|
||||
for (int i=0;i<preferredOrder.length;++i)
|
||||
if (preferredOrder[i].equals(s))
|
||||
return preferredOrder.length-i;
|
||||
@@ -101,6 +99,8 @@ public QuotedQualityCSV(Function<String, Integer> secondaryOrdering)
|
||||
protected void parsedValue(StringBuffer buffer)
|
||||
{
|
||||
super.parsedValue(buffer);
|
||||
+
|
||||
+ // Assume a quality of ONE
|
||||
_quality.add(ONE);
|
||||
}
|
||||
|
||||
@@ -108,30 +108,32 @@ protected void parsedValue(StringBuffer buffer)
|
||||
@Override
|
||||
protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
|
||||
{
|
||||
- if (paramName<0)
|
||||
+ if (paramName < 0)
|
||||
{
|
||||
- if (buffer.charAt(buffer.length()-1)==';')
|
||||
- buffer.setLength(buffer.length()-1);
|
||||
+ 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)=='=')
|
||||
+ else if (paramValue >= 0 &&
|
||||
+ buffer.charAt(paramName) == 'q' && paramValue > paramName &&
|
||||
+ buffer.length() >= paramName && buffer.charAt(paramName + 1) == '=')
|
||||
{
|
||||
Double q;
|
||||
try
|
||||
{
|
||||
- q=(_keepQuotes && buffer.charAt(paramValue)=='"')
|
||||
- ?new Double(buffer.substring(paramValue+1,buffer.length()-1))
|
||||
- :new Double(buffer.substring(paramValue));
|
||||
+ q = (_keepQuotes && buffer.charAt(paramValue) == '"')
|
||||
+ ? Double.valueOf(buffer.substring(paramValue + 1, buffer.length() - 1))
|
||||
+ : Double.valueOf(buffer.substring(paramValue));
|
||||
}
|
||||
- catch(Exception e)
|
||||
+ catch (Exception e)
|
||||
{
|
||||
- q=ZERO;
|
||||
- }
|
||||
- buffer.setLength(Math.max(0,paramName-1));
|
||||
-
|
||||
- if (!ONE.equals(q))
|
||||
- _quality.set(_quality.size()-1,q);
|
||||
+ Log.getLogger(QuotedQualityCSV.class).ignore(e);
|
||||
+ q = ZERO;
|
||||
+ }
|
||||
+ buffer.setLength(Math.max(0, paramName - 1));
|
||||
+
|
||||
+ if (!ONE.equals(q))
|
||||
+ // replace assumed quality
|
||||
+ _quality.set(_quality.size() - 1, q);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
From ca8a10a9d5a50e7d814c65134144f776bff1c07a Mon Sep 17 00:00:00 2001
|
||||
From: Greg Wilkins <gregw@webtide.com>
|
||||
Date: Fri, 1 Mar 2019 10:17:02 +1100
|
||||
Subject: [PATCH 2/4] Issue #3404 Cleanup QCSV mime ordering
|
||||
|
||||
Signed-off-by: Greg Wilkins <gregw@webtide.com>
|
||||
---
|
||||
.../org/eclipse/jetty/http/HttpFields.java | 16 ++++++++-
|
||||
.../eclipse/jetty/http/QuotedQualityCSV.java | 35 ++++++++++---------
|
||||
.../jetty/http/QuotedQualityCSVTest.java | 2 +-
|
||||
.../jetty/server/handler/ErrorHandler.java | 3 +-
|
||||
4 files changed, 37 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
|
||||
index 14c4335eb5a..5a8b53013a7 100644
|
||||
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
|
||||
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
|
||||
@@ -31,6 +31,7 @@
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
+import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
@@ -437,6 +438,19 @@ protected String addCSV(QuotedCSV existing,String... values)
|
||||
* @param header The header
|
||||
*/
|
||||
public List<String> getQualityCSV(HttpHeader header)
|
||||
+ {
|
||||
+ return getQualityCSV(header,null);
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Get multiple field values of the same name, split and
|
||||
+ * sorted as a {@link QuotedQualityCSV}
|
||||
+ *
|
||||
+ * @param header The header
|
||||
+ * @param secondaryOrdering Function to apply an ordering other than specified by quality
|
||||
+ * @return List the values in quality order with the q param and OWS stripped
|
||||
+ */
|
||||
+ public List<String> getQualityCSV(HttpHeader header, Function<String, Integer> secondaryOrdering)
|
||||
{
|
||||
QuotedQualityCSV values = null;
|
||||
for (HttpField f : this)
|
||||
@@ -444,7 +458,7 @@ protected String addCSV(QuotedCSV existing,String... values)
|
||||
if (f.getHeader()==header)
|
||||
{
|
||||
if (values==null)
|
||||
- values = new QuotedQualityCSV();
|
||||
+ values = new QuotedQualityCSV(secondaryOrdering);
|
||||
values.addValue(f.getValue());
|
||||
}
|
||||
}
|
||||
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 c7047c57a4b..498d4e01491 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
|
||||
@@ -38,17 +38,20 @@
|
||||
* @see "https://tools.ietf.org/html/rfc7231#section-5.3.1"
|
||||
*/
|
||||
public class QuotedQualityCSV extends QuotedCSV implements Iterable<String>
|
||||
-{
|
||||
- private final static Double ZERO = 0.0D;
|
||||
- private final static Double ONE = 1.0D;
|
||||
-
|
||||
+{
|
||||
/**
|
||||
- * Lambda to apply a most specific MIME encoding secondary ordering
|
||||
+ * Lambda to apply a most specific MIME encoding secondary ordering.
|
||||
+ * @see "https://tools.ietf.org/html/rfc7231#section-5.3.2"
|
||||
*/
|
||||
- public static Function<String, Integer> MOST_SPECIFIC = s ->
|
||||
+ public static Function<String, Integer> MOST_SPECIFIC_MIME_ORDERING = s ->
|
||||
{
|
||||
- String[] elements = s.split("/");
|
||||
- return 1000000*elements.length+1000*elements[0].length()+elements[elements.length-1].length();
|
||||
+ if ("*/*".equals(s))
|
||||
+ return 0;
|
||||
+ if (s.endsWith("/*"))
|
||||
+ return 1;
|
||||
+ if (s.indexOf(';')<0)
|
||||
+ return 2;
|
||||
+ return 3;
|
||||
};
|
||||
|
||||
private final List<Double> _quality = new ArrayList<>();
|
||||
@@ -61,7 +64,7 @@
|
||||
*/
|
||||
public QuotedQualityCSV()
|
||||
{
|
||||
- this((s) -> 0);
|
||||
+ this((Function)null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@@ -91,7 +94,7 @@ public QuotedQualityCSV(String[] preferredOrder)
|
||||
*/
|
||||
public QuotedQualityCSV(Function<String, Integer> secondaryOrdering)
|
||||
{
|
||||
- this._secondaryOrdering = secondaryOrdering;
|
||||
+ this._secondaryOrdering = secondaryOrdering == null ? s->0 : secondaryOrdering;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@@ -101,7 +104,7 @@ protected void parsedValue(StringBuffer buffer)
|
||||
super.parsedValue(buffer);
|
||||
|
||||
// Assume a quality of ONE
|
||||
- _quality.add(ONE);
|
||||
+ _quality.add(1.0D);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@@ -127,11 +130,11 @@ else if (paramValue >= 0 &&
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.getLogger(QuotedQualityCSV.class).ignore(e);
|
||||
- q = ZERO;
|
||||
+ q = 0.0D;
|
||||
}
|
||||
buffer.setLength(Math.max(0, paramName - 1));
|
||||
|
||||
- if (!ONE.equals(q))
|
||||
+ if (!((Double)1.0D).equals(q))
|
||||
// replace assumed quality
|
||||
_quality.set(_quality.size() - 1, q);
|
||||
}
|
||||
@@ -157,7 +160,7 @@ protected void sort()
|
||||
{
|
||||
_sorted=true;
|
||||
|
||||
- Double last = ZERO;
|
||||
+ Double last = 0.0D;
|
||||
int lastSecondaryOrder = Integer.MIN_VALUE;
|
||||
|
||||
for (int i = _values.size(); i-- > 0;)
|
||||
@@ -172,7 +175,7 @@ protected void sort()
|
||||
_values.set(i + 1, v);
|
||||
_quality.set(i, _quality.get(i + 1));
|
||||
_quality.set(i + 1, q);
|
||||
- last = ZERO;
|
||||
+ last = 0.0D;
|
||||
lastSecondaryOrder=0;
|
||||
i = _values.size();
|
||||
continue;
|
||||
@@ -183,7 +186,7 @@ protected void sort()
|
||||
}
|
||||
|
||||
int last_element=_quality.size();
|
||||
- while(last_element>0 && _quality.get(--last_element).equals(ZERO))
|
||||
+ while(last_element>0 && _quality.get(--last_element).equals(0.0D))
|
||||
{
|
||||
_quality.remove(last_element);
|
||||
_values.remove(last_element);
|
||||
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 ba0db4a8972..f03657ba3e5 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
|
||||
@@ -61,7 +61,7 @@ public void test7231_5_3_2_example3()
|
||||
@Test
|
||||
public void test7231_5_3_2_example3_most_specific()
|
||||
{
|
||||
- QuotedQualityCSV values = new QuotedQualityCSV(QuotedQualityCSV.MOST_SPECIFIC);
|
||||
+ 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/*","*/*"));
|
||||
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
|
||||
index 84088146cd3..2820dca3a0c 100644
|
||||
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
|
||||
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
|
||||
@@ -38,6 +38,7 @@
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
+import org.eclipse.jetty.http.QuotedQualityCSV;
|
||||
import org.eclipse.jetty.server.Dispatcher;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
@@ -159,7 +160,7 @@ else if (old_error_page!=null && old_error_page.equals(error_page))
|
||||
protected void generateAcceptableResponse(Request baseRequest, HttpServletRequest request, HttpServletResponse response, int code, String message)
|
||||
throws IOException
|
||||
{
|
||||
- List<String> acceptable=baseRequest.getHttpFields().getQualityCSV(HttpHeader.ACCEPT);
|
||||
+ List<String> acceptable=baseRequest.getHttpFields().getQualityCSV(HttpHeader.ACCEPT, QuotedQualityCSV.MOST_SPECIFIC_MIME_ORDERING);
|
||||
|
||||
if (acceptable.isEmpty() && !baseRequest.getHttpFields().contains(HttpHeader.ACCEPT))
|
||||
{
|
||||
|
||||
From b925380ede948ab7d8757e95a0ce384b2441625b Mon Sep 17 00:00:00 2001
|
||||
From: Greg Wilkins <gregw@webtide.com>
|
||||
Date: Fri, 1 Mar 2019 10:20:10 +1100
|
||||
Subject: [PATCH 3/4] Issue #3404 Updated QCSV Double usage
|
||||
|
||||
Signed-off-by: Greg Wilkins <gregw@webtide.com>
|
||||
---
|
||||
.../src/main/java/org/eclipse/jetty/http/QuotedQualityCSV.java | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
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 498d4e01491..a7407d34199 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
|
||||
@@ -134,7 +134,7 @@ else if (paramValue >= 0 &&
|
||||
}
|
||||
buffer.setLength(Math.max(0, paramName - 1));
|
||||
|
||||
- if (!((Double)1.0D).equals(q))
|
||||
+ if (q!=1.0D)
|
||||
// replace assumed quality
|
||||
_quality.set(_quality.size() - 1, q);
|
||||
}
|
||||
|
||||
From 69f6b3b6164228485744918a28ab6a0d4c3facae Mon Sep 17 00:00:00 2001
|
||||
From: Greg Wilkins <gregw@webtide.com>
|
||||
Date: Tue, 5 Mar 2019 08:59:55 +1100
|
||||
Subject: [PATCH 4/4] Issue #3404
|
||||
|
||||
updates after review:
|
||||
+ use ToIntFunction
|
||||
+ reformat
|
||||
|
||||
Signed-off-by: Greg Wilkins <gregw@webtide.com>
|
||||
---
|
||||
.../org/eclipse/jetty/http/HttpFields.java | 4 +-
|
||||
.../eclipse/jetty/http/QuotedQualityCSV.java | 62 +++++++++++--------
|
||||
2 files changed, 37 insertions(+), 29 deletions(-)
|
||||
|
||||
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
|
||||
index 5a8b53013a7..395b87bde35 100644
|
||||
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
|
||||
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
|
||||
@@ -31,7 +31,7 @@
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
-import java.util.function.Function;
|
||||
+import java.util.function.ToIntFunction;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
@@ -450,7 +450,7 @@ protected String addCSV(QuotedCSV existing,String... values)
|
||||
* @param secondaryOrdering Function to apply an ordering other than specified by quality
|
||||
* @return List the values in quality order with the q param and OWS stripped
|
||||
*/
|
||||
- public List<String> getQualityCSV(HttpHeader header, Function<String, Integer> secondaryOrdering)
|
||||
+ public List<String> getQualityCSV(HttpHeader header, ToIntFunction<String> secondaryOrdering)
|
||||
{
|
||||
QuotedQualityCSV values = null;
|
||||
for (HttpField f : this)
|
||||
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 a7407d34199..d148d9e65e1 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
|
||||
@@ -18,21 +18,23 @@
|
||||
|
||||
package org.eclipse.jetty.http;
|
||||
|
||||
-import static java.lang.Integer.MIN_VALUE;
|
||||
-
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
-import java.util.function.Function;
|
||||
+import java.util.function.ToIntFunction;
|
||||
|
||||
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.
|
||||
- * Values are returned sorted in quality order, with OWS and the
|
||||
+ * Values are returned sorted in quality order, with OWS and the
|
||||
* quality parameters removed.
|
||||
+ *
|
||||
* @see "https://tools.ietf.org/html/rfc7230#section-3.2.6"
|
||||
* @see "https://tools.ietf.org/html/rfc7230#section-7"
|
||||
* @see "https://tools.ietf.org/html/rfc7231#section-5.3.1"
|
||||
@@ -41,44 +43,48 @@
|
||||
{
|
||||
/**
|
||||
* Lambda to apply a most specific MIME encoding secondary ordering.
|
||||
+ *
|
||||
* @see "https://tools.ietf.org/html/rfc7231#section-5.3.2"
|
||||
*/
|
||||
- public static Function<String, Integer> MOST_SPECIFIC_MIME_ORDERING = s ->
|
||||
+ public static ToIntFunction<String> MOST_SPECIFIC_MIME_ORDERING = s ->
|
||||
{
|
||||
if ("*/*".equals(s))
|
||||
return 0;
|
||||
if (s.endsWith("/*"))
|
||||
return 1;
|
||||
- if (s.indexOf(';')<0)
|
||||
+ if (s.indexOf(';') < 0)
|
||||
return 2;
|
||||
return 3;
|
||||
};
|
||||
-
|
||||
+
|
||||
private final List<Double> _quality = new ArrayList<>();
|
||||
private boolean _sorted = false;
|
||||
- private final Function<String, Integer> _secondaryOrdering;
|
||||
-
|
||||
+ private final ToIntFunction<String> _secondaryOrdering;
|
||||
+
|
||||
/* ------------------------------------------------------------ */
|
||||
+
|
||||
/**
|
||||
* Sorts values with equal quality according to the length of the value String.
|
||||
*/
|
||||
public QuotedQualityCSV()
|
||||
{
|
||||
- this((Function)null);
|
||||
+ this((ToIntFunction)null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
+
|
||||
/**
|
||||
* Sorts values with equal quality according to given order.
|
||||
+ *
|
||||
* @param preferredOrder Array indicating the preferred order of known values
|
||||
*/
|
||||
public QuotedQualityCSV(String[] preferredOrder)
|
||||
{
|
||||
this((s) ->
|
||||
{
|
||||
- for (int i=0;i<preferredOrder.length;++i)
|
||||
+ for (int i = 0; i < preferredOrder.length; ++i)
|
||||
if (preferredOrder[i].equals(s))
|
||||
- return preferredOrder.length-i;
|
||||
+ return preferredOrder.length - i;
|
||||
|
||||
if ("*".equals(s))
|
||||
return preferredOrder.length;
|
||||
@@ -88,15 +94,17 @@ public QuotedQualityCSV(String[] preferredOrder)
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
+
|
||||
/**
|
||||
* Orders values with equal quality with the given function.
|
||||
+ *
|
||||
* @param secondaryOrdering Function to apply an ordering other than specified by quality
|
||||
*/
|
||||
- public QuotedQualityCSV(Function<String, Integer> secondaryOrdering)
|
||||
+ public QuotedQualityCSV(ToIntFunction<String> secondaryOrdering)
|
||||
{
|
||||
- this._secondaryOrdering = secondaryOrdering == null ? s->0 : secondaryOrdering;
|
||||
+ this._secondaryOrdering = secondaryOrdering == null ? s -> 0 : secondaryOrdering;
|
||||
}
|
||||
-
|
||||
+
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
protected void parsedValue(StringBuffer buffer)
|
||||
@@ -134,7 +142,7 @@ else if (paramValue >= 0 &&
|
||||
}
|
||||
buffer.setLength(Math.max(0, paramName - 1));
|
||||
|
||||
- if (q!=1.0D)
|
||||
+ if (q != 1.0D)
|
||||
// replace assumed quality
|
||||
_quality.set(_quality.size() - 1, q);
|
||||
}
|
||||
@@ -147,7 +155,7 @@ else if (paramValue >= 0 &&
|
||||
sort();
|
||||
return _values;
|
||||
}
|
||||
-
|
||||
+
|
||||
@Override
|
||||
public Iterator<String> iterator()
|
||||
{
|
||||
@@ -158,35 +166,35 @@ else if (paramValue >= 0 &&
|
||||
|
||||
protected void sort()
|
||||
{
|
||||
- _sorted=true;
|
||||
+ _sorted = true;
|
||||
|
||||
Double last = 0.0D;
|
||||
int lastSecondaryOrder = Integer.MIN_VALUE;
|
||||
|
||||
- for (int i = _values.size(); i-- > 0;)
|
||||
+ for (int i = _values.size(); i-- > 0; )
|
||||
{
|
||||
String v = _values.get(i);
|
||||
Double q = _quality.get(i);
|
||||
|
||||
- int compare=last.compareTo(q);
|
||||
- if (compare>0 || (compare==0 && _secondaryOrdering.apply(v)<lastSecondaryOrder))
|
||||
+ int compare = last.compareTo(q);
|
||||
+ if (compare > 0 || (compare == 0 && _secondaryOrdering.applyAsInt(v) < lastSecondaryOrder))
|
||||
{
|
||||
_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;
|
||||
+ lastSecondaryOrder = 0;
|
||||
i = _values.size();
|
||||
continue;
|
||||
}
|
||||
|
||||
- last=q;
|
||||
- lastSecondaryOrder=_secondaryOrdering.apply(v);
|
||||
+ last = q;
|
||||
+ lastSecondaryOrder = _secondaryOrdering.applyAsInt(v);
|
||||
}
|
||||
-
|
||||
- int last_element=_quality.size();
|
||||
- while(last_element>0 && _quality.get(--last_element).equals(0.0D))
|
||||
+
|
||||
+ int last_element = _quality.size();
|
||||
+ while (last_element > 0 && _quality.get(--last_element).equals(0.0D))
|
||||
{
|
||||
_quality.remove(last_element);
|
||||
_values.remove(last_element);
|
||||
@ -1,692 +0,0 @@
|
||||
From 05072b34dce43064e87ad0d59065f14666c1f34e Mon Sep 17 00:00:00 2001
|
||||
From: Greg Wilkins <gregw@webtide.com>
|
||||
Date: Wed, 8 May 2019 13:28:16 +0200
|
||||
Subject: [PATCH] Issue #3630 Forwarded-Port
|
||||
|
||||
Added support for the X-Forwarded-Port header.
|
||||
Reimplemented header scanning using more efficient Trie and MethodHandles
|
||||
|
||||
Signed-off-by: Greg Wilkins <gregw@webtide.com>
|
||||
---
|
||||
.../eclipse/jetty/http/HostPortHttpField.java | 13 +
|
||||
.../org/eclipse/jetty/http/HttpHeader.java | 1 +
|
||||
.../main/config/etc/jetty-http-forwarded.xml | 1 +
|
||||
.../main/config/modules/http-forwarded.mod | 1 +
|
||||
.../server/ForwardedRequestCustomizer.java | 274 +++++++++++++-----
|
||||
.../ForwardedRequestCustomizerTest.java | 27 +-
|
||||
.../java/org/eclipse/jetty/util/HostPort.java | 30 +-
|
||||
.../org/eclipse/jetty/util/HostPortTest.java | 13 +-
|
||||
8 files changed, 269 insertions(+), 91 deletions(-)
|
||||
|
||||
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java
|
||||
index 215c353b4b9..dc386665339 100644
|
||||
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java
|
||||
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HostPortHttpField.java
|
||||
@@ -49,6 +49,19 @@ protected HostPortHttpField(HttpHeader header, String name, String authority)
|
||||
}
|
||||
}
|
||||
|
||||
+ /* ------------------------------------------------------------ */
|
||||
+ public HostPortHttpField(String host, int port)
|
||||
+ {
|
||||
+ this(new HostPort(host, port));
|
||||
+ }
|
||||
+
|
||||
+ /* ------------------------------------------------------------ */
|
||||
+ protected HostPortHttpField(HostPort hostport)
|
||||
+ {
|
||||
+ super(HttpHeader.HOST,HttpHeader.HOST.asString(),hostport.toString());
|
||||
+ _hostPort = hostport;
|
||||
+ }
|
||||
+
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the host.
|
||||
* @return the host
|
||||
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java
|
||||
index f39c0f7df98..ac6bf2be8da 100644
|
||||
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java
|
||||
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java
|
||||
@@ -82,6 +82,7 @@
|
||||
TE("TE"),
|
||||
USER_AGENT("User-Agent"),
|
||||
X_FORWARDED_FOR("X-Forwarded-For"),
|
||||
+ X_FORWARDED_PORT("X-Forwarded-Port"),
|
||||
X_FORWARDED_PROTO("X-Forwarded-Proto"),
|
||||
X_FORWARDED_SERVER("X-Forwarded-Server"),
|
||||
X_FORWARDED_HOST("X-Forwarded-Host"),
|
||||
diff --git a/jetty-server/src/main/config/etc/jetty-http-forwarded.xml b/jetty-server/src/main/config/etc/jetty-http-forwarded.xml
|
||||
index 50b80976a2a..648d6c6a94f 100644
|
||||
--- a/jetty-server/src/main/config/etc/jetty-http-forwarded.xml
|
||||
+++ b/jetty-server/src/main/config/etc/jetty-http-forwarded.xml
|
||||
@@ -11,6 +11,7 @@
|
||||
<Set name="forwardedServerHeader"><Property name="jetty.httpConfig.forwardedServerHeader" default="X-Forwarded-Server"/></Set>
|
||||
<Set name="forwardedProtoHeader"><Property name="jetty.httpConfig.forwardedProtoHeader" default="X-Forwarded-Proto"/></Set>
|
||||
<Set name="forwardedForHeader"><Property name="jetty.httpConfig.forwardedForHeader" default="X-Forwarded-For"/></Set>
|
||||
+ <Set name="forwardedPortHeader"><Property name="jetty.httpConfig.forwardedPortHeader" default="X-Forwarded-Port"/></Set>
|
||||
<Set name="forwardedHttpsHeader"><Property name="jetty.httpConfig.forwardedHttpsHeader" default="X-Proxied-Https"/></Set>
|
||||
<Set name="forwardedSslSessionIdHeader"><Property name="jetty.httpConfig.forwardedSslSessionIdHeader" default="Proxy-ssl-id" /></Set>
|
||||
<Set name="forwardedCipherSuiteHeader"><Property name="jetty.httpConfig.forwardedCipherSuiteHeader" default="Proxy-auth-cert"/></Set>
|
||||
diff --git a/jetty-server/src/main/config/modules/http-forwarded.mod b/jetty-server/src/main/config/modules/http-forwarded.mod
|
||||
index 34e25642b2c..f67822065a4 100644
|
||||
--- a/jetty-server/src/main/config/modules/http-forwarded.mod
|
||||
+++ b/jetty-server/src/main/config/modules/http-forwarded.mod
|
||||
@@ -23,6 +23,7 @@ etc/jetty-http-forwarded.xml
|
||||
# jetty.httpConfig.forwardedServerHeader=X-Forwarded-Server
|
||||
# jetty.httpConfig.forwardedProtoHeader=X-Forwarded-Proto
|
||||
# jetty.httpConfig.forwardedForHeader=X-Forwarded-For
|
||||
+# jetty.httpConfig.forwardedPortHeader=X-Forwarded-Port
|
||||
# jetty.httpConfig.forwardedHttpsHeader=X-Proxied-Https
|
||||
# jetty.httpConfig.forwardedSslSessionIdHeader=Proxy-ssl-id
|
||||
# jetty.httpConfig.forwardedCipherSuiteHeader=Proxy-auth-cert
|
||||
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
|
||||
index f2ffe24fb85..1e64892cbe9 100644
|
||||
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
|
||||
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
+import java.lang.invoke.MethodHandle;
|
||||
+import java.lang.invoke.MethodHandles;
|
||||
+import java.lang.invoke.MethodType;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
@@ -29,11 +32,15 @@
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.http.QuotedCSV;
|
||||
import org.eclipse.jetty.server.HttpConfiguration.Customizer;
|
||||
+import org.eclipse.jetty.util.ArrayTrie;
|
||||
import org.eclipse.jetty.util.HostPort;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
+import org.eclipse.jetty.util.Trie;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
+import static java.lang.invoke.MethodType.methodType;
|
||||
+
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Customize Requests for Proxy Forwarding.
|
||||
@@ -63,14 +70,21 @@
|
||||
private String _forwardedHeader = HttpHeader.FORWARDED.toString();
|
||||
private String _forwardedHostHeader = HttpHeader.X_FORWARDED_HOST.toString();
|
||||
private String _forwardedServerHeader = HttpHeader.X_FORWARDED_SERVER.toString();
|
||||
- private String _forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString();
|
||||
private String _forwardedProtoHeader = HttpHeader.X_FORWARDED_PROTO.toString();
|
||||
+ private String _forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString();
|
||||
+ private String _forwardedPortHeader = HttpHeader.X_FORWARDED_PORT.toString();
|
||||
private String _forwardedHttpsHeader = "X-Proxied-Https";
|
||||
private String _forwardedCipherSuiteHeader = "Proxy-auth-cert";
|
||||
private String _forwardedSslSessionIdHeader = "Proxy-ssl-id";
|
||||
private boolean _proxyAsAuthority=false;
|
||||
private boolean _sslIsSecure=true;
|
||||
-
|
||||
+ private Trie <MethodHandle> _handles;
|
||||
+
|
||||
+ public ForwardedRequestCustomizer()
|
||||
+ {
|
||||
+ updateHandles();
|
||||
+ }
|
||||
+
|
||||
/**
|
||||
* @return true if the proxy address obtained via
|
||||
* {@code X-Forwarded-Server} or RFC7239 "by" is used as
|
||||
@@ -103,9 +117,9 @@ public void setForwardedOnly(boolean rfc7239only)
|
||||
if (_forwardedHeader==null)
|
||||
_forwardedHeader=HttpHeader.FORWARDED.toString();
|
||||
_forwardedHostHeader=null;
|
||||
- _forwardedHostHeader=null;
|
||||
_forwardedServerHeader=null;
|
||||
_forwardedForHeader=null;
|
||||
+ _forwardedPortHeader=null;
|
||||
_forwardedProtoHeader=null;
|
||||
_forwardedHttpsHeader=null;
|
||||
}
|
||||
@@ -117,11 +131,15 @@ public void setForwardedOnly(boolean rfc7239only)
|
||||
_forwardedServerHeader = HttpHeader.X_FORWARDED_SERVER.toString();
|
||||
if (_forwardedForHeader==null)
|
||||
_forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString();
|
||||
+ if (_forwardedPortHeader==null)
|
||||
+ _forwardedPortHeader = HttpHeader.X_FORWARDED_PORT.toString();
|
||||
if (_forwardedProtoHeader==null)
|
||||
_forwardedProtoHeader = HttpHeader.X_FORWARDED_PROTO.toString();
|
||||
if (_forwardedHttpsHeader==null)
|
||||
_forwardedHttpsHeader = "X-Proxied-Https";
|
||||
}
|
||||
+
|
||||
+ updateHandles();
|
||||
}
|
||||
|
||||
public String getForcedHost()
|
||||
@@ -138,6 +156,7 @@ public String getForcedHost()
|
||||
public void setForcedHost(String hostAndPort)
|
||||
{
|
||||
_forcedHost = new HostPortHttpField(hostAndPort);
|
||||
+ updateHandles();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,6 +174,7 @@ public String getForwardedHeader()
|
||||
public void setForwardedHeader(String forwardedHeader)
|
||||
{
|
||||
_forwardedHeader = forwardedHeader;
|
||||
+ updateHandles();
|
||||
}
|
||||
|
||||
public String getForwardedHostHeader()
|
||||
@@ -169,6 +189,7 @@ public String getForwardedHostHeader()
|
||||
public void setForwardedHostHeader(String forwardedHostHeader)
|
||||
{
|
||||
_forwardedHostHeader = forwardedHostHeader;
|
||||
+ updateHandles();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,6 +207,7 @@ public String getForwardedServerHeader()
|
||||
public void setForwardedServerHeader(String forwardedServerHeader)
|
||||
{
|
||||
_forwardedServerHeader = forwardedServerHeader;
|
||||
+ updateHandles();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,6 +225,22 @@ public String getForwardedForHeader()
|
||||
public void setForwardedForHeader(String forwardedRemoteAddressHeader)
|
||||
{
|
||||
_forwardedForHeader = forwardedRemoteAddressHeader;
|
||||
+ updateHandles();
|
||||
+ }
|
||||
+
|
||||
+ public String getForwardedPortHeader()
|
||||
+ {
|
||||
+ return _forwardedHostHeader;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * @param forwardedPortHeader
|
||||
+ * The header name for forwarded hosts (default {@code X-Forwarded-Port})
|
||||
+ */
|
||||
+ public void setForwardedPortHeader(String forwardedPortHeader)
|
||||
+ {
|
||||
+ _forwardedHostHeader = forwardedPortHeader;
|
||||
+ updateHandles();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,6 +262,7 @@ public String getForwardedProtoHeader()
|
||||
public void setForwardedProtoHeader(String forwardedProtoHeader)
|
||||
{
|
||||
_forwardedProtoHeader = forwardedProtoHeader;
|
||||
+ updateHandles();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,6 +280,7 @@ public String getForwardedCipherSuiteHeader()
|
||||
public void setForwardedCipherSuiteHeader(String forwardedCipherSuite)
|
||||
{
|
||||
_forwardedCipherSuiteHeader = forwardedCipherSuite;
|
||||
+ updateHandles();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,6 +298,7 @@ public String getForwardedSslSessionIdHeader()
|
||||
public void setForwardedSslSessionIdHeader(String forwardedSslSessionId)
|
||||
{
|
||||
_forwardedSslSessionIdHeader = forwardedSslSessionId;
|
||||
+ updateHandles();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,6 +315,7 @@ public String getForwardedHttpsHeader()
|
||||
public void setForwardedHttpsHeader(String forwardedHttpsHeader)
|
||||
{
|
||||
_forwardedHttpsHeader = forwardedHttpsHeader;
|
||||
+ updateHandles();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,118 +341,84 @@ public void customize(Connector connector, HttpConfiguration config, Request req
|
||||
{
|
||||
HttpFields httpFields = request.getHttpFields();
|
||||
|
||||
- RFC7239 rfc7239 = null;
|
||||
- String forwardedHost = null;
|
||||
- String forwardedServer = null;
|
||||
- HostPort forwardedFor = null;
|
||||
- String forwardedProto = null;
|
||||
- String forwardedHttps = null;
|
||||
-
|
||||
// Do a single pass through the header fields as it is a more efficient single iteration.
|
||||
- for (HttpField field : httpFields)
|
||||
+ Forwarded forwarded = new Forwarded(request, config);
|
||||
+ try
|
||||
{
|
||||
- String name = field.getName();
|
||||
-
|
||||
- if (getForwardedCipherSuiteHeader()!=null && getForwardedCipherSuiteHeader().equalsIgnoreCase(name))
|
||||
+ for (HttpField field : httpFields)
|
||||
{
|
||||
- request.setAttribute("javax.servlet.request.cipher_suite",field.getValue());
|
||||
- if (isSslIsSecure())
|
||||
- {
|
||||
- request.setSecure(true);
|
||||
- request.setScheme(config.getSecureScheme());
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (getForwardedSslSessionIdHeader()!=null && getForwardedSslSessionIdHeader().equalsIgnoreCase(name))
|
||||
- {
|
||||
- request.setAttribute("javax.servlet.request.ssl_session_id", field.getValue());
|
||||
- if (isSslIsSecure())
|
||||
- {
|
||||
- request.setSecure(true);
|
||||
- request.setScheme(config.getSecureScheme());
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (forwardedHost==null && _forwardedHostHeader!=null && _forwardedHostHeader.equalsIgnoreCase(name))
|
||||
- forwardedHost = getLeftMost(field.getValue());
|
||||
-
|
||||
- if (forwardedServer==null && _forwardedServerHeader!=null && _forwardedServerHeader.equalsIgnoreCase(name))
|
||||
- forwardedServer = getLeftMost(field.getValue());
|
||||
-
|
||||
- if (forwardedFor==null && _forwardedForHeader!=null && _forwardedForHeader.equalsIgnoreCase(name))
|
||||
- forwardedFor = getRemoteAddr(field.getValue());
|
||||
-
|
||||
- if (forwardedProto==null && _forwardedProtoHeader!=null && _forwardedProtoHeader.equalsIgnoreCase(name))
|
||||
- forwardedProto = getLeftMost(field.getValue());
|
||||
-
|
||||
- if (forwardedHttps==null && _forwardedHttpsHeader!=null && _forwardedHttpsHeader.equalsIgnoreCase(name))
|
||||
- forwardedHttps = getLeftMost(field.getValue());
|
||||
-
|
||||
- if (_forwardedHeader!=null && _forwardedHeader.equalsIgnoreCase(name))
|
||||
- {
|
||||
- if (rfc7239==null)
|
||||
- rfc7239= new RFC7239();
|
||||
- rfc7239.addValue(field.getValue());
|
||||
+ MethodHandle handle = _handles.get(field.getName());
|
||||
+ if (handle != null)
|
||||
+ handle.invoke(forwarded, field);
|
||||
}
|
||||
}
|
||||
-
|
||||
- // Handle host header if if not available any RFC7230.by or X-ForwardedServer header
|
||||
+ catch (Throwable e)
|
||||
+ {
|
||||
+ throw new RuntimeException(e);
|
||||
+ }
|
||||
+
|
||||
+ // Determine host
|
||||
if (_forcedHost != null)
|
||||
{
|
||||
// Update host header
|
||||
httpFields.put(_forcedHost);
|
||||
request.setAuthority(_forcedHost.getHost(),_forcedHost.getPort());
|
||||
}
|
||||
- else if (rfc7239!=null && rfc7239._host!=null)
|
||||
+ else if (forwarded._rfc7239!=null && forwarded._rfc7239._host!=null)
|
||||
{
|
||||
- HostPortHttpField auth = rfc7239._host;
|
||||
+ HostPortHttpField auth = forwarded._rfc7239._host;
|
||||
httpFields.put(auth);
|
||||
request.setAuthority(auth.getHost(),auth.getPort());
|
||||
}
|
||||
- else if (forwardedHost != null)
|
||||
+ else if (forwarded._forwardedHost != null)
|
||||
{
|
||||
- HostPortHttpField auth = new HostPortHttpField(forwardedHost);
|
||||
+ HostPortHttpField auth = new HostPortHttpField(forwarded._forwardedHost);
|
||||
httpFields.put(auth);
|
||||
- request.setAuthority(auth.getHost(),auth.getPort());
|
||||
+ request.setAuthority(auth.getHost(), auth.getPort());
|
||||
}
|
||||
else if (_proxyAsAuthority)
|
||||
{
|
||||
- if (rfc7239!=null && rfc7239._by!=null)
|
||||
+ if (forwarded._rfc7239!=null && forwarded._rfc7239._by!=null)
|
||||
{
|
||||
- HostPortHttpField auth = rfc7239._by;
|
||||
+ HostPortHttpField auth = forwarded._rfc7239._by;
|
||||
httpFields.put(auth);
|
||||
request.setAuthority(auth.getHost(),auth.getPort());
|
||||
}
|
||||
- else if (forwardedServer != null)
|
||||
+ else if (forwarded._forwardedServer != null)
|
||||
{
|
||||
- request.setAuthority(forwardedServer,request.getServerPort());
|
||||
+ request.setAuthority(forwarded._forwardedServer,request.getServerPort());
|
||||
}
|
||||
}
|
||||
|
||||
// handle remote end identifier
|
||||
- if (rfc7239!=null && rfc7239._for!=null)
|
||||
+ if (forwarded._rfc7239!=null && forwarded._rfc7239._for!=null)
|
||||
{
|
||||
- request.setRemoteAddr(InetSocketAddress.createUnresolved(rfc7239._for.getHost(),rfc7239._for.getPort()));
|
||||
+ request.setRemoteAddr(InetSocketAddress.createUnresolved(forwarded._rfc7239._for.getHost(),forwarded._rfc7239._for.getPort()));
|
||||
}
|
||||
- else if (forwardedFor != null)
|
||||
+ else if (forwarded._forwardedFor != null)
|
||||
{
|
||||
- request.setRemoteAddr(InetSocketAddress.createUnresolved(forwardedFor.getHost(), (forwardedFor.getPort() > 0) ? forwardedFor.getPort() : request.getRemotePort()));
|
||||
+ int port = (forwarded._forwardedPort>0)
|
||||
+ ? forwarded._forwardedPort
|
||||
+ : (forwarded._forwardedFor.getPort() > 0)
|
||||
+ ? forwarded._forwardedFor.getPort()
|
||||
+ : request.getRemotePort();
|
||||
+ request.setRemoteAddr(InetSocketAddress.createUnresolved(forwarded._forwardedFor.getHost(), port));
|
||||
}
|
||||
|
||||
// handle protocol identifier
|
||||
- if (rfc7239!=null && rfc7239._proto!=null)
|
||||
+ if (forwarded._rfc7239!=null && forwarded._rfc7239._proto!=null)
|
||||
{
|
||||
- request.setScheme(rfc7239._proto);
|
||||
- if (rfc7239._proto.equals(config.getSecureScheme()))
|
||||
+ request.setScheme(forwarded._rfc7239._proto);
|
||||
+ if (forwarded._rfc7239._proto.equals(config.getSecureScheme()))
|
||||
request.setSecure(true);
|
||||
}
|
||||
- else if (forwardedProto != null)
|
||||
+ else if (forwarded._forwardedProto != null)
|
||||
{
|
||||
- request.setScheme(forwardedProto);
|
||||
- if (forwardedProto.equals(config.getSecureScheme()))
|
||||
+ request.setScheme(forwarded._forwardedProto);
|
||||
+ if (forwarded._forwardedProto.equals(config.getSecureScheme()))
|
||||
request.setSecure(true);
|
||||
}
|
||||
- else if (forwardedHttps !=null && ("on".equalsIgnoreCase(forwardedHttps)||"true".equalsIgnoreCase(forwardedHttps)))
|
||||
+ else if (forwarded._forwardedHttps !=null && ("on".equalsIgnoreCase(forwarded._forwardedHttps)||"true".equalsIgnoreCase(forwarded._forwardedHttps)))
|
||||
{
|
||||
request.setScheme(HttpScheme.HTTPS.asString());
|
||||
if (HttpScheme.HTTPS.asString().equals(config.getSecureScheme()))
|
||||
@@ -521,4 +529,122 @@ protected void parsedParam(StringBuffer buffer, int valueLength, int paramName,
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+ private void updateHandles()
|
||||
+ {
|
||||
+ int size = 0;
|
||||
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
+ MethodType type = methodType(Void.TYPE, HttpField.class);
|
||||
+
|
||||
+ while(true)
|
||||
+ {
|
||||
+ try
|
||||
+ {
|
||||
+ size += 128;
|
||||
+ _handles = new ArrayTrie<>(size);
|
||||
+
|
||||
+ if (_forwardedCipherSuiteHeader != null && !_handles.put(_forwardedCipherSuiteHeader, lookup.findVirtual(Forwarded.class, "handleCipherSuite", type)))
|
||||
+ continue;
|
||||
+ if (_forwardedSslSessionIdHeader != null && !_handles.put(_forwardedSslSessionIdHeader, lookup.findVirtual(Forwarded.class, "handleSslSessionId", type)))
|
||||
+ continue;
|
||||
+ if (_forwardedHeader != null && !_handles.put(_forwardedHeader, lookup.findVirtual(Forwarded.class, "handleRFC7239", type)))
|
||||
+ continue;
|
||||
+ if (_forwardedForHeader != null && !_handles.put(_forwardedForHeader, lookup.findVirtual(Forwarded.class, "handleFor", type)))
|
||||
+ continue;
|
||||
+ if (_forwardedPortHeader != null && !_handles.put(_forwardedPortHeader, lookup.findVirtual(Forwarded.class, "handlePort", type)))
|
||||
+ continue;
|
||||
+ if (_forwardedHostHeader != null && !_handles.put(_forwardedHostHeader, lookup.findVirtual(Forwarded.class, "handleHost", type)))
|
||||
+ continue;
|
||||
+ if (_forwardedProtoHeader != null && !_handles.put(_forwardedProtoHeader, lookup.findVirtual(Forwarded.class, "handleProto", type)))
|
||||
+ continue;
|
||||
+ if (_forwardedHttpsHeader != null && !_handles.put(_forwardedHttpsHeader, lookup.findVirtual(Forwarded.class, "handleHttps", type)))
|
||||
+ continue;
|
||||
+ if (_forwardedServerHeader != null && !_handles.put(_forwardedServerHeader, lookup.findVirtual(Forwarded.class, "handleServer", type)))
|
||||
+ continue;
|
||||
+ break;
|
||||
+ }
|
||||
+ catch (NoSuchMethodException|IllegalAccessException e)
|
||||
+ {
|
||||
+ throw new IllegalStateException(e);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private class Forwarded
|
||||
+ {
|
||||
+ HttpConfiguration _config;
|
||||
+ Request _request;
|
||||
+
|
||||
+ RFC7239 _rfc7239 = null;
|
||||
+ String _forwardedHost = null;
|
||||
+ String _forwardedServer = null;
|
||||
+ String _forwardedProto = null;
|
||||
+ HostPort _forwardedFor = null;
|
||||
+ int _forwardedPort = -1;
|
||||
+ String _forwardedHttps = null;
|
||||
+
|
||||
+ public Forwarded(Request request, HttpConfiguration config)
|
||||
+ {
|
||||
+ _request = request;
|
||||
+ _config = config;
|
||||
+ }
|
||||
+
|
||||
+ public void handleCipherSuite(HttpField field)
|
||||
+ {
|
||||
+ _request.setAttribute("javax.servlet.request.cipher_suite",field.getValue());
|
||||
+ if (isSslIsSecure())
|
||||
+ {
|
||||
+ _request.setSecure(true);
|
||||
+ _request.setScheme(_config.getSecureScheme());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void handleSslSessionId(HttpField field)
|
||||
+ {
|
||||
+ _request.setAttribute("javax.servlet.request.ssl_session_id", field.getValue());
|
||||
+ if (isSslIsSecure())
|
||||
+ {
|
||||
+ _request.setSecure(true);
|
||||
+ _request.setScheme(_config.getSecureScheme());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void handleHost(HttpField field)
|
||||
+ {
|
||||
+ _forwardedHost = getLeftMost(field.getValue());
|
||||
+ }
|
||||
+
|
||||
+ public void handleServer(HttpField field)
|
||||
+ {
|
||||
+ _forwardedServer = getLeftMost(field.getValue());
|
||||
+ }
|
||||
+
|
||||
+ public void handleProto(HttpField field)
|
||||
+ {
|
||||
+ _forwardedProto = getLeftMost(field.getValue());
|
||||
+ }
|
||||
+
|
||||
+ public void handleFor(HttpField field)
|
||||
+ {
|
||||
+ _forwardedFor = getRemoteAddr(field.getValue());
|
||||
+ }
|
||||
+
|
||||
+ public void handlePort(HttpField field)
|
||||
+ {
|
||||
+ _forwardedPort = field.getIntValue();
|
||||
+ }
|
||||
+ public void handleHttps(HttpField field)
|
||||
+ {
|
||||
+ _forwardedHttps = getLeftMost(field.getValue());
|
||||
+ }
|
||||
+
|
||||
+ public void handleRFC7239(HttpField field)
|
||||
+ {
|
||||
+ if (_rfc7239 ==null)
|
||||
+ _rfc7239 = new RFC7239();
|
||||
+ _rfc7239.addValue(field.getValue());
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ }
|
||||
}
|
||||
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java
|
||||
index 5d5467f73bd..0a1cecec0c2 100644
|
||||
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java
|
||||
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java
|
||||
@@ -18,11 +18,6 @@
|
||||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
-import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
-import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
-import static org.hamcrest.MatcherAssert.assertThat;
|
||||
-import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
-
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
@@ -41,6 +36,11 @@
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
+import static org.hamcrest.MatcherAssert.assertThat;
|
||||
+import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
+import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
+import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
+
|
||||
public class ForwardedRequestCustomizerTest
|
||||
{
|
||||
private Server _server;
|
||||
@@ -249,6 +249,23 @@ public void testForIpv6WithPort() throws Exception
|
||||
assertEquals("1111",_results.poll());
|
||||
}
|
||||
|
||||
+ @Test
|
||||
+ public void testForIpv6AndPort() throws Exception
|
||||
+ {
|
||||
+ String response=_connector.getResponse(
|
||||
+ "GET / HTTP/1.1\n"+
|
||||
+ "Host: myhost\n"+
|
||||
+ "X-Forwarded-For: 1:2:3:4:5:6:7:8\n"+
|
||||
+ "X-Forwarded-Port: 2222\n"+
|
||||
+ "\n");
|
||||
+ assertThat(response, Matchers.containsString("200 OK"));
|
||||
+ assertEquals("http",_results.poll());
|
||||
+ assertEquals("myhost",_results.poll());
|
||||
+ assertEquals("80",_results.poll());
|
||||
+ assertEquals("[1:2:3:4:5:6:7:8]",_results.poll());
|
||||
+ assertEquals("2222",_results.poll());
|
||||
+ }
|
||||
+
|
||||
@Test
|
||||
public void testLegacyProto() throws Exception
|
||||
{
|
||||
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java b/jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java
|
||||
index 1824dd799d1..8fde487ae19 100644
|
||||
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java
|
||||
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/HostPort.java
|
||||
@@ -32,6 +32,12 @@
|
||||
private final String _host;
|
||||
private final int _port;
|
||||
|
||||
+ public HostPort(String host, int port) throws IllegalArgumentException
|
||||
+ {
|
||||
+ _host = host;
|
||||
+ _port = port;
|
||||
+ }
|
||||
+
|
||||
public HostPort(String authority) throws IllegalArgumentException
|
||||
{
|
||||
if (authority==null)
|
||||
@@ -66,8 +72,16 @@ else if (authority.charAt(0)=='[')
|
||||
int c = authority.lastIndexOf(':');
|
||||
if (c>=0)
|
||||
{
|
||||
- _host=authority.substring(0,c);
|
||||
- _port=StringUtil.toInt(authority,c+1);
|
||||
+ if (c!=authority.indexOf(':'))
|
||||
+ {
|
||||
+ _host="[" + authority + "]";
|
||||
+ _port=0;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ _host = authority.substring(0, c);
|
||||
+ _port = StringUtil.toInt(authority, c + 1);
|
||||
+ }
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -93,7 +107,6 @@ else if (authority.charAt(0)=='[')
|
||||
throw new IllegalArgumentException("Bad port");
|
||||
}
|
||||
|
||||
- /* ------------------------------------------------------------ */
|
||||
/** Get the host.
|
||||
* @return the host
|
||||
*/
|
||||
@@ -102,7 +115,6 @@ public String getHost()
|
||||
return _host;
|
||||
}
|
||||
|
||||
- /* ------------------------------------------------------------ */
|
||||
/** Get the port.
|
||||
* @return the port
|
||||
*/
|
||||
@@ -111,7 +123,6 @@ public int getPort()
|
||||
return _port;
|
||||
}
|
||||
|
||||
- /* ------------------------------------------------------------ */
|
||||
/** Get the port.
|
||||
* @param defaultPort, the default port to return if a port is not specified
|
||||
* @return the port
|
||||
@@ -121,7 +132,14 @@ public int getPort(int defaultPort)
|
||||
return _port>0?_port:defaultPort;
|
||||
}
|
||||
|
||||
- /* ------------------------------------------------------------ */
|
||||
+ @Override
|
||||
+ public String toString()
|
||||
+ {
|
||||
+ if (_port>0)
|
||||
+ return normalizeHost(_host) + ":" + _port;
|
||||
+ return _host;
|
||||
+ }
|
||||
+
|
||||
/** Normalize IPv6 address as per https://www.ietf.org/rfc/rfc2732.txt
|
||||
* @param host A host name
|
||||
* @return Host name surrounded by '[' and ']' as needed.
|
||||
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/HostPortTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/HostPortTest.java
|
||||
index 705bbbf6fa6..a700262cb90 100644
|
||||
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/HostPortTest.java
|
||||
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/HostPortTest.java
|
||||
@@ -18,17 +18,17 @@
|
||||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
-import static org.hamcrest.MatcherAssert.assertThat;
|
||||
-import static org.hamcrest.Matchers.is;
|
||||
-import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
-import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
-
|
||||
import java.util.stream.Stream;
|
||||
|
||||
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.is;
|
||||
+import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
+import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
+
|
||||
public class HostPortTest
|
||||
{
|
||||
private static Stream<Arguments> validAuthorityProvider()
|
||||
@@ -41,7 +41,8 @@
|
||||
Arguments.of("10.10.10.1", "10.10.10.1", null),
|
||||
Arguments.of("10.10.10.1:80", "10.10.10.1", "80"),
|
||||
Arguments.of("[0::0::0::1]", "[0::0::0::1]", null),
|
||||
- Arguments.of("[0::0::0::1]:80", "[0::0::0::1]", "80")
|
||||
+ Arguments.of("[0::0::0::1]:80", "[0::0::0::1]", "80"),
|
||||
+ Arguments.of("0:1:2:3:4:5:6","[0:1:2:3:4:5:6]",null)
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,518 +0,0 @@
|
||||
From 9f3b0223ab7e3159c4794e102f6b5e06dfc8710d Mon Sep 17 00:00:00 2001
|
||||
From: Greg Wilkins <gregw@webtide.com>
|
||||
Date: Wed, 8 May 2019 14:00:58 +0200
|
||||
Subject: [PATCH] Issue #3630 Forwarded-Port
|
||||
|
||||
reformatted code
|
||||
Avoid updating handles unless configuration is changed.
|
||||
|
||||
Signed-off-by: Greg Wilkins <gregw@webtide.com>
|
||||
---
|
||||
.../server/ForwardedRequestCustomizer.java | 216 ++++++++++--------
|
||||
1 file changed, 117 insertions(+), 99 deletions(-)
|
||||
|
||||
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
|
||||
index 1e64892cbe9..be3990794ed 100644
|
||||
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
|
||||
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
|
||||
@@ -43,7 +43,9 @@
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
-/** Customize Requests for Proxy Forwarding.
|
||||
+
|
||||
+/**
|
||||
+ * Customize Requests for Proxy Forwarding.
|
||||
* <p>
|
||||
* This customizer looks at at HTTP request for headers that indicate
|
||||
* it has been forwarded by one or more proxies. Specifically handled are
|
||||
@@ -59,7 +61,8 @@
|
||||
* so that the proxy is not seen as the other end point of the connection on which
|
||||
* the request came</p>
|
||||
* <p>Headers can also be defined so that forwarded SSL Session IDs and Cipher
|
||||
- * suites may be customised</p>
|
||||
+ * suites may be customised</p>
|
||||
+ *
|
||||
* @see <a href="http://en.wikipedia.org/wiki/X-Forwarded-For">Wikipedia: X-Forwarded-For</a>
|
||||
*/
|
||||
public class ForwardedRequestCustomizer implements Customizer
|
||||
@@ -76,9 +79,9 @@
|
||||
private String _forwardedHttpsHeader = "X-Proxied-Https";
|
||||
private String _forwardedCipherSuiteHeader = "Proxy-auth-cert";
|
||||
private String _forwardedSslSessionIdHeader = "Proxy-ssl-id";
|
||||
- private boolean _proxyAsAuthority=false;
|
||||
- private boolean _sslIsSecure=true;
|
||||
- private Trie <MethodHandle> _handles;
|
||||
+ private boolean _proxyAsAuthority = false;
|
||||
+ private boolean _sslIsSecure = true;
|
||||
+ private Trie<MethodHandle> _handles;
|
||||
|
||||
public ForwardedRequestCustomizer()
|
||||
{
|
||||
@@ -97,7 +100,7 @@ public boolean getProxyAsAuthority()
|
||||
|
||||
/**
|
||||
* @param proxyAsAuthority if true, use the proxy address obtained via
|
||||
- * {@code X-Forwarded-Server} or RFC7239 "by" as the request authority.
|
||||
+ * {@code X-Forwarded-Server} or RFC7239 "by" as the request authority.
|
||||
*/
|
||||
public void setProxyAsAuthority(boolean proxyAsAuthority)
|
||||
{
|
||||
@@ -114,49 +117,47 @@ public void setForwardedOnly(boolean rfc7239only)
|
||||
{
|
||||
if (rfc7239only)
|
||||
{
|
||||
- if (_forwardedHeader==null)
|
||||
- _forwardedHeader=HttpHeader.FORWARDED.toString();
|
||||
- _forwardedHostHeader=null;
|
||||
- _forwardedServerHeader=null;
|
||||
- _forwardedForHeader=null;
|
||||
- _forwardedPortHeader=null;
|
||||
- _forwardedProtoHeader=null;
|
||||
- _forwardedHttpsHeader=null;
|
||||
+ if (_forwardedHeader == null)
|
||||
+ _forwardedHeader = HttpHeader.FORWARDED.toString();
|
||||
+ _forwardedHostHeader = null;
|
||||
+ _forwardedServerHeader = null;
|
||||
+ _forwardedForHeader = null;
|
||||
+ _forwardedPortHeader = null;
|
||||
+ _forwardedProtoHeader = null;
|
||||
+ _forwardedHttpsHeader = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
- if (_forwardedHostHeader==null)
|
||||
+ if (_forwardedHostHeader == null)
|
||||
_forwardedHostHeader = HttpHeader.X_FORWARDED_HOST.toString();
|
||||
- if (_forwardedServerHeader==null)
|
||||
+ if (_forwardedServerHeader == null)
|
||||
_forwardedServerHeader = HttpHeader.X_FORWARDED_SERVER.toString();
|
||||
- if (_forwardedForHeader==null)
|
||||
+ if (_forwardedForHeader == null)
|
||||
_forwardedForHeader = HttpHeader.X_FORWARDED_FOR.toString();
|
||||
- if (_forwardedPortHeader==null)
|
||||
+ if (_forwardedPortHeader == null)
|
||||
_forwardedPortHeader = HttpHeader.X_FORWARDED_PORT.toString();
|
||||
- if (_forwardedProtoHeader==null)
|
||||
+ if (_forwardedProtoHeader == null)
|
||||
_forwardedProtoHeader = HttpHeader.X_FORWARDED_PROTO.toString();
|
||||
- if (_forwardedHttpsHeader==null)
|
||||
+ if (_forwardedHttpsHeader == null)
|
||||
_forwardedHttpsHeader = "X-Proxied-Https";
|
||||
}
|
||||
|
||||
updateHandles();
|
||||
}
|
||||
-
|
||||
+
|
||||
public String getForcedHost()
|
||||
{
|
||||
return _forcedHost.getValue();
|
||||
}
|
||||
-
|
||||
+
|
||||
/**
|
||||
* Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}.
|
||||
*
|
||||
- * @param hostAndPort
|
||||
- * The value of the host header to force.
|
||||
+ * @param hostAndPort The value of the host header to force.
|
||||
*/
|
||||
public void setForcedHost(String hostAndPort)
|
||||
{
|
||||
_forcedHost = new HostPortHttpField(hostAndPort);
|
||||
- updateHandles();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,13 +169,15 @@ public String getForwardedHeader()
|
||||
}
|
||||
|
||||
/**
|
||||
- * @param forwardedHeader
|
||||
- * The header name for RFC forwarded (default Forwarded)
|
||||
+ * @param forwardedHeader The header name for RFC forwarded (default Forwarded)
|
||||
*/
|
||||
public void setForwardedHeader(String forwardedHeader)
|
||||
{
|
||||
- _forwardedHeader = forwardedHeader;
|
||||
- updateHandles();
|
||||
+ if (_forwardedHeader == null || !_forwardedHeader.equals(forwardedHeader))
|
||||
+ {
|
||||
+ _forwardedHeader = forwardedHeader;
|
||||
+ updateHandles();
|
||||
+ }
|
||||
}
|
||||
|
||||
public String getForwardedHostHeader()
|
||||
@@ -183,13 +186,15 @@ public String getForwardedHostHeader()
|
||||
}
|
||||
|
||||
/**
|
||||
- * @param forwardedHostHeader
|
||||
- * The header name for forwarded hosts (default {@code X-Forwarded-Host})
|
||||
+ * @param forwardedHostHeader The header name for forwarded hosts (default {@code X-Forwarded-Host})
|
||||
*/
|
||||
public void setForwardedHostHeader(String forwardedHostHeader)
|
||||
{
|
||||
- _forwardedHostHeader = forwardedHostHeader;
|
||||
- updateHandles();
|
||||
+ if (_forwardedHostHeader == null || !_forwardedHostHeader.equalsIgnoreCase(forwardedHostHeader))
|
||||
+ {
|
||||
+ _forwardedHostHeader = forwardedHostHeader;
|
||||
+ updateHandles();
|
||||
+ }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,13 +206,15 @@ public String getForwardedServerHeader()
|
||||
}
|
||||
|
||||
/**
|
||||
- * @param forwardedServerHeader
|
||||
- * The header name for forwarded server (default {@code X-Forwarded-Server})
|
||||
+ * @param forwardedServerHeader The header name for forwarded server (default {@code X-Forwarded-Server})
|
||||
*/
|
||||
public void setForwardedServerHeader(String forwardedServerHeader)
|
||||
{
|
||||
- _forwardedServerHeader = forwardedServerHeader;
|
||||
- updateHandles();
|
||||
+ if (_forwardedServerHeader == null || !_forwardedServerHeader.equalsIgnoreCase(forwardedServerHeader))
|
||||
+ {
|
||||
+ _forwardedServerHeader = forwardedServerHeader;
|
||||
+ updateHandles();
|
||||
+ }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,13 +226,15 @@ public String getForwardedForHeader()
|
||||
}
|
||||
|
||||
/**
|
||||
- * @param forwardedRemoteAddressHeader
|
||||
- * The header name for forwarded for (default {@code X-Forwarded-For})
|
||||
+ * @param forwardedRemoteAddressHeader The header name for forwarded for (default {@code X-Forwarded-For})
|
||||
*/
|
||||
public void setForwardedForHeader(String forwardedRemoteAddressHeader)
|
||||
{
|
||||
- _forwardedForHeader = forwardedRemoteAddressHeader;
|
||||
- updateHandles();
|
||||
+ if (_forwardedForHeader == null || !_forwardedForHeader.equalsIgnoreCase(forwardedRemoteAddressHeader))
|
||||
+ {
|
||||
+ _forwardedForHeader = forwardedRemoteAddressHeader;
|
||||
+ updateHandles();
|
||||
+ }
|
||||
}
|
||||
|
||||
public String getForwardedPortHeader()
|
||||
@@ -234,13 +243,15 @@ public String getForwardedPortHeader()
|
||||
}
|
||||
|
||||
/**
|
||||
- * @param forwardedPortHeader
|
||||
- * The header name for forwarded hosts (default {@code X-Forwarded-Port})
|
||||
+ * @param forwardedPortHeader The header name for forwarded hosts (default {@code X-Forwarded-Port})
|
||||
*/
|
||||
public void setForwardedPortHeader(String forwardedPortHeader)
|
||||
{
|
||||
- _forwardedHostHeader = forwardedPortHeader;
|
||||
- updateHandles();
|
||||
+ if (_forwardedHostHeader == null || !_forwardedHostHeader.equalsIgnoreCase(forwardedPortHeader))
|
||||
+ {
|
||||
+ _forwardedHostHeader = forwardedPortHeader;
|
||||
+ updateHandles();
|
||||
+ }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,13 +267,15 @@ public String getForwardedProtoHeader()
|
||||
/**
|
||||
* Set the forwardedProtoHeader.
|
||||
*
|
||||
- * @param forwardedProtoHeader
|
||||
- * the forwardedProtoHeader to set (default {@code X-Forwarded-Proto})
|
||||
+ * @param forwardedProtoHeader the forwardedProtoHeader to set (default {@code X-Forwarded-Proto})
|
||||
*/
|
||||
public void setForwardedProtoHeader(String forwardedProtoHeader)
|
||||
{
|
||||
- _forwardedProtoHeader = forwardedProtoHeader;
|
||||
- updateHandles();
|
||||
+ if (_forwardedProtoHeader == null || !_forwardedProtoHeader.equalsIgnoreCase(forwardedProtoHeader))
|
||||
+ {
|
||||
+ _forwardedProtoHeader = forwardedProtoHeader;
|
||||
+ updateHandles();
|
||||
+ }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,13 +287,15 @@ public String getForwardedCipherSuiteHeader()
|
||||
}
|
||||
|
||||
/**
|
||||
- * @param forwardedCipherSuite
|
||||
- * The header name holding a forwarded cipher suite (default {@code Proxy-auth-cert})
|
||||
+ * @param forwardedCipherSuiteHeader The header name holding a forwarded cipher suite (default {@code Proxy-auth-cert})
|
||||
*/
|
||||
- public void setForwardedCipherSuiteHeader(String forwardedCipherSuite)
|
||||
+ public void setForwardedCipherSuiteHeader(String forwardedCipherSuiteHeader)
|
||||
{
|
||||
- _forwardedCipherSuiteHeader = forwardedCipherSuite;
|
||||
- updateHandles();
|
||||
+ if (_forwardedCipherSuiteHeader == null || !_forwardedCipherSuiteHeader.equalsIgnoreCase(forwardedCipherSuiteHeader))
|
||||
+ {
|
||||
+ _forwardedCipherSuiteHeader = forwardedCipherSuiteHeader;
|
||||
+ updateHandles();
|
||||
+ }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,13 +307,15 @@ public String getForwardedSslSessionIdHeader()
|
||||
}
|
||||
|
||||
/**
|
||||
- * @param forwardedSslSessionId
|
||||
- * The header name holding a forwarded SSL Session ID (default {@code Proxy-ssl-id})
|
||||
+ * @param forwardedSslSessionIdHeader The header name holding a forwarded SSL Session ID (default {@code Proxy-ssl-id})
|
||||
*/
|
||||
- public void setForwardedSslSessionIdHeader(String forwardedSslSessionId)
|
||||
+ public void setForwardedSslSessionIdHeader(String forwardedSslSessionIdHeader)
|
||||
{
|
||||
- _forwardedSslSessionIdHeader = forwardedSslSessionId;
|
||||
- updateHandles();
|
||||
+ if (_forwardedSslSessionIdHeader == null || !_forwardedSslSessionIdHeader.equalsIgnoreCase(forwardedSslSessionIdHeader))
|
||||
+ {
|
||||
+ _forwardedSslSessionIdHeader = forwardedSslSessionIdHeader;
|
||||
+ updateHandles();
|
||||
+ }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -314,10 +331,13 @@ public String getForwardedHttpsHeader()
|
||||
*/
|
||||
public void setForwardedHttpsHeader(String forwardedHttpsHeader)
|
||||
{
|
||||
- _forwardedHttpsHeader = forwardedHttpsHeader;
|
||||
- updateHandles();
|
||||
+ if (_forwardedHttpsHeader == null || !_forwardedHttpsHeader.equalsIgnoreCase(forwardedHttpsHeader))
|
||||
+ {
|
||||
+ _forwardedHttpsHeader = forwardedHttpsHeader;
|
||||
+ updateHandles();
|
||||
+ }
|
||||
}
|
||||
-
|
||||
+
|
||||
/**
|
||||
* @return true if the presence of a SSL session or certificate header is sufficient
|
||||
* to indicate a secure request (default is true)
|
||||
@@ -329,7 +349,7 @@ public boolean isSslIsSecure()
|
||||
|
||||
/**
|
||||
* @param sslIsSecure true if the presence of a SSL session or certificate header is sufficient
|
||||
- * to indicate a secure request (default is true)
|
||||
+ * to indicate a secure request (default is true)
|
||||
*/
|
||||
public void setSslIsSecure(boolean sslIsSecure)
|
||||
{
|
||||
@@ -362,13 +382,13 @@ public void customize(Connector connector, HttpConfiguration config, Request req
|
||||
{
|
||||
// Update host header
|
||||
httpFields.put(_forcedHost);
|
||||
- request.setAuthority(_forcedHost.getHost(),_forcedHost.getPort());
|
||||
+ request.setAuthority(_forcedHost.getHost(), _forcedHost.getPort());
|
||||
}
|
||||
- else if (forwarded._rfc7239!=null && forwarded._rfc7239._host!=null)
|
||||
+ else if (forwarded._rfc7239 != null && forwarded._rfc7239._host != null)
|
||||
{
|
||||
HostPortHttpField auth = forwarded._rfc7239._host;
|
||||
httpFields.put(auth);
|
||||
- request.setAuthority(auth.getHost(),auth.getPort());
|
||||
+ request.setAuthority(auth.getHost(), auth.getPort());
|
||||
}
|
||||
else if (forwarded._forwardedHost != null)
|
||||
{
|
||||
@@ -378,26 +398,26 @@ else if (forwarded._forwardedHost != null)
|
||||
}
|
||||
else if (_proxyAsAuthority)
|
||||
{
|
||||
- if (forwarded._rfc7239!=null && forwarded._rfc7239._by!=null)
|
||||
+ if (forwarded._rfc7239 != null && forwarded._rfc7239._by != null)
|
||||
{
|
||||
HostPortHttpField auth = forwarded._rfc7239._by;
|
||||
httpFields.put(auth);
|
||||
- request.setAuthority(auth.getHost(),auth.getPort());
|
||||
+ request.setAuthority(auth.getHost(), auth.getPort());
|
||||
}
|
||||
else if (forwarded._forwardedServer != null)
|
||||
{
|
||||
- request.setAuthority(forwarded._forwardedServer,request.getServerPort());
|
||||
+ request.setAuthority(forwarded._forwardedServer, request.getServerPort());
|
||||
}
|
||||
}
|
||||
|
||||
// handle remote end identifier
|
||||
- if (forwarded._rfc7239!=null && forwarded._rfc7239._for!=null)
|
||||
+ if (forwarded._rfc7239 != null && forwarded._rfc7239._for != null)
|
||||
{
|
||||
- request.setRemoteAddr(InetSocketAddress.createUnresolved(forwarded._rfc7239._for.getHost(),forwarded._rfc7239._for.getPort()));
|
||||
+ request.setRemoteAddr(InetSocketAddress.createUnresolved(forwarded._rfc7239._for.getHost(), forwarded._rfc7239._for.getPort()));
|
||||
}
|
||||
else if (forwarded._forwardedFor != null)
|
||||
{
|
||||
- int port = (forwarded._forwardedPort>0)
|
||||
+ int port = (forwarded._forwardedPort > 0)
|
||||
? forwarded._forwardedPort
|
||||
: (forwarded._forwardedFor.getPort() > 0)
|
||||
? forwarded._forwardedFor.getPort()
|
||||
@@ -406,7 +426,7 @@ else if (forwarded._forwardedFor != null)
|
||||
}
|
||||
|
||||
// handle protocol identifier
|
||||
- if (forwarded._rfc7239!=null && forwarded._rfc7239._proto!=null)
|
||||
+ if (forwarded._rfc7239 != null && forwarded._rfc7239._proto != null)
|
||||
{
|
||||
request.setScheme(forwarded._rfc7239._proto);
|
||||
if (forwarded._rfc7239._proto.equals(config.getSecureScheme()))
|
||||
@@ -418,7 +438,7 @@ else if (forwarded._forwardedProto != null)
|
||||
if (forwarded._forwardedProto.equals(config.getSecureScheme()))
|
||||
request.setSecure(true);
|
||||
}
|
||||
- else if (forwarded._forwardedHttps !=null && ("on".equalsIgnoreCase(forwarded._forwardedHttps)||"true".equalsIgnoreCase(forwarded._forwardedHttps)))
|
||||
+ else if (forwarded._forwardedHttps != null && ("on".equalsIgnoreCase(forwarded._forwardedHttps) || "true".equalsIgnoreCase(forwarded._forwardedHttps)))
|
||||
{
|
||||
request.setScheme(HttpScheme.HTTPS.asString());
|
||||
if (HttpScheme.HTTPS.asString().equals(config.getSecureScheme()))
|
||||
@@ -441,7 +461,7 @@ protected String getLeftMost(String headerValue)
|
||||
}
|
||||
|
||||
// The left-most value is the farthest downstream client
|
||||
- return headerValue.substring(0,commaIndex).trim();
|
||||
+ return headerValue.substring(0, commaIndex).trim();
|
||||
}
|
||||
|
||||
protected HostPort getRemoteAddr(String headerValue)
|
||||
@@ -463,11 +483,11 @@ protected HostPort getRemoteAddr(String headerValue)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
-
|
||||
+
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
- return String.format("%s@%x",this.getClass().getSimpleName(),hashCode());
|
||||
+ return String.format("%s@%x", this.getClass().getSimpleName(), hashCode());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@@ -475,12 +495,11 @@ public String getHostHeader()
|
||||
{
|
||||
return _forcedHost.getValue();
|
||||
}
|
||||
-
|
||||
+
|
||||
/**
|
||||
* Set a forced valued for the host header to control what is returned by {@link ServletRequest#getServerName()} and {@link ServletRequest#getServerPort()}.
|
||||
*
|
||||
- * @param hostHeader
|
||||
- * The value of the host header to force.
|
||||
+ * @param hostHeader The value of the host header to force.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setHostHeader(String hostHeader)
|
||||
@@ -494,7 +513,7 @@ public void setHostHeader(String hostHeader)
|
||||
HostPortHttpField _for;
|
||||
HostPortHttpField _host;
|
||||
String _proto;
|
||||
-
|
||||
+
|
||||
private RFC7239()
|
||||
{
|
||||
super(false);
|
||||
@@ -503,27 +522,27 @@ private RFC7239()
|
||||
@Override
|
||||
protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
|
||||
{
|
||||
- if (valueLength==0 && paramValue>paramName)
|
||||
+ if (valueLength == 0 && paramValue > paramName)
|
||||
{
|
||||
- String name=StringUtil.asciiToLowerCase(buffer.substring(paramName,paramValue-1));
|
||||
- String value=buffer.substring(paramValue);
|
||||
- switch(name)
|
||||
+ String name = StringUtil.asciiToLowerCase(buffer.substring(paramName, paramValue - 1));
|
||||
+ String value = buffer.substring(paramValue);
|
||||
+ switch (name)
|
||||
{
|
||||
case "by":
|
||||
- if (_by==null && !value.startsWith("_") && !"unknown".equals(value))
|
||||
- _by=new HostPortHttpField(value);
|
||||
+ if (_by == null && !value.startsWith("_") && !"unknown".equals(value))
|
||||
+ _by = new HostPortHttpField(value);
|
||||
break;
|
||||
case "for":
|
||||
- if (_for==null && !value.startsWith("_") && !"unknown".equals(value))
|
||||
- _for=new HostPortHttpField(value);
|
||||
+ if (_for == null && !value.startsWith("_") && !"unknown".equals(value))
|
||||
+ _for = new HostPortHttpField(value);
|
||||
break;
|
||||
case "host":
|
||||
- if (_host==null)
|
||||
- _host=new HostPortHttpField(value);
|
||||
+ if (_host == null)
|
||||
+ _host = new HostPortHttpField(value);
|
||||
break;
|
||||
case "proto":
|
||||
- if (_proto==null)
|
||||
- _proto=value;
|
||||
+ if (_proto == null)
|
||||
+ _proto = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -536,7 +555,7 @@ private void updateHandles()
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
MethodType type = methodType(Void.TYPE, HttpField.class);
|
||||
|
||||
- while(true)
|
||||
+ while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -563,7 +582,7 @@ private void updateHandles()
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
- catch (NoSuchMethodException|IllegalAccessException e)
|
||||
+ catch (NoSuchMethodException | IllegalAccessException e)
|
||||
{
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
@@ -591,7 +610,7 @@ public Forwarded(Request request, HttpConfiguration config)
|
||||
|
||||
public void handleCipherSuite(HttpField field)
|
||||
{
|
||||
- _request.setAttribute("javax.servlet.request.cipher_suite",field.getValue());
|
||||
+ _request.setAttribute("javax.servlet.request.cipher_suite", field.getValue());
|
||||
if (isSslIsSecure())
|
||||
{
|
||||
_request.setSecure(true);
|
||||
@@ -633,6 +652,7 @@ public void handlePort(HttpField field)
|
||||
{
|
||||
_forwardedPort = field.getIntValue();
|
||||
}
|
||||
+
|
||||
public void handleHttps(HttpField field)
|
||||
{
|
||||
_forwardedHttps = getLeftMost(field.getValue());
|
||||
@@ -640,11 +660,9 @@ public void handleHttps(HttpField field)
|
||||
|
||||
public void handleRFC7239(HttpField field)
|
||||
{
|
||||
- if (_rfc7239 ==null)
|
||||
+ if (_rfc7239 == null)
|
||||
_rfc7239 = new RFC7239();
|
||||
_rfc7239.addValue(field.getValue());
|
||||
}
|
||||
-
|
||||
-
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
1054
CVE-2020-27223.patch
Normal file → Executable file
1054
CVE-2020-27223.patch
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
@ -1,36 +0,0 @@
|
||||
From 00d379c94ba865dced2025c2d1bc3e2e0e41e880 Mon Sep 17 00:00:00 2001
|
||||
From: Joakim Erdfelt <joakim.erdfelt@gmail.com>
|
||||
Date: Thu, 18 Mar 2021 08:08:55 -0500
|
||||
Subject: [PATCH] Fixes #6072 - jetty server high CPU when client send data
|
||||
length > 17408.
|
||||
|
||||
Avoid spinning if the input buffer is full.
|
||||
|
||||
Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
|
||||
Co-authored-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>
|
||||
---
|
||||
.../main/java/org/eclipse/jetty/io/ssl/SslConnection.java | 8 +++++++-
|
||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
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 bc2431d..b2482e7 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
|
||||
@@ -603,7 +603,13 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
||||
|
||||
case BUFFER_UNDERFLOW:
|
||||
if (net_filled > 0)
|
||||
- continue; // try filling some more
|
||||
+ {
|
||||
+ if (BufferUtil.space(_encryptedInput) > 0)
|
||||
+ continue; // try filling some more
|
||||
+ BufferUtil.clear(_encryptedInput);
|
||||
+ throw new SSLHandshakeException("Encrypted buffer max length exceeded");
|
||||
+ }
|
||||
+
|
||||
_underflown = true;
|
||||
if (net_filled < 0 && _sslEngine.getUseClientMode())
|
||||
{
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,39 +0,0 @@
|
||||
From 294b2ba02b667548617a94cd99592110ac230add Mon Sep 17 00:00:00 2001
|
||||
From: Simone Bordet <simone.bordet@gmail.com>
|
||||
Date: Mon, 22 Mar 2021 10:39:36 +0100
|
||||
Subject: [PATCH] Fixes #6072 - jetty server high CPU when client send data
|
||||
length > 17408.
|
||||
|
||||
Updates after review.
|
||||
|
||||
Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
|
||||
---
|
||||
.../main/java/org/eclipse/jetty/io/ssl/SslConnection.java | 7 ++++---
|
||||
1 file changed, 4 insertions(+), 3 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 b2482e7..44c7f10 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
|
||||
@@ -602,14 +602,15 @@ public class SslConnection extends AbstractConnection implements Connection.Upgr
|
||||
return filled = -1;
|
||||
|
||||
case BUFFER_UNDERFLOW:
|
||||
- if (net_filled > 0)
|
||||
+ if (BufferUtil.space(_encryptedInput) == 0)
|
||||
{
|
||||
- if (BufferUtil.space(_encryptedInput) > 0)
|
||||
- continue; // try filling some more
|
||||
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())
|
||||
{
|
||||
--
|
||||
2.23.0
|
||||
|
||||
533
CVE-2021-28165.patch
Executable file
533
CVE-2021-28165.patch
Executable file
@ -0,0 +1,533 @@
|
||||
From: Markus Koschany <apo@debian.org>
|
||||
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=
|
||||
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+
|
||||
- "<requests xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"+
|
||||
- " xsi:noNamespaceSchemaLocation=\"commander.xsd\" version=\""+PROTOCOL_VERSION+"\">\n"+
|
||||
- "</requests>";
|
||||
-
|
||||
- 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 =
|
||||
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
||||
+ "<requests xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
|
||||
+ " xsi:noNamespaceSchemaLocation=\"commander.xsd\" version=\"" + PROTOCOL_VERSION + "\">\n" +
|
||||
+ "</requests>";
|
||||
+
|
||||
+ 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<loops;l++)
|
||||
+ for (int l = 0; l < loops; l++)
|
||||
{
|
||||
// System.err.print('.');
|
||||
try
|
||||
{
|
||||
- for (int i=0; i<numConns; ++i)
|
||||
+ for (int i = 0; i < numConns; ++i)
|
||||
{
|
||||
// System.err.println("write:"+i);
|
||||
- client[i]=ctx.getSocketFactory().createSocket("localhost",port);
|
||||
- OutputStream os=client[i].getOutputStream();
|
||||
+ client[i] = ctx.getSocketFactory().createSocket("localhost", port);
|
||||
+ OutputStream os = client[i].getOutputStream();
|
||||
|
||||
os.write(REQUEST0.getBytes());
|
||||
os.write(REQUEST0.getBytes());
|
||||
os.flush();
|
||||
}
|
||||
|
||||
- for (int i=0; i<numConns; ++i)
|
||||
+ for (int i = 0; i < numConns; ++i)
|
||||
{
|
||||
// System.err.println("flush:"+i);
|
||||
- OutputStream os=client[i].getOutputStream();
|
||||
+ OutputStream os = client[i].getOutputStream();
|
||||
os.write(REQUEST1.getBytes());
|
||||
os.flush();
|
||||
}
|
||||
|
||||
- for (int i=0; i<numConns; ++i)
|
||||
+ for (int i = 0; i < numConns; ++i)
|
||||
{
|
||||
// System.err.println("read:"+i);
|
||||
// Read the response.
|
||||
- String responses=readResponse(client[i]);
|
||||
+ String responses = readResponse(client[i]);
|
||||
// Check the responses
|
||||
- assertThat(String.format("responses loop=%d connection=%d",l,i),RESPONSE0+RESPONSE0+RESPONSE1,is(responses));
|
||||
+ assertThat(String.format("responses loop=%d connection=%d", l, i), RESPONSE0 + RESPONSE0 + RESPONSE1, is(responses));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
- for (int i=0; i<numConns; ++i)
|
||||
+ for (int i = 0; i < numConns; ++i)
|
||||
{
|
||||
- if (client[i]!=null)
|
||||
+ if (client[i] != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
assertThat("Client should read EOF", client[i].getInputStream().read(), is(-1));
|
||||
}
|
||||
- catch(SocketException e)
|
||||
+ catch (SocketException e)
|
||||
{
|
||||
+ // no op
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -272,10 +344,10 @@ public class SSLEngineTest
|
||||
server.start();
|
||||
|
||||
SSLContext context = SSLContext.getInstance("SSL");
|
||||
- context.init(null,SslContextFactory.TRUST_ALL_CERTS,new java.security.SecureRandom());
|
||||
+ context.init(null, SslContextFactory.TRUST_ALL_CERTS, new java.security.SecureRandom());
|
||||
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
|
||||
|
||||
- URL url = new URL("https://localhost:"+connector.getLocalPort()+"/test");
|
||||
+ URL url = new URL("https://localhost:" + connector.getLocalPort() + "/test");
|
||||
|
||||
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
|
||||
if (conn instanceof HttpsURLConnection)
|
||||
@@ -295,7 +367,7 @@ public class SSLEngineTest
|
||||
conn.setDoInput(true);
|
||||
conn.setDoOutput(true);
|
||||
conn.setRequestMethod("POST");
|
||||
- conn.setRequestProperty("Content-Type","text/plain");
|
||||
+ conn.setRequestProperty("Content-Type", "text/plain");
|
||||
conn.setChunkedStreamingMode(128);
|
||||
conn.connect();
|
||||
byte[] b = new byte[BODY_SIZE];
|
||||
@@ -309,13 +381,15 @@ public class SSLEngineTest
|
||||
|
||||
int len = 0;
|
||||
InputStream is = conn.getInputStream();
|
||||
- int bytes=0;
|
||||
+ int bytes = 0;
|
||||
while ((len = is.read(b)) > -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<buf.length;i++)
|
||||
- buf[i]=(byte)('0'+(i%10));
|
||||
+ for (int i = 0; i < buf.length; i++)
|
||||
+ {
|
||||
+ buf[i] = (byte)('0' + (i % 10));
|
||||
+ }
|
||||
out.write(buf);
|
||||
out.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
- PrintWriter out=response.getWriter();
|
||||
+ PrintWriter out = response.getWriter();
|
||||
out.print(HELLO_WORLD);
|
||||
out.close();
|
||||
}
|
||||
@@ -388,7 +464,7 @@ public class SSLEngineTest
|
||||
|
||||
private static class StreamHandler extends AbstractHandler
|
||||
{
|
||||
- private int bytes=0;
|
||||
+ private int bytes = 0;
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
@@ -400,7 +476,7 @@ public class SSLEngineTest
|
||||
InputStream is = request.getInputStream();
|
||||
while ((len = is.read(b)) > -1)
|
||||
{
|
||||
- bytes+=len;
|
||||
+ bytes += len;
|
||||
}
|
||||
|
||||
OutputStream os = response.getOutputStream();
|
||||
@@ -412,5 +488,4 @@ public class SSLEngineTest
|
||||
response.flushBuffer();
|
||||
}
|
||||
}
|
||||
-
|
||||
}
|
||||
233
CVE-2021-28169.patch
Normal file → Executable file
233
CVE-2021-28169.patch
Normal file → Executable file
@ -1,30 +1,24 @@
|
||||
From aec4092cc718b61998c1de221c9c728f377cd430 Mon Sep 17 00:00:00 2001
|
||||
From: Lachlan <lachlan@webtide.com>
|
||||
Date: Thu, 13 May 2021 01:13:30 +1000
|
||||
Subject: [PATCH] Fixes #6263 - Review URI encoding in ConcatServlet &
|
||||
WelcomeFilter.
|
||||
From: Markus Koschany <apo@debian.org>
|
||||
Date: Sat, 3 Jul 2021 20:47:31 +0200
|
||||
Subject: CVE-2021-28169
|
||||
|
||||
Review URI encoding in ConcatServlet & WelcomeFilter and improve testing.
|
||||
|
||||
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
|
||||
Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
|
||||
Co-authored-by: Simone Bordet <simone.bordet@gmail.com>
|
||||
Origin: https://github.com/eclipse/jetty.project/commit/1c05b0bcb181c759e98b060bded0b9376976b055
|
||||
---
|
||||
.../eclipse/jetty/server/ResourceService.java | 4 +-
|
||||
.../eclipse/jetty/servlets/ConcatServlet.java | 4 +-
|
||||
.../eclipse/jetty/servlets/WelcomeFilter.java | 8 +-
|
||||
.../jetty/servlets/ConcatServletTest.java | 83 ++++++----
|
||||
.../jetty/servlets/WelcomeFilterTest.java | 143 ++++++++++++++++++
|
||||
.../webapp/WebAppDefaultServletTest.java | 142 +++++++++++++++++
|
||||
6 files changed, 353 insertions(+), 31 deletions(-)
|
||||
.../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 3d3f05c..5ce24b4 100644
|
||||
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
|
||||
@@ -236,7 +236,7 @@ public class ResourceService
|
||||
@@ -234,7 +234,7 @@ public class ResourceService
|
||||
// Find the content
|
||||
content=_contentFactory.getContent(pathInContext,response.getBufferSize());
|
||||
if (LOG.isDebugEnabled())
|
||||
@ -33,7 +27,7 @@ index 3d3f05c..5ce24b4 100644
|
||||
|
||||
// Not found?
|
||||
if (content==null || !content.getResource().exists())
|
||||
@@ -422,7 +422,7 @@ public class ResourceService
|
||||
@@ -420,7 +420,7 @@ public class ResourceService
|
||||
return;
|
||||
}
|
||||
|
||||
@ -65,7 +59,7 @@ index a4b7df0..f1d8e57 100644
|
||||
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..492a8ca 100644
|
||||
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;
|
||||
@ -98,134 +92,108 @@ index e67a067..492a8ca 100644
|
||||
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..b815b35 100644
|
||||
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
|
||||
@@ -32,6 +32,7 @@ import java.nio.charset.StandardCharsets;
|
||||
@@ -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 java.util.stream.Stream;
|
||||
-
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
@@ -48,7 +49,12 @@ import org.junit.jupiter.api.AfterEach;
|
||||
|
||||
@@ -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 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.startsWith;
|
||||
+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;
|
||||
@@ -114,7 +120,7 @@ public class ConcatServletTest
|
||||
}
|
||||
|
||||
@Test
|
||||
- public void testWEBINFResourceIsNotServed() throws Exception
|
||||
+ public void testDirectoryNotAccessible() throws Exception
|
||||
{
|
||||
File directoryFile = MavenTestingUtils.getTargetTestingDir();
|
||||
Path directoryPath = directoryFile.toPath();
|
||||
@@ -136,9 +142,8 @@ public class ConcatServletTest
|
||||
// Verify that I can get the file programmatically, as required by the spec.
|
||||
assertNotNull(context.getServletContext().getResource("/WEB-INF/one.js"));
|
||||
|
||||
- // 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";
|
||||
+ // Make sure ConcatServlet cannot see file system files.
|
||||
+ String uri = contextPath + concatPath + "?/trick/../../" + directoryFile.getName();
|
||||
String request = "" +
|
||||
"GET " + uri + " HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
@@ -146,35 +151,59 @@ public class ConcatServletTest
|
||||
"\r\n";
|
||||
String response = connector.getResponse(request);
|
||||
assertTrue(response.startsWith("HTTP/1.1 404 "));
|
||||
+ }
|
||||
|
||||
- // Make sure ConcatServlet behaves well if it's case insensitive.
|
||||
- uri = contextPath + concatPath + "?/trick/../web-inf/one.js";
|
||||
- request = "" +
|
||||
@@ -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" +
|
||||
- "Host: localhost\r\n" +
|
||||
- "Connection: close\r\n" +
|
||||
- "\r\n";
|
||||
- response = connector.getResponse(request);
|
||||
- assertTrue(response.startsWith("HTTP/1.1 404 "));
|
||||
+ public static Stream<Arguments> webInfTestExamples()
|
||||
+ {
|
||||
+ return Stream.of(
|
||||
+ // Cannot access WEB-INF.
|
||||
+ Arguments.of("?/WEB-INF/", "HTTP/1.1 404 "),
|
||||
+ Arguments.of("?/WEB-INF/one.js", "HTTP/1.1 404 "),
|
||||
+
|
||||
+ // Having a path segment and then ".." triggers a special case that the ConcatServlet must detect and avoid.
|
||||
+ Arguments.of("?/trick/../WEB-INF/one.js", "HTTP/1.1 404 "),
|
||||
+
|
||||
+ // Make sure ConcatServlet behaves well if it's case insensitive.
|
||||
+ Arguments.of("?/trick/../web-inf/one.js", "HTTP/1.1 404 "),
|
||||
+
|
||||
+ // Make sure ConcatServlet behaves well if encoded.
|
||||
+ Arguments.of("?/trick/..%2FWEB-INF%2Fone.js", "HTTP/1.1 404 "),
|
||||
+ Arguments.of("?/%2557EB-INF/one.js", "HTTP/1.1 500 "),
|
||||
+ Arguments.of("?/js/%252e%252e/WEB-INF/one.js", "HTTP/1.1 500 ")
|
||||
+ );
|
||||
+ }
|
||||
|
||||
- // Make sure ConcatServlet behaves well if encoded.
|
||||
- uri = contextPath + concatPath + "?/trick/..%2FWEB-INF%2Fone.js";
|
||||
- request = "" +
|
||||
- "GET " + uri + " HTTP/1.1\r\n" +
|
||||
- "Host: localhost\r\n" +
|
||||
- "Connection: close\r\n" +
|
||||
- "\r\n";
|
||||
- response = connector.getResponse(request);
|
||||
- assertTrue(response.startsWith("HTTP/1.1 404 "));
|
||||
+ @ParameterizedTest
|
||||
+ @MethodSource("webInfTestExamples")
|
||||
+ public void testWEBINFResourceIsNotServed(String querystring, String expectedStatus) throws Exception
|
||||
+ {
|
||||
+ File directoryFile = MavenTestingUtils.getTargetTestingDir();
|
||||
+ Path directoryPath = directoryFile.toPath();
|
||||
+ Path hiddenDirectory = directoryPath.resolve("WEB-INF");
|
||||
+ Files.createDirectories(hiddenDirectory);
|
||||
+ Path hiddenResource = hiddenDirectory.resolve("one.js");
|
||||
+ try (OutputStream output = Files.newOutputStream(hiddenResource))
|
||||
+ {
|
||||
+ output.write("function() {}".getBytes(StandardCharsets.UTF_8));
|
||||
+ }
|
||||
+
|
||||
+ String contextPath = "";
|
||||
+ WebAppContext context = new WebAppContext(server, directoryPath.toString(), contextPath);
|
||||
+ server.setHandler(context);
|
||||
+ String concatPath = "/concat";
|
||||
+ context.addServlet(ConcatServlet.class, concatPath);
|
||||
+ server.start();
|
||||
|
||||
- // Make sure ConcatServlet cannot see file system files.
|
||||
- uri = contextPath + concatPath + "?/trick/../../" + directoryFile.getName();
|
||||
- request = "" +
|
||||
+ // Verify that I can get the file programmatically, as required by the spec.
|
||||
+ assertNotNull(context.getServletContext().getResource("/WEB-INF/one.js"));
|
||||
+
|
||||
+ String uri = contextPath + concatPath + querystring;
|
||||
+ String request =
|
||||
"GET " + uri + " HTTP/1.1\r\n" +
|
||||
+ "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";
|
||||
- response = connector.getResponse(request);
|
||||
- assertTrue(response.startsWith("HTTP/1.1 404 "));
|
||||
+ String response = connector.getResponse(request);
|
||||
+ assertThat(response, startsWith(expectedStatus));
|
||||
}
|
||||
}
|
||||
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
|
||||
@ -523,6 +491,3 @@ index 0000000..933bb7a
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
--
|
||||
2.23.0
|
||||
|
||||
|
||||
625
CVE-2021-34428.patch
Normal file → Executable file
625
CVE-2021-34428.patch
Normal file → Executable file
@ -1,21 +1,16 @@
|
||||
From 91d9850d64076cad97611a3379775e01acddf986 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Bartel <janb@webtide.com>
|
||||
Date: Sun, 16 May 2021 09:45:50 +1000
|
||||
Subject: [PATCH] Issue #6277 Better handling of exceptions thrown in
|
||||
sessionDestroyed (#6278)
|
||||
|
||||
* Issue #6277 Better handling of exceptions thrown in sessionDestroyed
|
||||
|
||||
Signed-off-by: Jan Bartel <janb@webtide.com>
|
||||
From: Markus Koschany <apo@debian.org>
|
||||
Date: Sat, 3 Jul 2021 20:28:06 +0200
|
||||
Subject: CVE-2021-34428
|
||||
|
||||
Origin: https://github.com/eclipse/jetty.project/commit/cd6462a6252d083b3c9ea2684aab0b4c9669ed19
|
||||
---
|
||||
.../eclipse/jetty/server/session/Session.java | 9 +-
|
||||
.../session/TestHttpSessionListener.java | 26 ++++--
|
||||
.../server/session/SessionListenerTest.java | 82 +++++++++++++++++--
|
||||
3 files changed, 102 insertions(+), 15 deletions(-)
|
||||
.../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..ecaf7c7 100644
|
||||
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
|
||||
@ -48,16 +43,14 @@ index a34bc0f..ecaf7c7 100644
|
||||
}
|
||||
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..b736fdf 100644
|
||||
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
|
||||
@@ -34,17 +34,19 @@ public class TestHttpSessionListener implements HttpSessionListener
|
||||
{
|
||||
@@ -35,16 +35,18 @@ public class TestHttpSessionListener implements HttpSessionListener
|
||||
public List<String> createdSessions = new ArrayList<>();
|
||||
public List<String> destroyedSessions = new ArrayList<>();
|
||||
- public boolean accessAttribute = false;
|
||||
public boolean accessAttribute = false;
|
||||
- public Exception ex = null;
|
||||
+ public boolean accessAttribute = false;
|
||||
+ public boolean lastAccessTime = false;
|
||||
+ public Exception attributeException = null;
|
||||
+ public Exception accessTimeException = null;
|
||||
@ -76,14 +69,14 @@ index 770627b..b736fdf 100644
|
||||
}
|
||||
|
||||
public void sessionDestroyed(HttpSessionEvent se)
|
||||
@@ -58,9 +60,21 @@ public class TestHttpSessionListener implements HttpSessionListener
|
||||
@@ -58,7 +60,19 @@ public class TestHttpSessionListener implements HttpSessionListener
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
- ex = e;
|
||||
+ attributeException = e;
|
||||
}
|
||||
}
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (lastAccessTime)
|
||||
+ {
|
||||
@ -94,37 +87,164 @@ index 770627b..b736fdf 100644
|
||||
+ catch (Exception e)
|
||||
+ {
|
||||
+ accessTimeException = e;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
public void sessionCreated(HttpSessionEvent se)
|
||||
}
|
||||
}
|
||||
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..24ac045 100644
|
||||
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
|
||||
@@ -21,6 +21,7 @@ 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;
|
||||
@@ -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;
|
||||
@@ -74,7 +75,7 @@ public class SessionListenerTest
|
||||
TestServer server = new TestServer(0, inactivePeriod, scavengePeriod,
|
||||
cacheFactory, storeFactory);
|
||||
+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);
|
||||
@@ -120,6 +121,73 @@ public class SessionListenerTest
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
+ */
|
||||
@ -150,40 +270,322 @@ index ba83986..24ac045 100644
|
||||
+ ServletHolder holder = new ServletHolder(servlet);
|
||||
+ context.addServlet(holder, servletMapping);
|
||||
+
|
||||
+ try
|
||||
+ {
|
||||
+ server.start();
|
||||
+ int port1 = server.getPort();
|
||||
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");
|
||||
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");
|
||||
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);
|
||||
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();
|
||||
// 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<MyHttpSessionListener> listeners = wac.getSessionHandler().getBeans(MyHttpSessionListener.class);
|
||||
+ assertNotNull(listeners);
|
||||
+
|
||||
+ assertEquals(1, listeners.size());
|
||||
+ }
|
||||
+ finally
|
||||
+ {
|
||||
@ -191,56 +593,65 @@ index ba83986..24ac045 100644
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/**
|
||||
* Test that listeners are called when a session expires.
|
||||
*
|
||||
@@ -144,7 +212,7 @@ public class SessionListenerTest
|
||||
ServletHolder holder = new ServletHolder(servlet);
|
||||
ServletContextHandler context = server1.addContext(contextPath);
|
||||
context.addServlet(holder, servletMapping);
|
||||
- TestHttpSessionListener listener = new TestHttpSessionListener(true);
|
||||
+ TestHttpSessionListener listener = new TestHttpSessionListener(true.true);
|
||||
context.getSessionHandler().addEventListener(listener);
|
||||
|
||||
server1.start();
|
||||
@@ -171,7 +239,8 @@ public class SessionListenerTest
|
||||
|
||||
assertThat(sessionId, isIn(listener.destroyedSessions));
|
||||
|
||||
- assertNull(listener.ex);
|
||||
+ assertNull(listener.attributeException);
|
||||
+ assertNull(listener.accessTimeException);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -203,7 +272,7 @@ public class SessionListenerTest
|
||||
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);
|
||||
|
||||
@@ -236,7 +305,8 @@ public class SessionListenerTest
|
||||
|
||||
assertTrue (listener.destroyedSessions.contains("1234"));
|
||||
|
||||
- assertNull(listener.ex);
|
||||
+ assertNull(listener.attributeException);
|
||||
+ assertNull(listener.accessTimeException);
|
||||
|
||||
}
|
||||
finally
|
||||
@@ -245,8 +315,6 @@ public class SessionListenerTest
|
||||
}
|
||||
}
|
||||
|
||||
-
|
||||
-
|
||||
public static class MySessionBindingListener implements HttpSessionBindingListener, Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
--
|
||||
2.23.0
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
22
jetty.spec
22
jetty.spec
@ -8,11 +8,11 @@
|
||||
%global rundir %{_localstatedir}/run/%{name}
|
||||
%global jettylibdir %{_localstatedir}/lib/%{name}
|
||||
%global appdir %{jettylibdir}/webapps
|
||||
%global addver .v20190215
|
||||
%global addver .v20190411
|
||||
%bcond_with jp_minimal
|
||||
Name: jetty
|
||||
Version: 9.4.15
|
||||
Release: 9
|
||||
Version: 9.4.16
|
||||
Release: 1
|
||||
Summary: Java Webserver and Servlet Container
|
||||
License: ASL 2.0 or EPL-1.0 or EPL-2.0
|
||||
URL: http://www.eclipse.org/jetty/
|
||||
@ -22,15 +22,10 @@ Source3: jetty.logrotate
|
||||
Source5: %{name}.service
|
||||
Source6: LICENSE-MIT
|
||||
Patch0: CVE-2020-27216.patch
|
||||
Patch1: CVE-2020-27223-pre-1.patch
|
||||
Patch2: CVE-2020-27223-pre-2.patch
|
||||
Patch3: CVE-2020-27223-pre-3.patch
|
||||
Patch4: CVE-2020-27223-pre-4.patch
|
||||
Patch5: CVE-2020-27223.patch
|
||||
Patch6: CVE-2021-28165-1.patch
|
||||
Patch7: CVE-2021-28165-2.patch
|
||||
Patch8: CVE-2021-28169.patch
|
||||
Patch9: CVE-2021-34428.patch
|
||||
Patch1: CVE-2020-27223.patch
|
||||
Patch2: CVE-2021-28165.patch
|
||||
Patch3: CVE-2021-28169.patch
|
||||
Patch4: CVE-2021-34428.patch
|
||||
|
||||
BuildRequires: maven-local mvn(javax.servlet:javax.servlet-api)
|
||||
BuildRequires: mvn(org.apache.felix:maven-bundle-plugin)
|
||||
@ -790,6 +785,9 @@ exit 0
|
||||
%license LICENSE NOTICE.txt LICENSE-MIT
|
||||
|
||||
%changelog
|
||||
* Tue Sep 13 2022 liangqifeng <liangqifeng@ncti-gba.cn> - 9.4.16-1
|
||||
- update to 9.4.14 to Fix CVE-2019-10241
|
||||
|
||||
* Thu Jul 1 2021 wutao <wutao61@huawei.com> - 9.4.15-9
|
||||
- Fix CVE-2021-34428
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user