diff --git a/Jenkinsfile b/Jenkinsfile index 0d9b2c54a3d..8f1d305dc69 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -14,62 +14,63 @@ pipeline { mavenBuild("jdk11", "-Pmongodb install", "maven3", true) // -Pautobahn // Collect up the jacoco execution results (only on main build) jacoco inclusionPattern: '**/org/eclipse/jetty/**/*.class', - exclusionPattern: '' + - // build tools - '**/org/eclipse/jetty/ant/**' + - ',**/org/eclipse/jetty/maven/**' + - ',**/org/eclipse/jetty/jspc/**' + - // example code / documentation - ',**/org/eclipse/jetty/embedded/**' + - ',**/org/eclipse/jetty/asyncrest/**' + - ',**/org/eclipse/jetty/demo/**' + - // special environments / late integrations - ',**/org/eclipse/jetty/gcloud/**' + - ',**/org/eclipse/jetty/infinispan/**' + - ',**/org/eclipse/jetty/osgi/**' + - ',**/org/eclipse/jetty/spring/**' + - ',**/org/eclipse/jetty/http/spi/**' + - // test classes - ',**/org/eclipse/jetty/tests/**' + - ',**/org/eclipse/jetty/test/**', - execPattern: '**/target/jacoco.exec', - classPattern: '**/target/classes', - sourcePattern: '**/src/main/java' + exclusionPattern: '' + + // build tools + '**/org/eclipse/jetty/ant/**' + + ',**/org/eclipse/jetty/maven/**' + + ',**/org/eclipse/jetty/jspc/**' + + // example code / documentation + ',**/org/eclipse/jetty/embedded/**' + + ',**/org/eclipse/jetty/asyncrest/**' + + ',**/org/eclipse/jetty/demo/**' + + // special environments / late integrations + ',**/org/eclipse/jetty/gcloud/**' + + ',**/org/eclipse/jetty/infinispan/**' + + ',**/org/eclipse/jetty/osgi/**' + + ',**/org/eclipse/jetty/spring/**' + + ',**/org/eclipse/jetty/http/spi/**' + + // test classes + ',**/org/eclipse/jetty/tests/**' + + ',**/org/eclipse/jetty/test/**', + execPattern: '**/target/jacoco.exec', + classPattern: '**/target/classes', + sourcePattern: '**/src/main/java' warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'Java']] junit testResults: '**/target/surefire-reports/*.xml,**/target/invoker-reports/TEST*.xml,**/target/autobahntestsuite-reports/*.xml' } } - + stage("Build / Test - JDK12") { agent { node { label 'linux' } } - options { timeout(time: 120, unit: 'MINUTES') } steps { - mavenBuild("jdk12", "-Pmongodb install", "maven3", true) - warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'Java']] - junit testResults: '**/target/surefire-reports/*.xml,**/target/invoker-reports/TEST*.xml' + timeout(time: 120, unit: 'MINUTES') { + mavenBuild("jdk12", "-Pmongodb install", "maven3", true) + warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'Java']] + junit testResults: '**/target/surefire-reports/*.xml,**/target/invoker-reports/TEST*.xml' + } } } stage("Build Javadoc") { agent { node { label 'linux' } } - options { timeout(time: 30, unit: 'MINUTES') } steps { - mavenBuild("jdk11", "install javadoc:javadoc -DskipTests", "maven3", true) - warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'JavaDoc'], [parserName: 'Java']] + timeout(time: 30, unit: 'MINUTES') { + mavenBuild("jdk11", "install javadoc:javadoc javadoc:aggregate-jar -DskipTests", "maven3", true) + warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'JavaDoc'], [parserName: 'Java']] + } } } stage("Checkstyle ") { agent { node { label 'linux' } } - options { timeout(time: 30, unit: 'MINUTES') } steps { - mavenBuild("jdk11", "install -DskipTests", "maven3", true) - mavenBuild("jdk11", "install -f build-resources", "maven3", true) - mavenBuild("jdk11", "install checkstyle:check -DskipTests", "maven3", true) - recordIssues( - enabledForFailure: true, aggregatingResults: true, - tools: [java(), checkStyle(pattern: '**/target/checkstyle-result.xml', reportEncoding: 'UTF-8')] - ) + timeout(time: 30, unit: 'MINUTES') { + mavenBuild("jdk11", "install -f build-resources", "maven3", true) + mavenBuild("jdk11", "install checkstyle:check -DskipTests", "maven3", true) + recordIssues( + enabledForFailure: true, aggregatingResults: true, + tools: [java(), checkStyle(pattern: '**/target/checkstyle-result.xml', reportEncoding: 'UTF-8')]) + } } } } @@ -90,23 +91,21 @@ pipeline { def slackNotif() { - script { - try - { - if ( env.BRANCH_NAME == 'jetty-10.0.x' || env.BRANCH_NAME == 'jetty-9.4.x' ) - { - //BUILD_USER = currentBuild.rawBuild.getCause(Cause.UserIdCause).getUserId() - // by ${BUILD_USER} - COLOR_MAP = ['SUCCESS': 'good', 'FAILURE': 'danger', 'UNSTABLE': 'danger', 'ABORTED': 'danger'] - slackSend channel: '#jenkins', - color: COLOR_MAP[currentBuild.currentResult], - message: "*${currentBuild.currentResult}:* Job ${env.JOB_NAME} build ${env.BUILD_NUMBER} - ${env.BUILD_URL}" - } - } catch (Exception e) { - e.printStackTrace() - echo "skip failure slack notification: " + e.getMessage() + script { + try { + if (env.BRANCH_NAME == 'jetty-10.0.x' || env.BRANCH_NAME == 'jetty-9.4.x') { + //BUILD_USER = currentBuild.rawBuild.getCause(Cause.UserIdCause).getUserId() + // by ${BUILD_USER} + COLOR_MAP = ['SUCCESS': 'good', 'FAILURE': 'danger', 'UNSTABLE': 'danger', 'ABORTED': 'danger'] + slackSend channel: '#jenkins', + color: COLOR_MAP[currentBuild.currentResult], + message: "*${currentBuild.currentResult}:* Job ${env.JOB_NAME} build ${env.BUILD_NUMBER} - ${env.BUILD_URL}" } + } catch (Exception e) { + e.printStackTrace() + echo "skip failure slack notification: " + e.getMessage() } + } } @@ -125,12 +124,12 @@ def mavenBuild(jdk, cmdline, mvnName, junitPublishDisabled) { def mavenOpts = '-Xms1g -Xmx4g -Djava.awt.headless=true' withMaven( - maven: mvnName, - jdk: "$jdk", - publisherStrategy: 'EXPLICIT', - options: [junitPublisher(disabled: junitPublishDisabled),mavenLinkerPublisher(disabled: false),pipelineGraphPublisher(disabled: false)], - mavenOpts: mavenOpts, - mavenLocalRepo: localRepo) { + maven: mvnName, + jdk: "$jdk", + publisherStrategy: 'EXPLICIT', + options: [junitPublisher(disabled: junitPublishDisabled), mavenLinkerPublisher(disabled: false), pipelineGraphPublisher(disabled: false)], + mavenOpts: mavenOpts, + mavenLocalRepo: localRepo) { // Some common Maven command line + provided command line sh "mvn -Pci -V -B -T3 -e -fae -Dmaven.test.failure.ignore=true -Djetty.testtracker.log=true $cmdline -Dunix.socket.tmp=" + env.JENKINS_HOME } diff --git a/jetty-documentation/src/main/asciidoc/embedded-guide/server/troubleshooting/security-reports.adoc b/jetty-documentation/src/main/asciidoc/embedded-guide/server/troubleshooting/security-reports.adoc index 658bfd190a5..34eed7ee5e7 100644 --- a/jetty-documentation/src/main/asciidoc/embedded-guide/server/troubleshooting/security-reports.adoc +++ b/jetty-documentation/src/main/asciidoc/embedded-guide/server/troubleshooting/security-reports.adoc @@ -28,6 +28,15 @@ If you would like to report a security issue please follow these link:#security- |======================================================================= |yyyy/mm/dd |ID |Exploitable |Severity |Affects |Fixed Version |Comment +|2019/04/11 |CVE-2019-10247 |Med |Med |< = 9.4.16 |9.2.28, 9.3.27, 9.4.17 +|https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-10247[If no webapp was mounted to the root namespace and a 404 was encountered, an HTML page would be generated displaying the fully qualified base resource location for each context.] + +|2019/04/11 |CVE-2019-10246 |High |High |< = 9.4.16 |9.2.28, 9.3.27, 9.4.17 +|https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-10246[Use of `DefaultServlet` or `ResourceHandler` with indexing was vulnerable to XSS behaviors to expose the directory listing on Windows operating systems.] + +|2019/04/11 |CVE-2019-10241 |High |High |< = 9.4.15 |9.2.27, 9.3.26, 9.4.16 +|https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-10241[Use of `DefaultServlet` or `ResourceHandler` with indexing was vulnerable to XSS behaviors to expose the directory listing.] + |2018/06/25 |CVE-2018-12538 |High |High |>= 9.4.0, < = 9.4.8 |9.4.9 |https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12538[`HttpSessions` present specifically in the FileSystem’s storage could be hijacked/accessed by an unauthorized user.] 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 92e7a1a52fc..aafbb97eacf 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 @@ -35,8 +35,6 @@ 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; @@ -63,8 +61,6 @@ import static java.lang.invoke.MethodType.methodType; */ public class ForwardedRequestCustomizer implements Customizer { - private static final Logger LOG = Log.getLogger(ForwardedRequestCustomizer.class); - private HostPortHttpField _forcedHost; private boolean _proxyAsAuthority = false; private boolean _forwardedPortAsAuthority = true; @@ -236,7 +232,7 @@ public class ForwardedRequestCustomizer implements Customizer public String getForwardedPortHeader() { - return _forwardedHostHeader; + return _forwardedPortHeader; } /** @@ -244,9 +240,9 @@ public class ForwardedRequestCustomizer implements Customizer */ public void setForwardedPortHeader(String forwardedPortHeader) { - if (_forwardedHostHeader == null || !_forwardedHostHeader.equalsIgnoreCase(forwardedPortHeader)) + if (_forwardedPortHeader == null || !_forwardedPortHeader.equalsIgnoreCase(forwardedPortHeader)) { - _forwardedHostHeader = forwardedPortHeader; + _forwardedPortHeader = forwardedPortHeader; updateHandles(); } } @@ -456,32 +452,32 @@ public class ForwardedRequestCustomizer implements Customizer { int size = 0; MethodHandles.Lookup lookup = MethodHandles.lookup(); - MethodType type = methodType(Void.TYPE, HttpField.class); + // Loop to grow capacity of ArrayTrie for all headers while (true) { try { - size += 128; + size += 128; // experimented good baseline size _handles = new ArrayTrie<>(size); - if (_forwardedCipherSuiteHeader != null && !_handles.put(_forwardedCipherSuiteHeader, lookup.findVirtual(Forwarded.class, "handleCipherSuite", type))) + if (updateForwardedHandle(lookup, getForwardedCipherSuiteHeader(), "handleCipherSuite")) continue; - if (_forwardedSslSessionIdHeader != null && !_handles.put(_forwardedSslSessionIdHeader, lookup.findVirtual(Forwarded.class, "handleSslSessionId", type))) + if (updateForwardedHandle(lookup, getForwardedSslSessionIdHeader(), "handleSslSessionId")) continue; - if (_forwardedHeader != null && !_handles.put(_forwardedHeader, lookup.findVirtual(Forwarded.class, "handleRFC7239", type))) + if (updateForwardedHandle(lookup, getForwardedHeader(), "handleRFC7239")) continue; - if (_forwardedForHeader != null && !_handles.put(_forwardedForHeader, lookup.findVirtual(Forwarded.class, "handleFor", type))) + if (updateForwardedHandle(lookup, getForwardedForHeader(), "handleFor")) continue; - if (_forwardedPortHeader != null && !_handles.put(_forwardedPortHeader, lookup.findVirtual(Forwarded.class, "handlePort", type))) + if (updateForwardedHandle(lookup, getForwardedPortHeader(), "handlePort")) continue; - if (_forwardedHostHeader != null && !_handles.put(_forwardedHostHeader, lookup.findVirtual(Forwarded.class, "handleHost", type))) + if (updateForwardedHandle(lookup, getForwardedHostHeader(), "handleHost")) continue; - if (_forwardedProtoHeader != null && !_handles.put(_forwardedProtoHeader, lookup.findVirtual(Forwarded.class, "handleProto", type))) + if (updateForwardedHandle(lookup, getForwardedProtoHeader(), "handleProto")) continue; - if (_forwardedHttpsHeader != null && !_handles.put(_forwardedHttpsHeader, lookup.findVirtual(Forwarded.class, "handleHttps", type))) + if (updateForwardedHandle(lookup, getForwardedHttpsHeader(), "handleHttps")) continue; - if (_forwardedServerHeader != null && !_handles.put(_forwardedServerHeader, lookup.findVirtual(Forwarded.class, "handleServer", type))) + if (updateForwardedHandle(lookup, getForwardedServerHeader(), "handleServer")) continue; break; } @@ -492,6 +488,16 @@ public class ForwardedRequestCustomizer implements Customizer } } + private boolean updateForwardedHandle(MethodHandles.Lookup lookup, String headerName, String forwardedMethodName) throws NoSuchMethodException, IllegalAccessException + { + final MethodType type = methodType(void.class, HttpField.class); + + if (StringUtil.isBlank(headerName)) + return false; + + return !_handles.put(headerName, lookup.findVirtual(Forwarded.class, forwardedMethodName, type)); + } + private static class ForcedHostPort extends HostPort { ForcedHostPort(String authority) @@ -548,6 +554,7 @@ public class ForwardedRequestCustomizer implements Customizer _host = _forcedHost.getHostPort(); } + @SuppressWarnings("unused") public void handleCipherSuite(HttpField field) { _request.setAttribute("javax.servlet.request.cipher_suite", field.getValue()); @@ -558,6 +565,7 @@ public class ForwardedRequestCustomizer implements Customizer } } + @SuppressWarnings("unused") public void handleSslSessionId(HttpField field) { _request.setAttribute("javax.servlet.request.ssl_session_id", field.getValue()); @@ -570,7 +578,7 @@ public class ForwardedRequestCustomizer implements Customizer public void handleHost(HttpField field) { - if (_forwardedPortAsAuthority && !StringUtil.isEmpty(_forwardedPortHeader)) + if (getForwardedPortAsAuthority() && !StringUtil.isEmpty(getForwardedPortHeader())) { if (_host == null) _host = new PossiblyPartialHostPort(getLeftMost(field.getValue())); @@ -583,22 +591,25 @@ public class ForwardedRequestCustomizer implements Customizer } } + @SuppressWarnings("unused") public void handleServer(HttpField field) { - if (_proxyAsAuthority) + if (getProxyAsAuthority()) return; handleHost(field); } + @SuppressWarnings("unused") public void handleProto(HttpField field) { if (_proto == null) _proto = getLeftMost(field.getValue()); } + @SuppressWarnings("unused") public void handleFor(HttpField field) { - if (!_forwardedPortAsAuthority && !StringUtil.isEmpty(_forwardedPortHeader)) + if (!getForwardedPortAsAuthority() && !StringUtil.isEmpty(getForwardedPortHeader())) { if (_for == null) _for = new PossiblyPartialHostPort(getLeftMost(field.getValue())); @@ -611,9 +622,10 @@ public class ForwardedRequestCustomizer implements Customizer } } + @SuppressWarnings("unused") public void handlePort(HttpField field) { - if (!_forwardedPortAsAuthority) + if (!getForwardedPortAsAuthority()) { if (_for == null) _for = new PortSetHostPort(_request.getRemoteHost(), field.getIntValue()); @@ -629,12 +641,14 @@ public class ForwardedRequestCustomizer implements Customizer } } + @SuppressWarnings("unused") public void handleHttps(HttpField field) { if (_proto == null && ("on".equalsIgnoreCase(field.getValue()) || "true".equalsIgnoreCase(field.getValue()))) _proto = HttpScheme.HTTPS.asString(); } + @SuppressWarnings("unused") public void handleRFC7239(HttpField field) { addValue(field.getValue()); @@ -650,11 +664,11 @@ public class ForwardedRequestCustomizer implements Customizer switch (name) { case "by": - if (!_proxyAsAuthority) + if (!getProxyAsAuthority()) break; if (value.startsWith("_") || "unknown".equals(value)) break; - if (_proxyAsAuthority && (_host == null || !(_host instanceof Rfc7239HostPort))) + if (_host == null || !(_host instanceof Rfc7239HostPort)) _host = new Rfc7239HostPort(value); break; case "for": 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 034bf642625..7f2ea3560d4 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 @@ -21,6 +21,9 @@ package org.eclipse.jetty.server; import java.io.IOException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Stream; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -29,621 +32,630 @@ import org.eclipse.jetty.http.tools.HttpTester; import org.eclipse.jetty.server.handler.AbstractHandler; 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.is; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public class ForwardedRequestCustomizerTest { - private Server _server; - private LocalConnector _connector; - private RequestHandler _handler; - final AtomicBoolean _wasSecure = new AtomicBoolean(false); - final AtomicReference _sslSession = new AtomicReference<>(); - final AtomicReference _sslCertificate = new AtomicReference<>(); - final AtomicReference _scheme = new AtomicReference<>(); - final AtomicReference _serverName = new AtomicReference<>(); - final AtomicReference _serverPort = new AtomicReference<>(); - final AtomicReference _remoteAddr = new AtomicReference<>(); - final AtomicReference _remotePort = new AtomicReference<>(); - final AtomicReference _requestURL = new AtomicReference<>(); + private Server server; + private RequestHandler handler; + private LocalConnector connector; + private LocalConnector connectorConfigured; + private ForwardedRequestCustomizer customizer; + private ForwardedRequestCustomizer customizerConfigured; - ForwardedRequestCustomizer _customizer; + private static class Actual + { + final AtomicReference scheme = new AtomicReference<>(); + final AtomicBoolean wasSecure = new AtomicBoolean(false); + final AtomicReference serverName = new AtomicReference<>(); + final AtomicReference serverPort = new AtomicReference<>(); + final AtomicReference requestURL = new AtomicReference<>(); + final AtomicReference remoteAddr = new AtomicReference<>(); + final AtomicReference remotePort = new AtomicReference<>(); + final AtomicReference sslSession = new AtomicReference<>(); + final AtomicReference sslCertificate = new AtomicReference<>(); + } + + private Actual actual; @BeforeEach public void init() throws Exception { - _server = new Server(); + server = new Server(); + + // Default behavior Connector HttpConnectionFactory http = new HttpConnectionFactory(); http.setInputBufferSize(1024); http.getHttpConfiguration().setRequestHeaderSize(512); http.getHttpConfiguration().setResponseHeaderSize(512); http.getHttpConfiguration().setOutputBufferSize(2048); - http.getHttpConfiguration().addCustomizer(_customizer = new ForwardedRequestCustomizer()); - _connector = new LocalConnector(_server, http); - _server.addConnector(_connector); - _handler = new RequestHandler(); - _server.setHandler(_handler); + customizer = new ForwardedRequestCustomizer(); + http.getHttpConfiguration().addCustomizer(customizer); + connector = new LocalConnector(server, http); + server.addConnector(connector); - _handler._checker = (request, response) -> + // Configured behavior Connector + http = new HttpConnectionFactory(); + http.setInputBufferSize(1024); + http.getHttpConfiguration().setRequestHeaderSize(512); + http.getHttpConfiguration().setResponseHeaderSize(512); + http.getHttpConfiguration().setOutputBufferSize(2048); + customizerConfigured = new ForwardedRequestCustomizer(); + customizerConfigured.setForwardedHeader("Jetty-Forwarded"); + customizerConfigured.setForwardedHostHeader("Jetty-Forwarded-Host"); + customizerConfigured.setForwardedServerHeader("Jetty-Forwarded-Server"); + customizerConfigured.setForwardedProtoHeader("Jetty-Forwarded-Proto"); + customizerConfigured.setForwardedForHeader("Jetty-Forwarded-For"); + customizerConfigured.setForwardedPortHeader("Jetty-Forwarded-Port"); + customizerConfigured.setForwardedHttpsHeader("Jetty-Proxied-Https"); + customizerConfigured.setForwardedCipherSuiteHeader("Jetty-Proxy-Auth-Cert"); + customizerConfigured.setForwardedSslSessionIdHeader("Jetty-Proxy-Ssl-Id"); + + http.getHttpConfiguration().addCustomizer(customizerConfigured); + connectorConfigured = new LocalConnector(server, http); + server.addConnector(connectorConfigured); + + handler = new RequestHandler(); + server.setHandler(handler); + + handler.requestTester = (request, response) -> { - _wasSecure.set(request.isSecure()); - _sslSession.set(String.valueOf(request.getAttribute("javax.servlet.request.ssl_session_id"))); - _sslCertificate.set(String.valueOf(request.getAttribute("javax.servlet.request.cipher_suite"))); - _scheme.set(request.getScheme()); - _serverName.set(request.getServerName()); - _serverPort.set(request.getServerPort()); - _remoteAddr.set(request.getRemoteAddr()); - _remotePort.set(request.getRemotePort()); - _requestURL.set(request.getRequestURL().toString()); + actual = new Actual(); + actual.wasSecure.set(request.isSecure()); + actual.sslSession.set(String.valueOf(request.getAttribute("javax.servlet.request.ssl_session_id"))); + actual.sslCertificate.set(String.valueOf(request.getAttribute("javax.servlet.request.cipher_suite"))); + actual.scheme.set(request.getScheme()); + actual.serverName.set(request.getServerName()); + actual.serverPort.set(request.getServerPort()); + actual.remoteAddr.set(request.getRemoteAddr()); + actual.remotePort.set(request.getRemotePort()); + actual.requestURL.set(request.getRequestURL().toString()); return true; }; - _server.start(); + server.start(); } @AfterEach public void destroy() throws Exception { - _server.stop(); + server.stop(); } - @Test - public void testHostIpv4() throws Exception + public static Stream cases() { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: 1.2.3.4:2222\n" + - "\n")); - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("1.2.3.4")); - assertThat("serverPort", _serverPort.get(), is(2222)); - assertThat("requestURL", _requestURL.get(), is("http://1.2.3.4:2222/")); + return Stream.of( + // Host IPv4 + Arguments.of( + new Request("IPv4 Host Only") + .headers( + "GET / HTTP/1.1", + "Host: 1.2.3.4:2222" + ), + new Expectations() + .scheme("http").serverName("1.2.3.4").serverPort(2222) + .requestURL("http://1.2.3.4:2222/") + ), + Arguments.of(new Request("IPv6 Host Only") + .headers( + "GET / HTTP/1.1", + "Host: [::1]:2222" + ), + new Expectations() + .scheme("http").serverName("[::1]").serverPort(2222) + .requestURL("http://[::1]:2222/") + ), + Arguments.of(new Request("IPv4 in Request Line") + .headers( + "GET http://1.2.3.4:2222/ HTTP/1.1", + "Host: wrong" + ), + new Expectations() + .scheme("http").serverName("1.2.3.4").serverPort(2222) + .requestURL("http://1.2.3.4:2222/") + ), + Arguments.of(new Request("IPv6 in Request Line") + .headers( + "GET http://[::1]:2222/ HTTP/1.1", + "Host: wrong" + ), + new Expectations() + .scheme("http").serverName("[::1]").serverPort(2222) + .requestURL("http://[::1]:2222/") + ), + + // ================================================================= + // https://tools.ietf.org/html/rfc7239#section-4 - examples of syntax + Arguments.of(new Request("RFC7239 Examples: Section 4") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "Forwarded: for=\"_gazonk\"", + "Forwarded: For=\"[2001:db8:cafe::17]:4711\"", + "Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43", + "Forwarded: for=192.0.2.43, for=198.51.100.17" + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(80) + .requestURL("http://myhost/") + .remoteAddr("[2001:db8:cafe::17]").remotePort(4711) + ), + + // https://tools.ietf.org/html/rfc7239#section-7 - Examples of syntax with regards to HTTP header fields + Arguments.of(new Request("RFC7239 Examples: Section 7") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "Forwarded: for=192.0.2.43,for=\"[2001:db8:cafe::17]\",for=unknown" + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(80) + .requestURL("http://myhost/") + .remoteAddr("192.0.2.43").remotePort(0) + ), + + // (same as above, but with spaces, as shown in RFC section 7.1) + Arguments.of(new Request("RFC7239 Examples: Section 7 (spaced)") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "Forwarded: for=192.0.2.43, for=\"[2001:db8:cafe::17]\", for=unknown" + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(80) + .requestURL("http://myhost/") + .remoteAddr("192.0.2.43").remotePort(0) + ), + + // (same as above, but as multiple headers, as shown in RFC section 7.1) + Arguments.of(new Request("RFC7239 Examples: Section 7 (multi header)") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "Forwarded: for=192.0.2.43", + "Forwarded: for=\"[2001:db8:cafe::17]\", for=unknown" + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(80) + .requestURL("http://myhost/") + .remoteAddr("192.0.2.43").remotePort(0) + ), + + // https://tools.ietf.org/html/rfc7239#section-7.4 - Transition + Arguments.of(new Request("RFC7239 Examples: Section 7.4 (old syntax)") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "X-Forwarded-For: 192.0.2.43, 2001:db8:cafe::17" + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(80) + .requestURL("http://myhost/") + .remoteAddr("192.0.2.43").remotePort(0) + ), + Arguments.of(new Request("RFC7239 Examples: Section 7.4 (new syntax)") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "Forwarded: for=192.0.2.43, for=\"[2001:db8:cafe::17]\"" + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(80) + .requestURL("http://myhost/") + .remoteAddr("192.0.2.43").remotePort(0) + ), + + // https://tools.ietf.org/html/rfc7239#section-7.5 - Example Usage + Arguments.of(new Request("RFC7239 Examples: Section 7.5") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "Forwarded: for=192.0.2.43,for=198.51.100.17;by=203.0.113.60;proto=http;host=example.com" + ), + new Expectations() + .scheme("http").serverName("example.com").serverPort(80) + .requestURL("http://example.com/") + .remoteAddr("192.0.2.43").remotePort(0) + ), + + // Forwarded, proto only + Arguments.of(new Request("RFC7239: Forwarded proto only") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "Forwarded: proto=https" + ), + new Expectations() + .scheme("https").serverName("myhost").serverPort(443) + .requestURL("https://myhost/") + ), + + // ================================================================= + // X-Forwarded-* usages + Arguments.of(new Request("X-Forwarded-Proto (old syntax)") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "X-Forwarded-Proto: https" + ), + new Expectations() + .scheme("https").serverName("myhost").serverPort(443) + .requestURL("https://myhost/") + ), + Arguments.of(new Request("X-Forwarded-For (multiple headers)") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "X-Forwarded-For: 10.9.8.7,6.5.4.3", + "X-Forwarded-For: 8.9.8.7,7.5.4.3" + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(80) + .requestURL("http://myhost/") + .remoteAddr("10.9.8.7").remotePort(0) + ), + Arguments.of(new Request("X-Forwarded-For (IPv4 with port)") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "X-Forwarded-For: 10.9.8.7:1111,6.5.4.3:2222" + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(80) + .requestURL("http://myhost/") + .remoteAddr("10.9.8.7").remotePort(1111) + ), + Arguments.of(new Request("X-Forwarded-For (IPv6 with port)") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "X-Forwarded-For: [2001:db8:cafe::17]:1111,6.5.4.3:2222" + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(80) + .requestURL("http://myhost/") + .remoteAddr("[2001:db8:cafe::17]").remotePort(1111) + ), + Arguments.of(new Request("X-Forwarded-For and X-Forwarded-Port (once)") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "X-Forwarded-For: 1:2:3:4:5:6:7:8", + "X-Forwarded-Port: 2222" + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(2222) + .requestURL("http://myhost:2222/") + .remoteAddr("[1:2:3:4:5:6:7:8]").remotePort(0) + ), + Arguments.of(new Request("X-Forwarded-For and X-Forwarded-Port (multiple times)") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "X-Forwarded-Port: 2222", // this wins + "X-Forwarded-For: 1:2:3:4:5:6:7:8", // this wins + "X-Forwarded-For: 7:7:7:7:7:7:7:7", // ignored + "X-Forwarded-Port: 3333" // ignored + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(2222) + .requestURL("http://myhost:2222/") + .remoteAddr("[1:2:3:4:5:6:7:8]").remotePort(0) + ), + Arguments.of(new Request("X-Forwarded-Port") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "X-Forwarded-Port: 4444", // resets server port + "X-Forwarded-For: 192.168.1.200" + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(4444) + .requestURL("http://myhost:4444/") + .remoteAddr("192.168.1.200").remotePort(0) + ), + Arguments.of(new Request("X-Forwarded-Port (ForwardedPortAsAuthority==false)") + .configureCustomizer((customizer) -> customizer.setForwardedPortAsAuthority(false)) + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "X-Forwarded-Port: 4444", + "X-Forwarded-For: 192.168.1.200" + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(80) + .requestURL("http://myhost/") + .remoteAddr("192.168.1.200").remotePort(4444) + ), + Arguments.of(new Request("X-Forwarded-Port for Late Host header") + .headers( + "GET / HTTP/1.1", + "X-Forwarded-Port: 4444", // this order is intentional + "X-Forwarded-For: 192.168.1.200", + "Host: myhost" // leave this as last header + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(4444) + .requestURL("http://myhost:4444/") + .remoteAddr("192.168.1.200").remotePort(0) + ), + Arguments.of(new Request("X-Forwarded-* (all headers)") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "X-Forwarded-Proto: https", + "X-Forwarded-Host: www.example.com", + "X-Forwarded-Port: 4333", + "X-Forwarded-For: 8.5.4.3:2222", + "X-Forwarded-Server: fw.example.com" + ), + new Expectations() + .scheme("https").serverName("www.example.com").serverPort(4333) + .requestURL("https://www.example.com:4333/") + .remoteAddr("8.5.4.3").remotePort(2222) + ), + + // ================================================================= + // Mixed Behavior + Arguments.of(new Request("RFC7239 mixed with X-Forwarded-* headers") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "X-Forwarded-For: 11.9.8.7:1111,8.5.4.3:2222", + "X-Forwarded-Port: 3333", + "Forwarded: for=192.0.2.43,for=198.51.100.17;by=203.0.113.60;proto=http;host=example.com", + "X-Forwarded-For: 11.9.8.7:1111,8.5.4.3:2222" + ), + new Expectations() + .scheme("http").serverName("example.com").serverPort(80) + .requestURL("http://example.com/") + .remoteAddr("192.0.2.43").remotePort(0) + ), + + // ================================================================= + // Legacy Headers + Arguments.of(new Request("X-Proxied-Https") + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "X-Proxied-Https: on" + ), + new Expectations() + .scheme("https").serverName("myhost").serverPort(443) + .requestURL("https://myhost/") + .remoteAddr("0.0.0.0").remotePort(0) + ), + Arguments.of(new Request("Proxy-Ssl-Id (setSslIsSecure==false)") + .configureCustomizer((customizer) -> customizer.setSslIsSecure(false)) + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "Proxy-Ssl-Id: Wibble" + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(80) + .requestURL("http://myhost/") + .remoteAddr("0.0.0.0").remotePort(0) + .sslSession("Wibble") + ), + Arguments.of(new Request("Proxy-Ssl-Id (setSslIsSecure==true)") + .configureCustomizer((customizer) -> customizer.setSslIsSecure(true)) + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "Proxy-Ssl-Id: 0123456789abcdef" + ), + new Expectations() + .scheme("https").serverName("myhost").serverPort(443) + .requestURL("https://myhost/") + .remoteAddr("0.0.0.0").remotePort(0) + .sslSession("0123456789abcdef") + ), + Arguments.of(new Request("Proxy-Auth-Cert (setSslIsSecure==false)") + .configureCustomizer((customizer) -> customizer.setSslIsSecure(false)) + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "Proxy-auth-cert: Wibble" + ), + new Expectations() + .scheme("http").serverName("myhost").serverPort(80) + .requestURL("http://myhost/") + .remoteAddr("0.0.0.0").remotePort(0) + .sslCertificate("Wibble") + ), + Arguments.of(new Request("Proxy-Auth-Cert (setSslIsSecure==true)") + .configureCustomizer((customizer) -> customizer.setSslIsSecure(true)) + .headers( + "GET / HTTP/1.1", + "Host: myhost", + "Proxy-auth-cert: 0123456789abcdef" + ), + new Expectations() + .scheme("https").serverName("myhost").serverPort(443) + .requestURL("https://myhost/") + .remoteAddr("0.0.0.0").remotePort(0) + .sslCertificate("0123456789abcdef") + ) + ); } - @Test - public void testHostIpv6() throws Exception + @ParameterizedTest(name = "{0}") + @MethodSource("cases") + @SuppressWarnings("unused") + public void testDefaultBehavior(Request request, Expectations expectations) throws Exception { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: [::1]:2222\n" + - "\n")); + request.configure(customizer); + + String rawRequest = request.getRawRequest((header) -> header); + System.out.println(rawRequest); + + HttpTester.Response response = HttpTester.parseResponse(connector.getResponse(rawRequest)); assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("[::1]")); - assertThat("serverPort", _serverPort.get(), is(2222)); - assertThat("requestURL", _requestURL.get(), is("http://[::1]:2222/")); + + expectations.accept(actual); } - @Test - public void testURIIpv4() throws Exception + @ParameterizedTest(name = "{0}") + @MethodSource("cases") + @SuppressWarnings("unused") + public void testConfiguredBehavior(Request request, Expectations expectations) throws Exception { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET http://1.2.3.4:2222/ HTTP/1.1\n" + - "Host: wrong\n" + - "\n")); + request.configure(customizerConfigured); + + String rawRequest = request.getRawRequest((header) -> header + .replaceFirst("X-Forwarded-", "Jetty-Forwarded-") + .replaceFirst("Forwarded:", "Jetty-Forwarded:") + .replaceFirst("X-Proxied-Https:", "Jetty-Proxied-Https:") + .replaceFirst("Proxy-Ssl-Id:", "Jetty-Proxy-Ssl-Id:") + .replaceFirst("Proxy-auth-cert:", "Jetty-Proxy-Auth-Cert:")); + System.out.println(rawRequest); + + HttpTester.Response response = HttpTester.parseResponse(connectorConfigured.getResponse(rawRequest)); assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("1.2.3.4")); - assertThat("serverPort", _serverPort.get(), is(2222)); - assertThat("requestURL", _requestURL.get(), is("http://1.2.3.4:2222/")); + + expectations.accept(actual); } - @Test - public void testURIIpv6() throws Exception + private static class Request { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET http://[::1]:2222/ HTTP/1.1\n" + - "Host: wrong\n" + - "\n")); - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("[::1]")); - assertThat("serverPort", _serverPort.get(), is(2222)); - assertThat("requestURL", _requestURL.get(), is("http://[::1]:2222/")); + String description; + String[] requestHeaders; + Consumer forwardedRequestCustomizerConsumer; + + public Request(String description) + { + this.description = description; + } + + public Request headers(String... headers) + { + this.requestHeaders = headers; + return this; + } + + public Request configureCustomizer(Consumer forwardedRequestCustomizerConsumer) + { + this.forwardedRequestCustomizerConsumer = forwardedRequestCustomizerConsumer; + return this; + } + + public void configure(ForwardedRequestCustomizer customizer) + { + if (forwardedRequestCustomizerConsumer != null) + { + forwardedRequestCustomizerConsumer.accept(customizer); + } + } + + public String getRawRequest(Function headerManip) + { + StringBuilder request = new StringBuilder(); + for (String header : requestHeaders) + { + request.append(headerManip.apply(header)).append('\n'); + } + request.append('\n'); + return request.toString(); + } + + @Override + public String toString() + { + return this.description; + } } - /** - * RFC 7239: Section 4 - * - * Examples of syntax. - */ - @Test - public void testRFC7239_Examples_4() throws Exception + private static class Expectations implements Consumer { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "Forwarded: for=\"_gazonk\"\n" + - "Forwarded: For=\"[2001:db8:cafe::17]:4711\"\n" + - "Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43\n" + - "Forwarded: for=192.0.2.43, for=198.51.100.17\n" + - "\n")); - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(80)); - assertThat("remoteAddr", _remoteAddr.get(), is("[2001:db8:cafe::17]")); - assertThat("remotePort", _remotePort.get(), is(4711)); - assertThat("requestURL", _requestURL.get(), is("http://myhost/")); - } + String expectedScheme; + String expectedServerName; + int expectedServerPort; + String expectedRequestURL; + String expectedRemoteAddr = "0.0.0.0"; + int expectedRemotePort = 0; + String expectedSslSession; + String expectedSslCertificate; - /** - * RFC 7239: Section 7.1 - * - * Examples of syntax with regards to HTTP header fields - */ - @Test - public void testRFC7239_Examples_7_1() throws Exception - { - // Without spaces - HttpTester.Response response1 = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "Forwarded: for=192.0.2.43,for=\"[2001:db8:cafe::17]\",for=unknown\n" + - "\n")); + @Override + public void accept(Actual actual) + { + assertThat("scheme", actual.scheme.get(), is(expectedScheme)); + if (actual.scheme.equals("https")) + { + assertTrue(actual.wasSecure.get(), "wasSecure"); + } + assertThat("serverName", actual.serverName.get(), is(expectedServerName)); + assertThat("serverPort", actual.serverPort.get(), is(expectedServerPort)); + assertThat("requestURL", actual.requestURL.get(), is(expectedRequestURL)); + if (expectedRemoteAddr != null) + { + assertThat("remoteAddr", actual.remoteAddr.get(), is(expectedRemoteAddr)); + assertThat("remotePort", actual.remotePort.get(), is(expectedRemotePort)); + } + if (expectedSslSession != null) + { + assertThat("sslSession", actual.sslSession.get(), is(expectedSslSession)); + } + if (expectedSslCertificate != null) + { + assertThat("sslCertificate", actual.sslCertificate.get(), is(expectedSslCertificate)); + } + } - assertThat("status", response1.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(80)); - assertThat("remoteAddr", _remoteAddr.get(), is("192.0.2.43")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("http://myhost/")); + public Expectations scheme(String scheme) + { + this.expectedScheme = scheme; + return this; + } - // With spaces - HttpTester.Response response2 = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "Forwarded: for=192.0.2.43, for=\"[2001:db8:cafe::17]\", for=unknown\n" + - "\n")); - assertThat("status", response2.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(80)); - assertThat("remoteAddr", _remoteAddr.get(), is("192.0.2.43")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("http://myhost/")); + public Expectations serverName(String name) + { + this.expectedServerName = name; + return this; + } - // As multiple headers - HttpTester.Response response3 = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "Forwarded: for=192.0.2.43\n" + - "Forwarded: for=\"[2001:db8:cafe::17]\", for=unknown\n" + - "\n")); + public Expectations serverPort(int port) + { + this.expectedServerPort = port; + return this; + } - assertThat("status", response3.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(80)); - assertThat("remoteAddr", _remoteAddr.get(), is("192.0.2.43")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("http://myhost/")); - } + public Expectations requestURL(String requestURL) + { + this.expectedRequestURL = requestURL; + return this; + } - /** - * RFC 7239: Section 7.4 - * - * Transition - */ - @Test - public void testRFC7239_Examples_7_4() throws Exception - { - // Old syntax - HttpTester.Response response1 = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "X-Forwarded-For: 192.0.2.43, 2001:db8:cafe::17\n" + - "\n")); + public Expectations remoteAddr(String remoteAddr) + { + this.expectedRemoteAddr = remoteAddr; + return this; + } - assertThat("status", response1.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(80)); - assertThat("remoteAddr", _remoteAddr.get(), is("192.0.2.43")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("http://myhost/")); + public Expectations remotePort(int remotePort) + { + this.expectedRemotePort = remotePort; + return this; + } - // New syntax - HttpTester.Response response2 = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "Forwarded: for=192.0.2.43, for=\"[2001:db8:cafe::17]\"\n" + - "\n")); + public Expectations sslSession(String sslSession) + { + this.expectedSslSession = sslSession; + return this; + } - assertThat("status", response2.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(80)); - assertThat("remoteAddr", _remoteAddr.get(), is("192.0.2.43")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("http://myhost/")); - } - - /** - * RFC 7239: Section 7.5 - * - * Example Usage - */ - @Test - public void testRFC7239_Examples_7_5() throws Exception - { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "Forwarded: for=192.0.2.43,for=198.51.100.17;by=203.0.113.60;proto=http;host=example.com\n" + - "\n")); - - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("example.com")); - assertThat("serverPort", _serverPort.get(), is(80)); - assertThat("remoteAddr", _remoteAddr.get(), is("192.0.2.43")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("http://example.com/")); - } - - @Test - public void testRFC7239_IPv6() throws Exception - { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "Forwarded: for=\"[2001:db8:cafe::1]\";by=\"[2001:db8:cafe::2]\";host=\"[2001:db8:cafe::3]:8888\"\n" + - "\n")); - - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("[2001:db8:cafe::3]")); - assertThat("serverPort", _serverPort.get(), is(8888)); - assertThat("remoteAddr", _remoteAddr.get(), is("[2001:db8:cafe::1]")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("http://[2001:db8:cafe::3]:8888/")); - } - - @Test - public void testProto_OldSyntax() throws Exception - { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "X-Forwarded-Proto: https\n" + - "\n")); - - assertTrue(_wasSecure.get(), "wasSecure"); - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("https")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(443)); - assertThat("remoteAddr", _remoteAddr.get(), is("0.0.0.0")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("https://myhost/")); - } - - @Test - public void testRFC7239_Proto() throws Exception - { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "Forwarded: proto=https\n" + - "\n")); - - assertTrue(_wasSecure.get(), "wasSecure"); - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("https")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(443)); - assertThat("remoteAddr", _remoteAddr.get(), is("0.0.0.0")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("https://myhost/")); - } - - @Test - public void testFor() throws Exception - { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "X-Forwarded-For: 10.9.8.7,6.5.4.3\n" + - "X-Forwarded-For: 8.9.8.7,7.5.4.3\n" + - "\n")); - - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(80)); - assertThat("remoteAddr", _remoteAddr.get(), is("10.9.8.7")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("http://myhost/")); - } - - @Test - public void testForIpv4WithPort() throws Exception - { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "X-Forwarded-For: 10.9.8.7:1111,6.5.4.3:2222\n" + - "\n")); - - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(80)); - assertThat("remoteAddr", _remoteAddr.get(), is("10.9.8.7")); - assertThat("remotePort", _remotePort.get(), is(1111)); - assertThat("requestURL", _requestURL.get(), is("http://myhost/")); - } - - @Test - public void testForIpv6WithPort() throws Exception - { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "X-Forwarded-For: [2001:db8:cafe::17]:1111,6.5.4.3:2222\n" + - "\n")); - - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(80)); - assertThat("remoteAddr", _remoteAddr.get(), is("[2001:db8:cafe::17]")); - assertThat("remotePort", _remotePort.get(), is(1111)); - assertThat("requestURL", _requestURL.get(), is("http://myhost/")); - } - - @Test - public void testForIpv6AndPort() throws Exception - { - HttpTester.Response response = HttpTester.parseResponse( - _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("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(2222)); - assertThat("remoteAddr", _remoteAddr.get(), is("[1:2:3:4:5:6:7:8]")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("http://myhost:2222/")); - } - - @Test - public void testForIpv6AndPort_MultiField() throws Exception - { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "X-Forwarded-Port: 2222\n" + - "X-Forwarded-For: 1:2:3:4:5:6:7:8\n" + - "X-Forwarded-For: 7:7:7:7:7:7:7:7\n" + - "X-Forwarded-Port: 3333\n" + - "\n")); - - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(2222)); - assertThat("remoteAddr", _remoteAddr.get(), is("[1:2:3:4:5:6:7:8]")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("http://myhost:2222/")); - } - - @Test - public void testLegacyProto() throws Exception - { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "X-Proxied-Https: on\n" + - "\n")); - assertTrue(_wasSecure.get(), "wasSecure"); - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("https")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(443)); - assertThat("remoteAddr", _remoteAddr.get(), is("0.0.0.0")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("https://myhost/")); - } - - @Test - public void testSslSession() throws Exception - { - _customizer.setSslIsSecure(false); - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "Proxy-Ssl-Id: Wibble\n" + - "\n")); - - assertFalse(_wasSecure.get(), "wasSecure"); - assertThat("sslSession", _sslSession.get(), is("Wibble")); - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(80)); - assertThat("remoteAddr", _remoteAddr.get(), is("0.0.0.0")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("http://myhost/")); - - _customizer.setSslIsSecure(true); - response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "Proxy-Ssl-Id: 0123456789abcdef\n" + - "\n")); - - assertTrue(_wasSecure.get(), "wasSecure"); - assertThat("sslSession", _sslSession.get(), is("0123456789abcdef")); - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("https")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(443)); - assertThat("remoteAddr", _remoteAddr.get(), is("0.0.0.0")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("https://myhost/")); - } - - @Test - public void testSslCertificate() throws Exception - { - _customizer.setSslIsSecure(false); - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "Proxy-auth-cert: Wibble\n" + - "\n")); - - assertFalse(_wasSecure.get(), "wasSecure"); - assertThat("sslCertificate", _sslCertificate.get(), is("Wibble")); - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(80)); - assertThat("remoteAddr", _remoteAddr.get(), is("0.0.0.0")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("http://myhost/")); - - _customizer.setSslIsSecure(true); - response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "Proxy-auth-cert: 0123456789abcdef\n" + - "\n")); - - assertTrue(_wasSecure.get(), "wasSecure"); - assertThat("sslCertificate", _sslCertificate.get(), is("0123456789abcdef")); - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("https")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(443)); - assertThat("remoteAddr", _remoteAddr.get(), is("0.0.0.0")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("https://myhost/")); - } - - /** - * Resetting the server port via a forwarding header - */ - @Test - public void testPort_For() throws Exception - { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "X-Forwarded-Port: 4444\n" + - "X-Forwarded-For: 192.168.1.200\n" + - "\n")); - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(4444)); - assertThat("remoteAddr", _remoteAddr.get(), is("192.168.1.200")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("http://myhost:4444/")); - } - - /** - * Resetting the server port via a forwarding header - */ - @Test - public void testRemote_Port_For() throws Exception - { - _customizer.setForwardedPortAsAuthority(false); - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "X-Forwarded-Port: 4444\n" + - "X-Forwarded-For: 192.168.1.200\n" + - "\n")); - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(80)); - assertThat("remoteAddr", _remoteAddr.get(), is("192.168.1.200")); - assertThat("remotePort", _remotePort.get(), is(4444)); - assertThat("requestURL", _requestURL.get(), is("http://myhost/")); - } - - /** - * Test setting the server Port before the "Host" header has been seen. - */ - @Test - public void testPort_For_LateHost() throws Exception - { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "X-Forwarded-Port: 4444\n" + // this order is intentional - "X-Forwarded-For: 192.168.1.200\n" + - "Host: myhost\n" + // leave this as the last header - "\n")); - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("myhost")); - assertThat("serverPort", _serverPort.get(), is(4444)); - assertThat("remoteAddr", _remoteAddr.get(), is("192.168.1.200")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("http://myhost:4444/")); - } - - @Test - public void testMixed_For_Port_RFC_For() throws Exception - { - HttpTester.Response response = HttpTester.parseResponse( - _connector.getResponse( - "GET / HTTP/1.1\n" + - "Host: myhost\n" + - "X-Forwarded-For: 11.9.8.7:1111,8.5.4.3:2222\n" + - "X-Forwarded-Port: 3333\n" + - "Forwarded: for=192.0.2.43,for=198.51.100.17;by=203.0.113.60;proto=http;host=example.com\n" + - "X-Forwarded-For: 11.9.8.7:1111,8.5.4.3:2222\n" + - "\n")); - - assertThat("status", response.getStatus(), is(200)); - assertThat("scheme", _scheme.get(), is("http")); - assertThat("serverName", _serverName.get(), is("example.com")); - assertThat("serverPort", _serverPort.get(), is(80)); - assertThat("remoteAddr", _remoteAddr.get(), is("192.0.2.43")); - assertThat("remotePort", _remotePort.get(), is(0)); - assertThat("requestURL", _requestURL.get(), is("http://example.com/")); + public Expectations sslCertificate(String sslCertificate) + { + this.expectedSslCertificate = sslCertificate; + return this; + } } interface RequestTester @@ -653,14 +665,15 @@ public class ForwardedRequestCustomizerTest private class RequestHandler extends AbstractHandler { - private RequestTester _checker; + private RequestTester requestTester; @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, org.eclipse.jetty.server.Request baseRequest, + HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { baseRequest.setHandled(true); - if (_checker != null && _checker.check(request, response)) + if (requestTester != null && requestTester.check(request, response)) response.setStatus(200); else response.sendError(500); diff --git a/pom.xml b/pom.xml index bcc75bd57f6..5d36e43b1a6 100644 --- a/pom.xml +++ b/pom.xml @@ -304,7 +304,7 @@ attach-sources process-classes - jar-no-fork + jar @@ -548,11 +548,6 @@ - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - org.apache.maven.plugins maven-javadoc-plugin @@ -1267,7 +1262,6 @@ - diff --git a/scripts/release-jetty.sh b/scripts/release-jetty.sh index a98a762814e..57ae4c9afbd 100755 --- a/scripts/release-jetty.sh +++ b/scripts/release-jetty.sh @@ -167,7 +167,7 @@ if proceedyn "Are you sure you want to release using above? (y/N)" n; then # This is equivalent to 'mvn release:perform' if proceedyn "Build/Deploy from tag $TAG_NAME? (Y/n)" y; then git checkout $TAG_NAME - mvn clean package gpg:sign javadoc:aggregate-jar deploy \ + mvn clean package source:jar javadoc:jar gpg:sign javadoc:aggregate-jar deploy \ -Peclipse-release $DEPLOY_OPTS reportMavenTestFailures git checkout $GIT_BRANCH_ID diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/CDITests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/CDITests.java index 9153d4bb76d..533947eee07 100644 --- a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/CDITests.java +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/CDITests.java @@ -42,12 +42,13 @@ public class CDITests extends AbstractDistributionTest // Tests from here use these parameters public static Stream tests() { - Consumer removeJettyWebXml = d -> + Consumer renameJettyWebOwbXml = d -> { try { + Path jettyWebOwbXml = d.getJettyBase().resolve("webapps/demo/WEB-INF/jetty-web-owb.xml"); Path jettyWebXml = d.getJettyBase().resolve("webapps/demo/WEB-INF/jetty-web.xml"); - Files.deleteIfExists(jettyWebXml); + Files.move(jettyWebOwbXml, jettyWebXml); } catch(IOException e) { @@ -62,7 +63,7 @@ public class CDITests extends AbstractDistributionTest // TODO Arguments.of("weld", "cdi-decorate", null), // Weld >= 3.1.3 // -- Apache OpenWebBeans -- - Arguments.of("owb", "cdi-spi", removeJettyWebXml) + Arguments.of("owb", "jsp", renameJettyWebOwbXml) // Arguments.of("owb", "decorate", null), // Not supported // Arguments.of("owb", "cdi-decorate", null) // Not supported ); @@ -85,7 +86,7 @@ public class CDITests extends AbstractDistributionTest String[] args1 = { "--create-startd", "--approve-all-licenses", - "--add-to-start=http,deploy,annotations,jsp,"+integration + "--add-to-start=http,deploy,annotations,jsp" + (integration==null?"":(","+integration)) }; try (DistributionTester.Run run1 = distribution.start(args1)) { diff --git a/tests/test-webapps/test-cdi-common-webapp/src/main/webapp/index.html b/tests/test-webapps/test-cdi-common-webapp/src/main/webapp/index.html index 9beca9836d8..a1765080059 100644 --- a/tests/test-webapps/test-cdi-common-webapp/src/main/webapp/index.html +++ b/tests/test-webapps/test-cdi-common-webapp/src/main/webapp/index.html @@ -1,4 +1,4 @@ -

OWB CDI Test Webapp

+

CDI Test Webapp

CDI Info

diff --git a/tests/test-webapps/test-owb-cdi-webapp/pom.xml b/tests/test-webapps/test-owb-cdi-webapp/pom.xml index 9ab476f7ab8..95a25c5a629 100644 --- a/tests/test-webapps/test-owb-cdi-webapp/pom.xml +++ b/tests/test-webapps/test-owb-cdi-webapp/pom.xml @@ -16,7 +16,7 @@ - weld-owb-demo + owb-cdi-demo diff --git a/tests/test-webapps/test-owb-cdi-webapp/src/main/webapp/WEB-INF/jetty-web.xml b/tests/test-webapps/test-owb-cdi-webapp/src/main/webapp/WEB-INF/jetty-web-owb.xml similarity index 82% rename from tests/test-webapps/test-owb-cdi-webapp/src/main/webapp/WEB-INF/jetty-web.xml rename to tests/test-webapps/test-owb-cdi-webapp/src/main/webapp/WEB-INF/jetty-web-owb.xml index 3451e096f4b..0291691bbfb 100644 --- a/tests/test-webapps/test-owb-cdi-webapp/src/main/webapp/WEB-INF/jetty-web.xml +++ b/tests/test-webapps/test-owb-cdi-webapp/src/main/webapp/WEB-INF/jetty-web-owb.xml @@ -1,7 +1,7 @@ - +