diff --git a/Jenkinsfile b/Jenkinsfile index 77a8c47fb48..dd81c80846a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -73,6 +73,7 @@ pipeline { agent { node { label 'linux' } } options { timeout(time: 30, unit: 'MINUTES') } steps { + mavenBuild("jdk11", "install -f build-resources", "maven3", true) mavenBuild("jdk11", "install checkstyle:check -DskipTests", "maven3", true) recordIssues( enabledForFailure: true, aggregatingResults: true, @@ -137,15 +138,13 @@ def slackNotif() { * @return the Jenkinsfile step representing a maven build */ def mavenBuild(jdk, cmdline, mvnName, junitPublishDisabled) { - def localRepo = "${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}" // ".repository" // - def settingsName = 'oss-settings.xml' + def localRepo = ".repository" def mavenOpts = '-Xms1g -Xmx4g -Djava.awt.headless=true' withMaven( maven: mvnName, jdk: "$jdk", publisherStrategy: 'EXPLICIT', - globalMavenSettingsConfig: settingsName, options: [junitPublisher(disabled: junitPublishDisabled),mavenLinkerPublisher(disabled: false),pipelineGraphPublisher(disabled: false)], mavenOpts: mavenOpts, mavenLocalRepo: localRepo) { diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCorrelationDataTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCorrelationDataTest.java new file mode 100644 index 00000000000..ac7e58d6eb6 --- /dev/null +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientCorrelationDataTest.java @@ -0,0 +1,70 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.client; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class HttpClientCorrelationDataTest extends AbstractHttpClientServerTest +{ + @ParameterizedTest + @ArgumentsSource(ScenarioProvider.class) + public void testCorrelationData(Scenario scenario) throws Exception + { + String correlationName = "X-Correlation-Data"; + String correlationData = "123456"; + ThreadLocal correlation = new ThreadLocal<>(); + + start(scenario, new EmptyServerHandler() + { + @Override + protected void service(String target, org.eclipse.jetty.server.Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + assertEquals(correlationData, request.getHeader(correlationName)); + } + }); + client.getRequestListeners().add(new Request.Listener.Adapter() + { + @Override + public void onQueued(Request request) + { + request.header(correlationName, correlation.get()); + } + }); + + correlation.set(correlationData); + + ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) + .scheme(scenario.getScheme()) + .timeout(5, TimeUnit.SECONDS) + .send(); + + assertEquals(200, response.getStatus()); + } +} diff --git a/jetty-home/pom.xml b/jetty-home/pom.xml index 1e9c227840e..471e67c431b 100644 --- a/jetty-home/pom.xml +++ b/jetty-home/pom.xml @@ -440,7 +440,7 @@ org.eclipse.jetty,org.eclipse.jetty.websocket - infinispan-embedded,infinispan-remote + infinispan-embedded,infinispan-remote,jetty-test-helper,alpn-api,javax.security.auth.message,javax.activation config false META-INF/** diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/ResourceHttpContent.java b/jetty-http/src/main/java/org/eclipse/jetty/http/ResourceHttpContent.java index 5441a0d7b7a..22e404a0df8 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/ResourceHttpContent.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/ResourceHttpContent.java @@ -125,7 +125,7 @@ public class ResourceHttpContent implements HttpContent @Override public ByteBuffer getDirectBuffer() { - if (_resource.length() <= 0 || _maxBuffer > 0 && _maxBuffer < _resource.length()) + if (_resource.length() <= 0 || _maxBuffer > 0 && _resource.length() > _maxBuffer) return null; try { @@ -152,7 +152,7 @@ public class ResourceHttpContent implements HttpContent @Override public ByteBuffer getIndirectBuffer() { - if (_resource.length() <= 0 || _maxBuffer > 0 && _maxBuffer < _resource.length()) + if (_resource.length() <= 0 || _maxBuffer > 0 && _resource.length() > _maxBuffer) return null; try { diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/ResponseTrailerTest.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/ResponseTrailerTest.java new file mode 100644 index 00000000000..11727ee7425 --- /dev/null +++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/ResponseTrailerTest.java @@ -0,0 +1,127 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http2.client.http; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpFields; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.http.MetaData; +import org.eclipse.jetty.http2.api.Session; +import org.eclipse.jetty.http2.api.Stream; +import org.eclipse.jetty.http2.client.HTTP2Client; +import org.eclipse.jetty.http2.frames.DataFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.FuturePromise; +import org.eclipse.jetty.util.Promise; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ResponseTrailerTest extends AbstractTest +{ + @Test + public void testEmptyTrailersWithoutContent() throws Exception + { + testEmptyTrailers(null); + } + + @Test + public void testEmptyTrailersWithContent() throws Exception + { + testEmptyTrailers("data"); + } + + public void testEmptyTrailers(String data) throws Exception + { + start(new EmptyServerHandler() + { + @Override + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException + { + // Send empty response trailers. + Response jettyResponse = jettyRequest.getResponse(); + jettyResponse.setTrailers(HttpFields::new); + if (data != null) + response.getOutputStream().write(data.getBytes(StandardCharsets.US_ASCII)); + } + }); + + HTTP2Client http2Client = new HTTP2Client(); + http2Client.start(); + try + { + String host = "localhost"; + int port = connector.getLocalPort(); + InetSocketAddress address = new InetSocketAddress(host, port); + FuturePromise sessionPromise = new FuturePromise<>(); + http2Client.connect(address, new Session.Listener.Adapter(), sessionPromise); + Session session = sessionPromise.get(5, TimeUnit.SECONDS); + + HttpURI uri = new HttpURI("http://" + host + ":" + port + "/"); + MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, new HttpFields()); + HeadersFrame frame = new HeadersFrame(request, null, true); + BlockingQueue headers = new LinkedBlockingQueue<>(); + CountDownLatch latch = new CountDownLatch(1); + session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter() + { + @Override + public void onHeaders(Stream stream, HeadersFrame frame) + { + headers.offer(frame); + if (frame.isEndStream()) + latch.countDown(); + } + + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + super.onData(stream, frame, callback); + if (frame.isEndStream()) + latch.countDown(); + } + }); + + assertTrue(latch.await(5, TimeUnit.SECONDS)); + assertEquals(1, headers.size()); + frame = headers.poll(); + assertNotNull(frame); + assertTrue(frame.getMetaData().isResponse()); + } + finally + { + http2Client.stop(); + } + } +} diff --git a/jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties b/jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties index 287d28319e0..34929219c9d 100644 --- a/jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties +++ b/jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties @@ -1,4 +1,5 @@ org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +#org.eclipse.jetty.LEVEL=DEBUG #org.eclipse.jetty.client.LEVEL=DEBUG org.eclipse.jetty.http2.hpack.LEVEL=INFO #org.eclipse.jetty.http2.LEVEL=DEBUG diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index 7b86321ac83..a8a9476423f 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -119,9 +119,17 @@ public class HttpTransportOverHTTP2 implements HttpTransport { if (lastContent) { - Supplier trailers = info.getTrailerSupplier(); - if (transportCallback.start(new SendTrailers(getCallback(), trailers), false)) - sendDataFrame(content, true, trailers == null, transportCallback); + HttpFields trailers = retrieveTrailers(); + if (trailers != null) + { + if (transportCallback.start(new SendTrailers(getCallback(), trailers), false)) + sendDataFrame(content, true, false, transportCallback); + } + else + { + if (transportCallback.start(getCallback(), false)) + sendDataFrame(content, true, true, transportCallback); + } } else { @@ -137,9 +145,17 @@ public class HttpTransportOverHTTP2 implements HttpTransport { if (lastContent) { - Supplier trailers = info.getTrailerSupplier(); - if (transportCallback.start(new SendTrailers(callback, trailers), true)) - sendHeadersFrame(info, trailers == null, transportCallback); + HttpFields trailers = retrieveTrailers(); + if (trailers != null) + { + if (transportCallback.start(new SendTrailers(callback, trailers), true)) + sendHeadersFrame(info, false, transportCallback); + } + else + { + if (transportCallback.start(callback, true)) + sendHeadersFrame(info, true, transportCallback); + } } else { @@ -160,16 +176,24 @@ public class HttpTransportOverHTTP2 implements HttpTransport { if (lastContent) { - Supplier trailers = metaData.getTrailerSupplier(); - SendTrailers sendTrailers = new SendTrailers(callback, trailers); - if (hasContent || trailers == null) + HttpFields trailers = retrieveTrailers(); + if (trailers != null) { - if (transportCallback.start(sendTrailers, false)) - sendDataFrame(content, true, trailers == null, transportCallback); + SendTrailers sendTrailers = new SendTrailers(callback, trailers); + if (hasContent) + { + if (transportCallback.start(sendTrailers, false)) + sendDataFrame(content, true, false, transportCallback); + } + else + { + sendTrailers.succeeded(); + } } else { - sendTrailers.succeeded(); + if (transportCallback.start(callback, false)) + sendDataFrame(content, true, true, transportCallback); } } else @@ -185,6 +209,17 @@ public class HttpTransportOverHTTP2 implements HttpTransport } } + private HttpFields retrieveTrailers() + { + Supplier supplier = metaData.getTrailerSupplier(); + if (supplier == null) + return null; + HttpFields trailers = supplier.get(); + if (trailers == null) + return null; + return trailers.size() == 0 ? null : trailers; + } + @Override public boolean isPushSupported() { @@ -406,7 +441,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport } } if (LOG.isDebugEnabled()) - LOG.debug(String.format("HTTP2 Response #%d/%h idle timeout", stream.getId(), stream.getSession()), failure); + LOG.debug(String.format("HTTP2 Response #%d/%h idle timeout %s", stream.getId(), stream.getSession(), result ? "expired" : "ignored"), failure); if (result) callback.failed(failure); return result; @@ -420,9 +455,9 @@ public class HttpTransportOverHTTP2 implements HttpTransport private class SendTrailers extends Callback.Nested { - private final Supplier trailers; + private final HttpFields trailers; - private SendTrailers(Callback callback, Supplier trailers) + private SendTrailers(Callback callback, HttpFields trailers) { super(callback); this.trailers = trailers; @@ -431,15 +466,8 @@ public class HttpTransportOverHTTP2 implements HttpTransport @Override public void succeeded() { - if (trailers != null) - { - if (transportCallback.start(getCallback(), false)) - sendTrailersFrame(new MetaData(HttpVersion.HTTP_2, trailers.get()), transportCallback); - } - else - { - super.succeeded(); - } + if (transportCallback.start(getCallback(), false)) + sendTrailersFrame(new MetaData(HttpVersion.HTTP_2, trailers), transportCallback); } } } diff --git a/jetty-maven-plugin/src/it/it-parent-pom/pom.xml b/jetty-maven-plugin/src/it/it-parent-pom/pom.xml index 6350cf41786..e18e1028903 100644 --- a/jetty-maven-plugin/src/it/it-parent-pom/pom.xml +++ b/jetty-maven-plugin/src/it/it-parent-pom/pom.xml @@ -144,6 +144,16 @@ maven-war-plugin @maven.war.plugin.version@ + + org.apache.maven.plugins + maven-install-plugin + @maven.install.plugin.version@ + + + org.apache.maven.plugins + maven-deploy-plugin + @maven.deploy.plugin.version@ + diff --git a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/postbuild.groovy b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/postbuild.groovy index b8b8b5e2599..bd9510f83fc 100644 --- a/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/postbuild.groovy +++ b/jetty-maven-plugin/src/it/jetty-run-mojo-multi-module-single-war-it/postbuild.groovy @@ -20,7 +20,7 @@ File buildLog = new File( basedir, 'build.log' ) assert buildLog.text.contains( 'Started Jetty Server' ) assert buildLog.text.contains( '(1a) >> javax.servlet.ServletContextListener loaded from jar:' ) -assert buildLog.text.contains( 'local-repo/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar!/javax/servlet/ServletContextListener.class << (1b)' ) +assert buildLog.text.contains( 'javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar!/javax/servlet/ServletContextListener.class << (1b)' ) assert buildLog.text.contains( '(2a) >> mca.common.CommonService loaded from file:' ) assert buildLog.text.contains( 'common/target/classes/mca/common/CommonService.class << (2b)' ) diff --git a/jetty-maven-plugin/src/it/settings.xml b/jetty-maven-plugin/src/it/settings.xml index d64bdb89034..c78e01dff9d 100644 --- a/jetty-maven-plugin/src/it/settings.xml +++ b/jetty-maven-plugin/src/it/settings.xml @@ -1,6 +1,13 @@ + + + local.mirror + file://@localRepo@ + central + + it-repo diff --git a/jetty-osgi/test-jetty-osgi/pom.xml b/jetty-osgi/test-jetty-osgi/pom.xml index 0122c6de984..8befd094b12 100644 --- a/jetty-osgi/test-jetty-osgi/pom.xml +++ b/jetty-osgi/test-jetty-osgi/pom.xml @@ -14,8 +14,8 @@ ${project.groupId}.boot.test.osgi http://download.eclipse.org/jetty/orbit/ target/distribution - 4.12.0 - 2.5.2 + 4.13.1 + 2.6.1 1.0 true @@ -449,6 +449,7 @@ ${skipTests} ${settings.localRepository} + ${env.GLOBAL_MVN_SETTINGS} diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestOSGiUtil.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestOSGiUtil.java index 606bf4b6831..641d79d805c 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestOSGiUtil.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/test/TestOSGiUtil.java @@ -38,6 +38,7 @@ import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.ops4j.pax.exam.CoreOptions; import org.ops4j.pax.exam.Option; +import org.ops4j.pax.url.mvn.internal.AetherBasedResolver; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; @@ -106,11 +107,22 @@ public class TestOSGiUtil public static List