diff --git a/.gitignore b/.gitignore index 2ae9eb757e6..918c60f7fc3 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,6 @@ bin/ # test generated content */src/test/*/WEB-INF/lib/test*.jar .flattened-pom.xml + +# reports +reports/ diff --git a/Jenkinsfile-autobahn b/Jenkinsfile-autobahn index 0e92efd217d..374830be9e8 100644 --- a/Jenkinsfile-autobahn +++ b/Jenkinsfile-autobahn @@ -17,11 +17,9 @@ pipeline { node { label 'linux' } } steps { - container( 'jetty-build' ) { - timeout( time: 120, unit: 'MINUTES' ) { - mavenBuild( "jdk11", "-T3 clean install -Djacoco.skip=true -Pautobahn", "maven3", true ) // - junit testResults: '**/target/surefire-reports/*.xml,**/target/invoker-reports/TEST*.xml,**/target/autobahntestsuite-reports/*.xml' - } + timeout( time: 120, unit: 'MINUTES' ) { + mavenBuild( "jdk11", "-T3 clean install -Djacoco.skip=true -Pautobahn", "maven3", true ) // + junit testResults: '**/target/surefire-reports/*.xml,**/target/invoker-reports/TEST*.xml,**/target/autobahntestsuite-reports/*.xml' } } } diff --git a/Jenkinsfile-dependency-report b/Jenkinsfile-dependency-report new file mode 100644 index 00000000000..e25e11830ab --- /dev/null +++ b/Jenkinsfile-dependency-report @@ -0,0 +1,46 @@ +#!groovy + +pipeline { + agent any + triggers { + pollSCM('@weekly') + } + options { + skipDefaultCheckout() + buildDiscarder logRotator( numToKeepStr: '50' ) + // save some io during the build + durabilityHint( 'PERFORMANCE_OPTIMIZED' ) + } + parameters { + string( defaultValue: 'jetty-12.0.x', description: 'Jetty branch to build', + name: 'JETTY_BRANCH' ) + } + stages { + stage( "Build / Dependency Report" ) { + agent { + node { label 'linux' } + } + steps { + timeout( time: 120, unit: 'MINUTES' ) { + withEnv(["JAVA_HOME=${ tool "jdk17" }", + "PATH+MAVEN=${ tool "jdk17" }/bin:${tool "maven3"}/bin", + "MAVEN_OPTS=-Xms2g -Xmx4g -Djava.awt.headless=true"]) { + checkout([$class: 'GitSCM', + branches: [[name: "$JETTY_BRANCH"]], + extensions: [[$class: 'CloneOption', depth: 1, noTags: true, shallow: true, reference: "/home/jenkins/jetty.project.git"]], + userRemoteConfigs: [[url: 'https://github.com/eclipse/jetty.project.git']]]) + sh "mvn install -ntp -DskipTests -T5" + sh "bash ./build/scripts/dependency-update-reports.sh" + publishHTML([allowMissing: false, alwaysLinkToLastBuild: true, keepAll: true, reportDir: "reports/dependency-update-reports/", reportFiles: 'dependency-updates-report-*.html', reportName: 'Dependencies Report', reportTitles: '']) + } + } + } + } + } +} + + + + + +// vim: et:ts=2:sw=2:ft=groovy diff --git a/build/scripts/dependency-update-reports.sh b/build/scripts/dependency-update-reports.sh new file mode 100755 index 00000000000..c8fcde4d72f --- /dev/null +++ b/build/scripts/dependency-update-reports.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +echo "# This script is meant to be run from the root of the project" +echo "[jetty.project-12.0.0x]$ build/scripts/dependency-updates-report.sh" + +PWD=$(pwd) +REPORT_OUTPUT_DIR=$PWD/reports/dependency-update-reports/ + +if [ -d $REPORT_OUTPUT_DIR ] ; then + rm -rf $REPORT_OUTPUT_DIR/* +fi + +mkdir -p $REPORT_OUTPUT_DIR + +echo "HTML Reports can be found in $REPORT_OUTPUT_DIR" + +mvn -N -B -Pdependency-updates-reports validate + +cp -Rv target/site/* $REPORT_OUTPUT_DIR +mv $REPORT_OUTPUT_DIR/dependency-updates-aggregate-report.html $REPORT_OUTPUT_DIR/dependency-updates-report-root.html + +pushd jetty-core +mvn -B -Pdependency-updates-reports validate +cp target/site/dependency-updates-aggregate-report.html $REPORT_OUTPUT_DIR/dependency-updates-report-core.html +popd + +pushd jetty-ee10 +mvn -B -Pdependency-updates-reports validate +cp target/site/dependency-updates-aggregate-report.html $REPORT_OUTPUT_DIR/dependency-updates-report-ee10.html +popd + +pushd jetty-ee9 +mvn -B -Pdependency-updates-reports validate +cp target/site/dependency-updates-aggregate-report.html $REPORT_OUTPUT_DIR/dependency-updates-report-ee9.html +popd + +pushd jetty-ee8 +mvn -B -Pdependency-updates-reports validate +cp target/site/dependency-updates-aggregate-report.html $REPORT_OUTPUT_DIR/dependency-updates-report-ee8.html +popd + +echo "HTML Reports can be found in $REPORT_OUTPUT_DIR" diff --git a/documentation/jetty-documentation/src/main/asciidoc/programming-guide/client/http/client-http-configuration.adoc b/documentation/jetty-documentation/src/main/asciidoc/programming-guide/client/http/client-http-configuration.adoc index bc9966e0036..62e47d66c1a 100644 --- a/documentation/jetty-documentation/src/main/asciidoc/programming-guide/client/http/client-http-configuration.adoc +++ b/documentation/jetty-documentation/src/main/asciidoc/programming-guide/client/http/client-http-configuration.adoc @@ -30,7 +30,7 @@ The most common parameters are: `HttpClient` supports HTTPS requests out-of-the-box like a browser does. -The support for HTTPS request is provided by a `SslContextFactory.Client`, typically configured in the `ClientConnector`. +The support for HTTPS request is provided by a `SslContextFactory.Client` instance, typically configured in the `ClientConnector`. If not explicitly configured, the `ClientConnector` will allocate a default one when started. [source,java,indent=0] @@ -38,29 +38,34 @@ If not explicitly configured, the `ClientConnector` will allocate a default one include::../../{doc_code}/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java[tags=tlsExplicit] ---- -The default `SslContextFactory.Client` verifies the certificate sent by the server by verifying the certificate chain. -This means that requests to public websites that have a valid certificate (such as ``https://google.com``) will work out-of-the-box. +The default `SslContextFactory.Client` verifies the certificate sent by the server by verifying the validity of the certificate with respect to the certificate chain, the expiration date, the server host name, etc. +This means that requests to public websites that have a valid certificate (such as `+https://google.com+`) will work out-of-the-box, without the need to specify a KeyStore or a TrustStore. -However, requests made to sites (typically ``localhost``) that have an invalid (for example, expired or with a wrong host) or self-signed certificate will fail (like they will in a browser). +However, requests made to sites that return an invalid or a self-signed certificate will fail (like they will in a browser). +An invalid certificate may be expired or have the wrong server host name; a self-signed certificate has a certificate chain that cannot be verified. -Certificate validation is performed at two levels: at the TLS implementation level (in the JDK) and, optionally, at the application level. +The validation of the server host name present in the certificate is important, to guarantee that the client is connected indeed with the intended server. -By default, certificate validation at the TLS level is enabled, while certificate validation at the application level is disabled. +The validation of the server host name is performed at two levels: at the TLS level (in the JDK) and, optionally, at the application level. -You can configure the `SslContextFactory.Client` to skip certificate validation at the TLS level: +By default, the validation of the server host name at the TLS level is enabled, while it is disabled at the application level. + +You can configure the `SslContextFactory.Client` to skip the validation of the server host name at the TLS level: [source,java,indent=0] ---- include::../../{doc_code}/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java[tags=tlsNoValidation] ---- -You can enable certificate validation at the application level: +When you disable the validation of the server host name at the TLS level, you are strongly recommended to enable it at the application level, otherwise you may risk to connect to a server different from the one you intend to connect to: [source,java,indent=0] ---- include::../../{doc_code}/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java[tags=tlsAppValidation] ---- +You may have the validation of the server host name enabled at both the TLS level and application level, typically when you want to further restrict the client to connect only to a smaller set of server hosts than those allowed in the certificate sent by the server. + Please refer to the `SslContextFactory.Client` link:{javadoc-url}/org/eclipse/jetty/util/ssl/SslContextFactory.Client.html[javadocs] for the complete list of configurable parameters. [[pg-client-http-configuration-tls-truststore]] diff --git a/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java b/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java index 0517ee8268f..f61c19a97ca 100644 --- a/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java +++ b/documentation/jetty-documentation/src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java @@ -127,7 +127,7 @@ public class HTTPClientDocs { // tag::tlsNoValidation[] SslContextFactory.Client sslContextFactory = new SslContextFactory.Client(); - // Disable certificate validation at the TLS level. + // Disable the validation of the server host name at the TLS level. sslContextFactory.setEndpointIdentificationAlgorithm(null); // end::tlsNoValidation[] } @@ -136,7 +136,7 @@ public class HTTPClientDocs { // tag::tlsAppValidation[] SslContextFactory.Client sslContextFactory = new SslContextFactory.Client(); - // Only allow subdomains of domain.com. + // Only allow to connect to subdomains of domain.com. sslContextFactory.setHostnameVerifier((hostName, session) -> hostName.endsWith(".domain.com")); // end::tlsAppValidation[] } diff --git a/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/transport/internal/HttpChannelOverHTTP.java b/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/transport/internal/HttpChannelOverHTTP.java index 842a6dcd711..f34ddf9b11a 100644 --- a/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/transport/internal/HttpChannelOverHTTP.java +++ b/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/transport/internal/HttpChannelOverHTTP.java @@ -22,7 +22,6 @@ import org.eclipse.jetty.client.transport.HttpExchange; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpHeaderValue; -import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; @@ -98,14 +97,16 @@ public class HttpChannelOverHTTP extends HttpChannel String method = exchange.getRequest().getMethod(); Response response = result.getResponse(); + int status = response.getStatus(); HttpFields responseHeaders = response.getHeaders(); + boolean isTunnel = isTunnel(method, status); String closeReason = null; if (result.isFailed()) closeReason = "failure"; else if (receiver.isShutdown()) closeReason = "server close"; - else if (sender.isShutdown() && response.getStatus() != HttpStatus.SWITCHING_PROTOCOLS_101) + else if (sender.isShutdown() && status != HttpStatus.SWITCHING_PROTOCOLS_101) closeReason = "client close"; if (closeReason == null) @@ -113,16 +114,15 @@ public class HttpChannelOverHTTP extends HttpChannel if (response.getVersion().compareTo(HttpVersion.HTTP_1_1) < 0) { // HTTP 1.0 must close the connection unless it has - // an explicit keep alive or it's a CONNECT method. + // an explicit keep alive or it is a CONNECT tunnel. boolean keepAlive = responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()); - boolean connect = HttpMethod.CONNECT.is(method); - if (!keepAlive && !connect) + if (!keepAlive && !isTunnel) closeReason = "http/1.0"; } else { - // HTTP 1.1 closes only if it has an explicit close. - if (responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString())) + // HTTP 1.1 closes only if it has an explicit close, unless it is a CONNECT tunnel. + if (responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString()) && !isTunnel) closeReason = "http/1.1"; } } @@ -138,8 +138,7 @@ public class HttpChannelOverHTTP extends HttpChannel } else { - int status = response.getStatus(); - if (status == HttpStatus.SWITCHING_PROTOCOLS_101 || isTunnel(method, status)) + if (status == HttpStatus.SWITCHING_PROTOCOLS_101 || isTunnel) connection.remove(); else release(); diff --git a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java index 882e8bd3819..e1bdd2636e9 100644 --- a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java +++ b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java @@ -44,7 +44,8 @@ import org.slf4j.LoggerFactory; public class PathMappings extends AbstractMap implements Iterable>, Dumpable { private static final Logger LOG = LoggerFactory.getLogger(PathMappings.class); - + // In prefix matches, this is the length ("/*".length() + 1) - used for the best prefix match loop + private static final int PREFIX_TAIL_LEN = 3; private final Set> _mappings = new TreeSet<>(Map.Entry.comparingByKey()); /** @@ -220,11 +221,14 @@ public class PathMappings extends AbstractMap implements Iterabl // Try a prefix match MappedResource prefix = _prefixMap.getBest(path); - if (prefix != null) + while (prefix != null) { - MatchedPath matchedPath = prefix.getPathSpec().matched(path); + PathSpec pathSpec = prefix.getPathSpec(); + MatchedPath matchedPath = pathSpec.matched(path); if (matchedPath != null) - return new MatchedResource<>(prefix.getResource(), prefix.getPathSpec(), matchedPath); + return new MatchedResource<>(prefix.getResource(), pathSpec, matchedPath); + int specLength = pathSpec.getSpecLength(); + prefix = specLength > PREFIX_TAIL_LEN ? _prefixMap.getBest(path, 0, specLength - PREFIX_TAIL_LEN) : null; } // Try a suffix match @@ -238,13 +242,13 @@ public class PathMappings extends AbstractMap implements Iterabl // Loop 3: "foo" while ((i = path.indexOf('.', i + 1)) > 0) { - prefix = _suffixMap.get(path, i + 1, path.length() - i - 1); - if (prefix == null) + MappedResource suffix = _suffixMap.get(path, i + 1, path.length() - i - 1); + if (suffix == null) continue; - MatchedPath matchedPath = prefix.getPathSpec().matched(path); + MatchedPath matchedPath = suffix.getPathSpec().matched(path); if (matchedPath != null) - return new MatchedResource<>(prefix.getResource(), prefix.getPathSpec(), matchedPath); + return new MatchedResource<>(suffix.getResource(), suffix.getPathSpec(), matchedPath); } } @@ -301,12 +305,15 @@ public class PathMappings extends AbstractMap implements Iterabl { if (_optimizedPrefix) { - MappedResource candidate = _prefixMap.getBest(path); - if (candidate != null) + MappedResource prefix = _prefixMap.getBest(path); + while (prefix != null) { - matchedPath = candidate.getPathSpec().matched(path); + PathSpec pathSpec = prefix.getPathSpec(); + matchedPath = pathSpec.matched(path); if (matchedPath != null) - return new MatchedResource<>(candidate.getResource(), candidate.getPathSpec(), matchedPath); + return new MatchedResource<>(prefix.getResource(), pathSpec, matchedPath); + int specLength = pathSpec.getSpecLength(); + prefix = specLength > PREFIX_TAIL_LEN ? _prefixMap.getBest(path, 0, specLength - PREFIX_TAIL_LEN) : null; } // If we reached here, there's NO optimized PREFIX Match possible, skip simple match below @@ -327,13 +334,13 @@ public class PathMappings extends AbstractMap implements Iterabl // Loop 3: "foo" while ((i = path.indexOf('.', i + 1)) > 0) { - MappedResource candidate = _suffixMap.get(path, i + 1, path.length() - i - 1); - if (candidate == null) + MappedResource suffix = _suffixMap.get(path, i + 1, path.length() - i - 1); + if (suffix == null) continue; - matchedPath = candidate.getPathSpec().matched(path); + matchedPath = suffix.getPathSpec().matched(path); if (matchedPath != null) - return new MatchedResource<>(candidate.getResource(), candidate.getPathSpec(), matchedPath); + return new MatchedResource<>(suffix.getResource(), suffix.getPathSpec(), matchedPath); } // If we reached here, there's NO optimized SUFFIX Match possible, skip simple match below skipRestOfGroup = true; diff --git a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/PathMappingsTest.java b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/PathMappingsTest.java index 0d574a096a4..55676bd15db 100644 --- a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/PathMappingsTest.java +++ b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/pathmap/PathMappingsTest.java @@ -94,6 +94,55 @@ public class PathMappingsTest assertMatch(p, "/", "any"); } + /** + * Test the match order rules imposed by the Servlet API (any vs specific sub-dir) + */ + @Test + public void testServletMatchPrefix() + { + PathMappings p = new PathMappings<>(); + + p.put(new ServletPathSpec("/*"), "any"); + p.put(new ServletPathSpec("/foo/*"), "foo"); + p.put(new ServletPathSpec("/food/*"), "food"); + p.put(new ServletPathSpec("/a/*"), "a"); + p.put(new ServletPathSpec("/a/b/*"), "ab"); + + assertMatch(p, "/abs/path", "any"); + assertMatch(p, "/abs/foo/bar", "any"); + assertMatch(p, "/foo/bar", "foo"); + assertMatch(p, "/", "any"); + assertMatch(p, "/foo", "foo"); + assertMatch(p, "/fo", "any"); + assertMatch(p, "/foobar", "any"); + assertMatch(p, "/foob", "any"); + assertMatch(p, "/food", "food"); + assertMatch(p, "/food/zed", "food"); + assertMatch(p, "/foodie", "any"); + assertMatch(p, "/a/bc", "a"); + assertMatch(p, "/a/b/c", "ab"); + assertMatch(p, "/a/", "a"); + assertMatch(p, "/a", "a"); + + // Try now with order important + p.put(new RegexPathSpec("/other.*/"), "other"); + assertMatch(p, "/abs/path", "any"); + assertMatch(p, "/abs/foo/bar", "any"); + assertMatch(p, "/foo/bar", "foo"); + assertMatch(p, "/", "any"); + assertMatch(p, "/foo", "foo"); + assertMatch(p, "/fo", "any"); + assertMatch(p, "/foobar", "any"); + assertMatch(p, "/foob", "any"); + assertMatch(p, "/food", "food"); + assertMatch(p, "/food/zed", "food"); + assertMatch(p, "/foodie", "any"); + assertMatch(p, "/a/bc", "a"); + assertMatch(p, "/a/b/c", "ab"); + assertMatch(p, "/a/", "a"); + assertMatch(p, "/a", "a"); + } + /** * Test the match order rules with a mixed Servlet and URI Template path specs * diff --git a/jetty-core/jetty-tests/jetty-test-client-transports/src/test/java/org/eclipse/jetty/test/client/transport/HttpClientStreamTest.java b/jetty-core/jetty-tests/jetty-test-client-transports/src/test/java/org/eclipse/jetty/test/client/transport/HttpClientStreamTest.java index c22faf9fa7d..f9f250233ea 100644 --- a/jetty-core/jetty-tests/jetty-test-client-transports/src/test/java/org/eclipse/jetty/test/client/transport/HttpClientStreamTest.java +++ b/jetty-core/jetty-tests/jetty-test-client-transports/src/test/java/org/eclipse/jetty/test/client/transport/HttpClientStreamTest.java @@ -528,7 +528,8 @@ public class HttpClientStreamTest extends AbstractTest latch.countDown(); - assertThrows(AsynchronousCloseException.class, input::read); + IOException ioException = assertThrows(IOException.class, input::read); + assertTrue(ioException instanceof AsynchronousCloseException || ioException.getCause() instanceof AsynchronousCloseException); } @ParameterizedTest diff --git a/jetty-core/pom.xml b/jetty-core/pom.xml index 5627d386b63..22edf453ee6 100644 --- a/jetty-core/pom.xml +++ b/jetty-core/pom.xml @@ -55,4 +55,72 @@ + + + + dependency-updates-reports + + + + org.codehaus.mojo + versions-maven-plugin + + + core-report + validate + + dependency-updates-aggregate-report + + + + html + + true + true + + + + + org.apache.maven + + + regex + .+-(alpha|beta).?[0-9]+ + + + + + + org.eclipse.jetty + + + regex + .+ + + + + + + org.eclipse.jetty.* + + + regex + .+ + + + + + + + + + + + + + + diff --git a/jetty-ee10/jetty-ee10-annotations/src/main/java/org/eclipse/jetty/ee10/annotations/AnnotationParser.java b/jetty-ee10/jetty-ee10-annotations/src/main/java/org/eclipse/jetty/ee10/annotations/AnnotationParser.java index 1a4f03585d3..bbf07f2f0e4 100644 --- a/jetty-ee10/jetty-ee10-annotations/src/main/java/org/eclipse/jetty/ee10/annotations/AnnotationParser.java +++ b/jetty-ee10/jetty-ee10-annotations/src/main/java/org/eclipse/jetty/ee10/annotations/AnnotationParser.java @@ -19,6 +19,7 @@ import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; +import java.util.Collections; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -655,7 +656,7 @@ public class AnnotationParser ClassReader reader = new ClassReader(in); reader.accept(new MyClassVisitor(handlers, containingResource, _asmVersion), ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); - String classname = reader.getClassName(); + String classname = normalize(reader.getClassName()); URI existing = _parsedClassNames.putIfAbsent(classname, location); if (existing != null) LOG.warn("{} scanned from multiple locations: {}, {}", classname, existing, location); @@ -665,4 +666,13 @@ public class AnnotationParser throw new IOException("Unable to parse class: " + classFile.toUri(), e); } } + + /** + * Useful mostly for testing to expose the list of parsed classes. + * @return the map of classnames to their URIs + */ + Map getParsedClassNames() + { + return Collections.unmodifiableMap(_parsedClassNames); + } } diff --git a/jetty-ee10/jetty-ee10-annotations/src/test/java/org/eclipse/jetty/ee10/annotations/TestAnnotationParser.java b/jetty-ee10/jetty-ee10-annotations/src/test/java/org/eclipse/jetty/ee10/annotations/TestAnnotationParser.java index d721edf6606..976bec798b0 100644 --- a/jetty-ee10/jetty-ee10-annotations/src/test/java/org/eclipse/jetty/ee10/annotations/TestAnnotationParser.java +++ b/jetty-ee10/jetty-ee10-annotations/src/test/java/org/eclipse/jetty/ee10/annotations/TestAnnotationParser.java @@ -15,6 +15,7 @@ package org.eclipse.jetty.ee10.annotations; import java.io.File; import java.io.IOException; +import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; @@ -41,6 +42,8 @@ import org.junit.jupiter.api.extension.ExtendWith; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.in; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; @@ -217,12 +220,17 @@ public class TestAnnotationParser { Path badClassesJar = MavenTestingUtils.getTestResourcePathFile("jdk9/log4j-api-2.9.0.jar"); AnnotationParser parser = new AnnotationParser(); - Set emptySet = Collections.emptySet(); - try (ResourceFactory.Closeable resourceFactory = ResourceFactory.closeable()) { - parser.parse(emptySet, resourceFactory.newResource(badClassesJar)); // Should throw no exceptions and work with the META-INF/versions without incident + parser.parse(Collections.emptySet(), resourceFactory.newResource(badClassesJar)); + + //check for a class that is only in versions 9 + Map parsed = parser.getParsedClassNames(); + URI processIdUtilURI = parsed.get("org.apache.logging.log4j.util.ProcessIdUtil"); + assertNotNull(processIdUtilURI); + if (Runtime.version().feature() > 17) + assertThat(processIdUtilURI.toString(), containsString("META-INF/versions/9")); } } @@ -231,13 +239,17 @@ public class TestAnnotationParser { Path jdk10Jar = MavenTestingUtils.getTestResourcePathFile("jdk10/multirelease-10.jar"); AnnotationParser parser = new AnnotationParser(); - DuplicateClassScanHandler handler = new DuplicateClassScanHandler(); - Set handlers = Collections.singleton(handler); try (ResourceFactory.Closeable resourceFactory = ResourceFactory.closeable()) { - parser.parse(handlers, resourceFactory.newResource(jdk10Jar)); // Should throw no exceptions + parser.parse(Collections.emptySet(), resourceFactory.newResource(jdk10Jar)); + + Map parsed = parser.getParsedClassNames(); + assertEquals(3, parsed.size()); + assertThat(parsed.keySet(), containsInAnyOrder("hello.DetailedVer", "hello.Greetings", "hello.Hello")); + if (Runtime.version().feature() > 17) + assertThat(parsed.get("hello.Greetings").toString(), containsString("META-INF/versions/10")); } } diff --git a/jetty-ee10/jetty-ee10-proxy/src/test/java/org/eclipse/jetty/ee10/proxy/ConnectHandlerSSLTest.java b/jetty-ee10/jetty-ee10-proxy/src/test/java/org/eclipse/jetty/ee10/proxy/ConnectHandlerSSLTest.java index 1dd6c8af83f..7cdf3a63937 100644 --- a/jetty-ee10/jetty-ee10-proxy/src/test/java/org/eclipse/jetty/ee10/proxy/ConnectHandlerSSLTest.java +++ b/jetty-ee10/jetty-ee10-proxy/src/test/java/org/eclipse/jetty/ee10/proxy/ConnectHandlerSSLTest.java @@ -19,19 +19,31 @@ import java.io.OutputStream; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.nio.file.Path; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import jakarta.servlet.ServletException; +import org.eclipse.jetty.client.ContentResponse; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.HttpClientTransport; +import org.eclipse.jetty.client.HttpProxy; +import org.eclipse.jetty.client.StringRequestContent; +import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.http.HttpHeaderValue; +import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpTester; +import org.eclipse.jetty.io.ClientConnector; import org.eclipse.jetty.io.Content; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.handler.ConnectHandler; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.ssl.SslContextFactory; @@ -39,6 +51,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; public class ConnectHandlerSSLTest extends AbstractConnectHandlerTest { @@ -48,11 +61,11 @@ public class ConnectHandlerSSLTest extends AbstractConnectHandlerTest public void prepare() throws Exception { sslContextFactory = new SslContextFactory.Server(); - String keyStorePath = MavenTestingUtils.getTestResourceFile("server_keystore.p12").getAbsolutePath(); - sslContextFactory.setKeyStorePath(keyStorePath); + Path keyStorePath = MavenTestingUtils.getTestResourcePath("server_keystore.p12").toAbsolutePath(); + sslContextFactory.setKeyStorePath(keyStorePath.toString()); sslContextFactory.setKeyStorePassword("storepwd"); server = new Server(); - serverConnector = new ServerConnector(server, sslContextFactory); + serverConnector = new ServerConnector(server, 1, 1, sslContextFactory); server.addConnector(serverConnector); server.setHandler(new ServerHandler()); server.start(); @@ -76,6 +89,7 @@ public class ConnectHandlerSSLTest extends AbstractConnectHandlerTest // Expect 200 OK from the CONNECT request HttpTester.Response response = HttpTester.parseResponse(HttpTester.from(socket.getInputStream())); + assertNotNull(response); assertEquals(HttpStatus.OK_200, response.getStatus()); // Upgrade the socket to SSL @@ -91,6 +105,7 @@ public class ConnectHandlerSSLTest extends AbstractConnectHandlerTest output.flush(); response = HttpTester.parseResponse(HttpTester.from(sslSocket.getInputStream())); + assertNotNull(response); assertEquals(HttpStatus.OK_200, response.getStatus()); assertEquals("GET /echo", response.getContent()); } @@ -114,6 +129,7 @@ public class ConnectHandlerSSLTest extends AbstractConnectHandlerTest // Expect 200 OK from the CONNECT request HttpTester.Response response = HttpTester.parseResponse(HttpTester.from(socket.getInputStream())); + assertNotNull(response); assertEquals(HttpStatus.OK_200, response.getStatus()); // Upgrade the socket to SSL @@ -133,6 +149,7 @@ public class ConnectHandlerSSLTest extends AbstractConnectHandlerTest output.flush(); response = HttpTester.parseResponse(HttpTester.from(sslSocket.getInputStream())); + assertNotNull(response); assertEquals(HttpStatus.OK_200, response.getStatus()); assertEquals("POST /echo?param=" + i + "\r\nHELLO", response.getContent()); } @@ -140,6 +157,40 @@ public class ConnectHandlerSSLTest extends AbstractConnectHandlerTest } } + @Test + public void testCONNECTWithConnectionClose() throws Exception + { + disposeProxy(); + connectHandler = new ConnectHandler() + { + @Override + protected void onConnectSuccess(ConnectContext connectContext, UpstreamConnection upstreamConnection) + { + // Add Connection: close to the 200 response. + connectContext.getResponse().getHeaders().put(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE); + super.onConnectSuccess(connectContext, upstreamConnection); + } + }; + proxy.setHandler(connectHandler); + proxy.start(); + + ClientConnector connector = new ClientConnector(); + connector.setSslContextFactory(new SslContextFactory.Client(true)); + HttpClientTransport transport = new HttpClientTransportOverHTTP(connector); + HttpClient httpClient = new HttpClient(transport); + httpClient.getProxyConfiguration().addProxy(new HttpProxy("localhost", proxyConnector.getLocalPort())); + httpClient.start(); + + ContentResponse response = httpClient.newRequest("localhost", serverConnector.getLocalPort()) + .scheme(HttpScheme.HTTPS.asString()) + .path("/echo") + .body(new StringRequestContent("hello")) + .send(); + + assertEquals(HttpStatus.OK_200, response.getStatus()); + assertEquals("GET /echo\r\nhello", response.getContentAsString()); + } + private SSLSocket wrapSocket(Socket socket) throws Exception { SSLContext sslContext = sslContextFactory.getSslContext(); diff --git a/jetty-ee10/pom.xml b/jetty-ee10/pom.xml index ecc9eb3660b..8cbd831c4bd 100644 --- a/jetty-ee10/pom.xml +++ b/jetty-ee10/pom.xml @@ -24,7 +24,7 @@ 2.1.1 2.0.1 6.0.0 - 3.1.0 + 3.1.1 3.0.0 3.0.1 3.1.0 @@ -414,6 +414,52 @@ html + true + true + + + + + org.apache.maven + + + regex + .+-(alpha|beta).?[0-9]+ + + + + + + org.eclipse.jetty + + + regex + .+ + + + + + + org.eclipse.jetty.* + + + regex + .+ + + + + + + org.apache.mina + + + regex + .+-M[0-9]+$ + + + + + diff --git a/jetty-ee8/jetty-ee8-jaas/pom.xml b/jetty-ee8/jetty-ee8-jaas/pom.xml index 9bcf0374586..98ae9467679 100644 --- a/jetty-ee8/jetty-ee8-jaas/pom.xml +++ b/jetty-ee8/jetty-ee8-jaas/pom.xml @@ -14,7 +14,8 @@ jetty-ee9-jaas ${project.groupId}.jaas 2.0.0.AM26 - 2.1.0 + 2.1.2 + 2.2.1 org.eclipse.jetty.jaas.* @@ -57,6 +58,12 @@ jetty-test-helper test + + org.apache.mina + mina-core + ${apache.mina.version} + test + org.apache.directory.server apacheds-test-framework @@ -125,6 +132,12 @@ org.apache.directory.api api-ldap-model ${apache.directory.api.version} + + + org.apache.mina + mina-core + + org.apache.directory.api diff --git a/jetty-ee8/pom.xml b/jetty-ee8/pom.xml index cb99ad6fbcb..c877a25120e 100644 --- a/jetty-ee8/pom.xml +++ b/jetty-ee8/pom.xml @@ -383,4 +383,151 @@ + + + + + dependency-updates-reports + + + + org.codehaus.mojo + versions-maven-plugin + + + ee8-report + validate + + dependency-updates-aggregate-report + + + + html + + true + true + + + + + org.apache.maven + + + regex + .+-(alpha|beta).?[0-9]+ + + + + + + org.eclipse.jetty + + + regex + .+ + + + + + + org.eclipse.jetty.* + + + regex + .+ + + + + + + jakarta.annotation + + + regex + ^(?!1.).+ + + + + + + jakarta.servlet.jsp + jakarta.servlet.jsp-api + + + regex + ^(?!2.).+ + + + + + + jakarta.servlet.jsp.jstl + jakarta.servlet.jsp.jstl-api + + + regex + ^(?!1.).+ + + + + + + jakarta.transaction + jakarta.transaction-api + + + regex + ^(?!1.).+ + + + + + + org.apache.directory.api + + + regex + ^(?!2.1.).+ + + + + + + org.mortbay.jasper + apache-jsp + + + regex + ^(?!9.0.).+ + + + + + + org.apache.mina + + + regex + .+-M[0-9]+$ + + + + + + + + + + + + + diff --git a/jetty-ee9/jetty-ee9-annotations/src/main/java/org/eclipse/jetty/ee9/annotations/AnnotationParser.java b/jetty-ee9/jetty-ee9-annotations/src/main/java/org/eclipse/jetty/ee9/annotations/AnnotationParser.java index bc03ac78a77..8070bfa8d0a 100644 --- a/jetty-ee9/jetty-ee9-annotations/src/main/java/org/eclipse/jetty/ee9/annotations/AnnotationParser.java +++ b/jetty-ee9/jetty-ee9-annotations/src/main/java/org/eclipse/jetty/ee9/annotations/AnnotationParser.java @@ -19,6 +19,7 @@ import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; +import java.util.Collections; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -652,7 +653,7 @@ public class AnnotationParser ClassReader reader = new ClassReader(in); reader.accept(new MyClassVisitor(handlers, containingResource, _asmVersion), ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); - String classname = reader.getClassName(); + String classname = normalize(reader.getClassName()); URI existing = _parsedClassNames.putIfAbsent(classname, location); if (existing != null) LOG.warn("{} scanned from multiple locations: {}, {}", classname, existing, location); @@ -662,4 +663,13 @@ public class AnnotationParser throw new IOException("Unable to parse class: " + classFile.toUri(), e); } } + + /** + * Useful mostly for testing to expose the list of parsed classes. + * @return the map of classnames to their URIs + */ + Map getParsedClassNames() + { + return Collections.unmodifiableMap(_parsedClassNames); + } } diff --git a/jetty-ee9/jetty-ee9-annotations/src/test/java/org/eclipse/jetty/ee9/annotations/TestAnnotationParser.java b/jetty-ee9/jetty-ee9-annotations/src/test/java/org/eclipse/jetty/ee9/annotations/TestAnnotationParser.java index 60bec9e3a07..6ddbde52dbf 100644 --- a/jetty-ee9/jetty-ee9-annotations/src/test/java/org/eclipse/jetty/ee9/annotations/TestAnnotationParser.java +++ b/jetty-ee9/jetty-ee9-annotations/src/test/java/org/eclipse/jetty/ee9/annotations/TestAnnotationParser.java @@ -15,6 +15,7 @@ package org.eclipse.jetty.ee9.annotations; import java.io.File; import java.io.IOException; +import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; @@ -41,6 +42,8 @@ import org.junit.jupiter.api.extension.ExtendWith; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.in; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; @@ -214,14 +217,20 @@ public class TestAnnotationParser @Test public void testJep238MultiReleaseInJar() throws Exception { - Path badClassesJar = MavenTestingUtils.getTargetPath("test-classes/jdk9/log4j-api-2.9.0.jar"); - AnnotationParser parser = new AnnotationParser(); - Set emptySet = Collections.emptySet(); + Path badClassesJar = MavenTestingUtils.getTargetPath("test-classes/jdk9/log4j-api-2.9.0.jar"); + AnnotationParser parser = new AnnotationParser(); try (ResourceFactory.Closeable resourceFactory = ResourceFactory.closeable()) { - parser.parse(emptySet, resourceFactory.newResource(badClassesJar)); // Should throw no exceptions and work with the META-INF/versions without incident + parser.parse(Collections.emptySet(), resourceFactory.newResource(badClassesJar)); + + //check for a class that is only in versions 9 + Map parsed = parser.getParsedClassNames(); + URI processIdUtilURI = parsed.get("org.apache.logging.log4j.util.ProcessIdUtil"); + assertNotNull(processIdUtilURI); + if (Runtime.version().feature() > 17) + assertThat(processIdUtilURI.toString(), containsString("META-INF/versions/9")); } } @@ -230,13 +239,16 @@ public class TestAnnotationParser { Path jdk10Jar = MavenTestingUtils.getTargetPath("test-classes/jdk10/multirelease-10.jar"); AnnotationParser parser = new AnnotationParser(); - DuplicateClassScanHandler handler = new DuplicateClassScanHandler(); - Set handlers = Collections.singleton(handler); - try (ResourceFactory.Closeable resourceFactory = ResourceFactory.closeable()) { - parser.parse(handlers, resourceFactory.newResource(jdk10Jar)); // Should throw no exceptions + parser.parse(Collections.emptySet(), resourceFactory.newResource(jdk10Jar)); + + Map parsed = parser.getParsedClassNames(); + assertEquals(3, parsed.size()); + assertThat(parsed.keySet(), containsInAnyOrder("hello.DetailedVer", "hello.Greetings", "hello.Hello")); + if (Runtime.version().feature() > 17) + assertThat(parsed.get("hello.Greetings").toString(), containsString("META-INF/versions/10")); } } diff --git a/jetty-ee9/jetty-ee9-maven-plugin/src/main/java/org/eclipse/jetty/ee9/maven/plugin/JettyEffectiveWebXml.java b/jetty-ee9/jetty-ee9-maven-plugin/src/main/java/org/eclipse/jetty/ee9/maven/plugin/JettyEffectiveWebXml.java index 49d8a859e2c..9001a778715 100644 --- a/jetty-ee9/jetty-ee9-maven-plugin/src/main/java/org/eclipse/jetty/ee9/maven/plugin/JettyEffectiveWebXml.java +++ b/jetty-ee9/jetty-ee9-maven-plugin/src/main/java/org/eclipse/jetty/ee9/maven/plugin/JettyEffectiveWebXml.java @@ -60,12 +60,11 @@ public class JettyEffectiveWebXml extends AbstractUnassembledWebAppMojo } } - Path start = path.getName(0); - int count = path.getNameCount(); - Path end = path.getName(count > 0 ? count - 1 : count); - //if the war is not assembled, we must configure it - if (start.startsWith("src") || !end.toString().endsWith(".war")) + + if ((path == null) || (path.startsWith("src") || !path.endsWith(".war"))) + { super.configureUnassembledWebApp(); + } } /** diff --git a/jetty-ee9/jetty-ee9-proxy/src/test/java/org/eclipse/jetty/ee9/proxy/AbstractConnectHandlerTest.java b/jetty-ee9/jetty-ee9-proxy/src/test/java/org/eclipse/jetty/ee9/proxy/AbstractConnectHandlerTest.java index cd77714cb96..cc8e273a1d8 100644 --- a/jetty-ee9/jetty-ee9-proxy/src/test/java/org/eclipse/jetty/ee9/proxy/AbstractConnectHandlerTest.java +++ b/jetty-ee9/jetty-ee9-proxy/src/test/java/org/eclipse/jetty/ee9/proxy/AbstractConnectHandlerTest.java @@ -32,7 +32,7 @@ public abstract class AbstractConnectHandlerTest protected void prepareProxy() throws Exception { proxy = new Server(); - proxyConnector = new ServerConnector(proxy); + proxyConnector = new ServerConnector(proxy, 1, 1); proxy.addConnector(proxyConnector); connectHandler = new ConnectHandler(); proxy.setHandler(connectHandler); diff --git a/jetty-ee9/jetty-ee9-proxy/src/test/java/org/eclipse/jetty/ee9/proxy/ConnectHandlerTest.java b/jetty-ee9/jetty-ee9-proxy/src/test/java/org/eclipse/jetty/ee9/proxy/ConnectHandlerTest.java index 0952c2f6a2e..cd3289a03ef 100644 --- a/jetty-ee9/jetty-ee9-proxy/src/test/java/org/eclipse/jetty/ee9/proxy/ConnectHandlerTest.java +++ b/jetty-ee9/jetty-ee9-proxy/src/test/java/org/eclipse/jetty/ee9/proxy/ConnectHandlerTest.java @@ -58,7 +58,7 @@ public class ConnectHandlerTest extends AbstractConnectHandlerTest public void prepare() throws Exception { server = new Server(); - serverConnector = new ServerConnector(server); + serverConnector = new ServerConnector(server, 1, 1); server.addConnector(serverConnector); server.setHandler(new ServerHandler()); server.start(); diff --git a/jetty-ee9/jetty-ee9-tests/jetty-ee9-test-loginservice/pom.xml b/jetty-ee9/jetty-ee9-tests/jetty-ee9-test-loginservice/pom.xml index b7f3e8542a5..ae739660c02 100644 --- a/jetty-ee9/jetty-ee9-tests/jetty-ee9-test-loginservice/pom.xml +++ b/jetty-ee9/jetty-ee9-tests/jetty-ee9-test-loginservice/pom.xml @@ -46,6 +46,11 @@ mariadb test + + net.java.dev.jna + jna + test + org.testcontainers junit-jupiter diff --git a/jetty-ee9/pom.xml b/jetty-ee9/pom.xml index 88d0a918846..5f2c17b3f33 100644 --- a/jetty-ee9/pom.xml +++ b/jetty-ee9/pom.xml @@ -455,6 +455,204 @@ html + true + true + + + + + org.apache.maven + + + regex + .+-(alpha|beta).?[0-9]+ + + + + + + org.eclipse.jetty + + + regex + .+ + + + + + + org.eclipse.jetty.* + + + regex + .+ + + + + + + jakarta.activation + + + regex + ^(?!2.0.).+ + + + + + + jakarta.annotation + + + regex + ^(?!2.0.).+ + + + + + + jakarta.authentication + + + regex + ^(?!2.).+ + + + + + + jakarta.el + + + regex + ^(?!4.).+ + + + + + + jakarta.enterprise + jakarta.enterprise.cdi-api + + + regex + ^(?!3.).+ + + + + + + jakarta.interceptor + jakarta.interceptor-api + + + regex + ^(?!2.0.).+ + + + + + + jakarta.mail + jakarta.mail-api + + + regex + ^(?!2.0.).+ + + + + + + jakarta.servlet + jakarta.servlet-api + + + regex + ^(?!5.).+ + + + + + + jakarta.servlet + jakarta.servlet.jsp-api + + + regex + ^(?!3.0.).+ + + + + + + jakarta.servlet.jsp.jstl + jakarta.servlet.jsp.jstl-api + + + regex + ^(?!2.).+ + + + + + + org.glassfish.web + jakarta.servlet.jsp.jstl + + + regex + ^(?!2.).+ + + + + + + org.mortbay.jasper + apache-jsp + + + regex + ^(?!10.0.).+ + + + + + + org.mortbay.jasper + apache-el + + + regex + ^(?!10.0.).+ + + + + + + org.apache.mina + + + regex + .+-M[0-9]+$ + + + + + diff --git a/pom.xml b/pom.xml index 0c0eeae5ce8..14cbaa657a6 100644 --- a/pom.xml +++ b/pom.xml @@ -33,7 +33,7 @@ 2.2.1 9.4 4.2.0 - 6.3.1 + 6.4.0 1.5 10.6.0 1.15 @@ -45,12 +45,12 @@ 7.0.5 3.0.2 2.18.0 - 1.52.1 + 1.53.0 2.10.1 31.1-jre 5.1.0 2.2 - 5.2.1 + 5.2.2 4.6.1.Final 11.0.17.Final 2.14.2 @@ -80,7 +80,7 @@ 2.2.1.Final 2.2.1.Final 3.5.0.Final - 2.1.19.Final + 2.3.0.Alpha1 3.5.0.Final 1.1 1.0.7 @@ -91,12 +91,12 @@ 1.36 5.13.0 1.1.1 - 2.4.8 + 2.4.9 5.9.2 2.0.3 2.20.0 1.4.5 - 3.0.10 + 3.1.2 10.3.6 3.8.7 0.13.1 @@ -105,9 +105,9 @@ 3.12.11 0.9.1 8.1.0 - 6.0.0 + 8.0.0 1.2.0 - 1.2.0 + 1.3.0 3.18.200 @@ -129,7 +129,7 @@ 1.2 2.1.1 - 3.5.0 + 3.5.1 2.0.6 1.3.6 2.1.1.RELEASE @@ -1001,6 +1001,11 @@ jna-jpms ${jna.version} + + net.java.dev.jna + jna + ${jna.version} + net.minidev json-smart @@ -2088,6 +2093,71 @@ + + + dependency-updates-reports + + + + org.codehaus.mojo + versions-maven-plugin + + + root-report + validate + + dependency-updates-aggregate-report + + + + html + + false + true + + + + + org.apache.maven + + + regex + .+-(alpha|beta).?[0-9]+ + + + + + + org.eclipse.jetty + + + regex + .+ + + + + + + org.eclipse.jetty.* + + + regex + .+ + + + + + + + + + + + +