From a6e28b5ce0e4fa6a22f798dd215cb89b7c4b6533 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Sat, 30 Sep 2017 22:16:45 +0200 Subject: [PATCH] Issue #1859 - Jetty http2 client idle_timeout when trying to get the session after connected to Jetty HTTP2 server. Implemented an integration test case that shows HTTP2Client usage from within a web application. --- tests/test-webapps/pom.xml | 1 + tests/test-webapps/test-http2-webapp/pom.xml | 175 ++++++++++++++++++ .../jetty/test/webapp/HTTP1Servlet.java | 138 ++++++++++++++ .../jetty/test/webapp/HTTP2Servlet.java | 35 ++++ .../src/main/webapp/WEB-INF/web.xml | 28 +++ .../jetty/test/webapp/HTTP2FromWebAppIT.java | 96 ++++++++++ .../test/resources/jetty-logging.properties | 3 + .../src/test/resources/keystore.jks | Bin 0 -> 2206 bytes 8 files changed, 476 insertions(+) create mode 100644 tests/test-webapps/test-http2-webapp/pom.xml create mode 100644 tests/test-webapps/test-http2-webapp/src/main/java/org/eclipse/jetty/test/webapp/HTTP1Servlet.java create mode 100644 tests/test-webapps/test-http2-webapp/src/main/java/org/eclipse/jetty/test/webapp/HTTP2Servlet.java create mode 100644 tests/test-webapps/test-http2-webapp/src/main/webapp/WEB-INF/web.xml create mode 100644 tests/test-webapps/test-http2-webapp/src/test/java/org/eclipse/jetty/test/webapp/HTTP2FromWebAppIT.java create mode 100644 tests/test-webapps/test-http2-webapp/src/test/resources/jetty-logging.properties create mode 100644 tests/test-webapps/test-http2-webapp/src/test/resources/keystore.jks diff --git a/tests/test-webapps/pom.xml b/tests/test-webapps/pom.xml index 738e7695aa1..72a533eeae6 100644 --- a/tests/test-webapps/pom.xml +++ b/tests/test-webapps/pom.xml @@ -38,5 +38,6 @@ test-servlet-spec test-jaas-webapp test-jndi-webapp + test-http2-webapp diff --git a/tests/test-webapps/test-http2-webapp/pom.xml b/tests/test-webapps/test-http2-webapp/pom.xml new file mode 100644 index 00000000000..3b3ba85365b --- /dev/null +++ b/tests/test-webapps/test-http2-webapp/pom.xml @@ -0,0 +1,175 @@ + + + + org.eclipse.jetty.tests + test-webapps-parent + 9.4.8-SNAPSHOT + + + 4.0.0 + test-http2-webapp + Test :: Jetty HTTP2 Webapp + war + + + ${project.groupId}.http2 + + + + + + maven-dependency-plugin + + + unpack-webapp + pre-integration-test + + unpack + + + + + ${project.groupId} + ${project.artifactId} + ${project.version} + war + false + ${project.build.directory}/webapp + + + + + + + + maven-failsafe-plugin + + + + integration-test + verify + + + + + + + + + + jdk8 + + [1.8,1.9) + + + + + maven-dependency-plugin + + + copy-alpn-boot + pre-integration-test + + copy + + + + + org.mortbay.jetty.alpn + alpn-boot + ${alpn.version} + jar + false + ${project.build.directory}/alpn + + + + + + + + maven-failsafe-plugin + + -Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar + + + + + + + org.eclipse.jetty + jetty-alpn-openjdk8-client + ${project.version} + + + org.eclipse.jetty.alpn + alpn-api + + + + + org.eclipse.jetty + jetty-alpn-openjdk8-server + ${project.version} + test + + + + + jdk9 + + [1.9,) + + + + org.eclipse.jetty + jetty-alpn-java-client + ${project.version} + + + org.eclipse.jetty + jetty-alpn-java-server + ${project.version} + test + + + + + + + + org.eclipse.jetty.http2 + http2-client + ${project.version} + + + javax.servlet + javax.servlet-api + provided + + + + org.eclipse.jetty + jetty-client + ${project.version} + test + + + org.eclipse.jetty + jetty-webapp + ${project.version} + test + + + org.eclipse.jetty.http2 + http2-server + ${project.version} + test + + + junit + junit + test + + + diff --git a/tests/test-webapps/test-http2-webapp/src/main/java/org/eclipse/jetty/test/webapp/HTTP1Servlet.java b/tests/test-webapps/test-http2-webapp/src/main/java/org/eclipse/jetty/test/webapp/HTTP1Servlet.java new file mode 100644 index 00000000000..dd7aae745bc --- /dev/null +++ b/tests/test-webapps/test-http2-webapp/src/main/java/org/eclipse/jetty/test/webapp/HTTP1Servlet.java @@ -0,0 +1,138 @@ +// +// ======================================================================== +// Copyright (c) 1995-2017 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.test.webapp; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; + +import javax.servlet.AsyncContext; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServlet; +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.HttpStatus; +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.util.Callback; +import org.eclipse.jetty.util.Promise; +import org.eclipse.jetty.util.ssl.SslContextFactory; + +public class HTTP1Servlet extends HttpServlet +{ + private SslContextFactory sslContextFactory; + private HTTP2Client http2Client; + + @Override + public void init() throws ServletException + { + try + { + sslContextFactory = new SslContextFactory(true); + http2Client = new HTTP2Client(); + http2Client.addBean(sslContextFactory); + http2Client.start(); + } + catch (Exception x) + { + throw new ServletException(x); + } + } + + @Override + public void destroy() + { + try + { + http2Client.stop(); + } + catch (Exception x) + { + x.printStackTrace(); + } + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + String host = "localhost"; + int port = request.getServerPort(); + String contextPath = request.getContextPath(); + ServletOutputStream output = response.getOutputStream(); + AsyncContext asyncContext = request.startAsync(); + http2Client.connect(sslContextFactory, new InetSocketAddress(host, port), new Session.Listener.Adapter(), new Promise() + { + @Override + public void succeeded(Session session) + { + HttpURI uri = new HttpURI(request.getScheme(), host, port, contextPath + "/h2"); + MetaData.Request metaData = new MetaData.Request(HttpMethod.GET.asString(), uri, HttpVersion.HTTP_2, new HttpFields()); + HeadersFrame frame = new HeadersFrame(metaData, null, true); + session.newStream(frame, new Promise.Adapter() + { + @Override + public void failed(Throwable x) + { + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500); + response.setHeader("X-Failure", "stream"); + asyncContext.complete(); + } + }, new Stream.Listener.Adapter() + { + @Override + public void onData(Stream stream, DataFrame frame, Callback callback) + { + try + { + ByteBuffer buffer = frame.getData(); + byte[] bytes = new byte[buffer.remaining()]; + buffer.get(bytes); + output.write(bytes); + callback.succeeded(); + if (frame.isEndStream()) + asyncContext.complete(); + } + catch (IOException x) + { + asyncContext.complete(); + } + } + }); + } + + @Override + public void failed(Throwable x) + { + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500); + response.setHeader("X-Failure", "session"); + asyncContext.complete(); + } + }); + } +} diff --git a/tests/test-webapps/test-http2-webapp/src/main/java/org/eclipse/jetty/test/webapp/HTTP2Servlet.java b/tests/test-webapps/test-http2-webapp/src/main/java/org/eclipse/jetty/test/webapp/HTTP2Servlet.java new file mode 100644 index 00000000000..ab92da37e01 --- /dev/null +++ b/tests/test-webapps/test-http2-webapp/src/main/java/org/eclipse/jetty/test/webapp/HTTP2Servlet.java @@ -0,0 +1,35 @@ +// +// ======================================================================== +// Copyright (c) 1995-2017 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.test.webapp; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class HTTP2Servlet extends HttpServlet +{ + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + response.getOutputStream().print("ok"); + } +} diff --git a/tests/test-webapps/test-http2-webapp/src/main/webapp/WEB-INF/web.xml b/tests/test-webapps/test-http2-webapp/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..9944a3b0ff2 --- /dev/null +++ b/tests/test-webapps/test-http2-webapp/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,28 @@ + + + + + h1 + org.eclipse.jetty.test.webapp.HTTP1Servlet + true + + + h1 + /h1 + + + + h2 + org.eclipse.jetty.test.webapp.HTTP2Servlet + + + h2 + /h2 + + + + + diff --git a/tests/test-webapps/test-http2-webapp/src/test/java/org/eclipse/jetty/test/webapp/HTTP2FromWebAppIT.java b/tests/test-webapps/test-http2-webapp/src/test/java/org/eclipse/jetty/test/webapp/HTTP2FromWebAppIT.java new file mode 100644 index 00000000000..b4f3a8a9391 --- /dev/null +++ b/tests/test-webapps/test-http2-webapp/src/test/java/org/eclipse/jetty/test/webapp/HTTP2FromWebAppIT.java @@ -0,0 +1,96 @@ +// +// ======================================================================== +// Copyright (c) 1995-2017 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.test.webapp; + +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.http.HttpScheme; +import org.eclipse.jetty.http2.HTTP2Cipher; +import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.webapp.WebAppContext; +import org.junit.Assert; +import org.junit.Test; + +public class HTTP2FromWebAppIT +{ + @Test + public void testHTTP2FromWebApp() throws Exception + { + Server server = new Server(); + + SslContextFactory serverTLS = new SslContextFactory(); + serverTLS.setKeyStorePath("src/test/resources/keystore.jks"); + serverTLS.setKeyStorePassword("storepwd"); + serverTLS.setCipherComparator(new HTTP2Cipher.CipherComparator()); + + HttpConfiguration httpsConfig = new HttpConfiguration(); + httpsConfig.addCustomizer(new SecureRequestCustomizer()); + + HttpConnectionFactory h1 = new HttpConnectionFactory(httpsConfig); + ALPNServerConnectionFactory alpn = new ALPNServerConnectionFactory(); + alpn.setDefaultProtocol(h1.getProtocol()); + SslConnectionFactory ssl = new SslConnectionFactory(serverTLS, alpn.getProtocol()); + HTTP2ServerConnectionFactory h2 = new HTTP2ServerConnectionFactory(httpsConfig); + + ServerConnector connector = new ServerConnector(server, ssl, alpn, h2, h1); + server.addConnector(connector); + + String contextPath = "/http2_from_webapp"; + WebAppContext context = new WebAppContext("target/webapp", contextPath); + server.setHandler(context); + + server.start(); + + try + { + SslContextFactory clientTLS = new SslContextFactory(true); + HttpClient client = new HttpClient(clientTLS); + client.start(); + + try + { + ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) + .scheme(HttpScheme.HTTPS.asString()) + .path(contextPath + "/h1") + .timeout(5, TimeUnit.SECONDS) + .send(); + + Assert.assertEquals("ok", response.getContentAsString()); + } + finally + { + client.stop(); + } + } + finally + { + server.stop(); + } + } +} diff --git a/tests/test-webapps/test-http2-webapp/src/test/resources/jetty-logging.properties b/tests/test-webapps/test-http2-webapp/src/test/resources/jetty-logging.properties new file mode 100644 index 00000000000..055e90b60ef --- /dev/null +++ b/tests/test-webapps/test-http2-webapp/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +org.eclipse.jetty.LEVEL=INFO +#org.eclipse.jetty.alpn.LEVEL=DEBUG diff --git a/tests/test-webapps/test-http2-webapp/src/test/resources/keystore.jks b/tests/test-webapps/test-http2-webapp/src/test/resources/keystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..428ba54776ede2fdcdeedd879edb927c2abd9953 GIT binary patch literal 2206 zcmcgt`9Bkm8{cNkoMUp6gmShKn!AQX*(l6Nj(i=TnQPOKYtv{*Wg>ItE=Q!pRYH8a z$Sp#S#2lYw#aw;$y9u4T}83H*%lp zAKZay0sy=q1Qoo85aAQh;$ zD(c2EIN#D7WwYDLKUg!CotQPD@dp;5FR#bgaace(^x$6g5frD~(_b(MI^J&*A2DRp zf5Q2onfE(zvUb9|9C`66)YFRNM6~xrz4;iVbU=P|*YT2eWHFJJtr+M@zt2qPm)K~rRcqcs=LM12)PX0TT%QO zlf*xkqD3}7l)1J`5W(>=9nR0e6j-<79<11v3ZuXXcQpoCsqY~n`$FN+S}hcVm5Y>G zXnD{@DYs1@{S0z(lW+?86LWKtku$$-(khsh>0qRUXn=84`GRn?77M^_JY`durnN;KE zW#OJ`h<6xcB{I))ekGpc*Ylt}0cx4|OMBDPQvx4`r`}4Ze5_ipdObGMTi3bZHd5PC zcY0;?uBWu$PSvjJeb87nY7ghNv?%M@SoDl6IWt`bQCosfSh$#D6$ea~QhKM^ud2Ut z+9PYJuVpoELmN-A`F$BicO{BSYg@#tS%avVfb}DxL)|NanJ)#zB!2~?#Ot%H7--9N zU$bs0fS5G!m5M4&WK3#a|H|Tgw*?X-;H+Lu@kwA>qSR~7UC7b)7MJXTn6PG>n@8jP zW+}F^X$$c;U~4ryqRF; z>`j!tbLMK4ZGyY643|~?%Mu#fm!l%wAKjBDmd+VYmp3S#$scD$~bxbf|z#)hShN0*AhRaPDcmqrftGlHq4^54MM$Xfy(2> zH8QYVMzmn_oHbvJCB`IN~E&{1*h&0gEM{e zKvWvzp(!BqMX8`t#)~0nq}Wa zr6>FRPyp;AAB&)1$5@;r$23J{K&~>TWjZf7V$wFzmGM95CXhFG1cJNVAXks}C+&2- zbf9Qn*D8N}Afd2kpwDxns3%1uaFhAqDV8ksWiWY|quuLGZ0)SqrJ!Y8yX}@}IyC$C zQ3rCUsn}#>F#D8%D?q~ySy4j&he%Bs{{7V%rl!ui`@KQP?NTi+_iN{cwom&9RaMRR zB~z!hz|0HAgB9_Ijvpe-zr#jLbckJsc>vmo{+im?t8lA;N#fD4?{lb&J0V8Gocq%; f1ihv=QIDh{M_<9V+45Z2{KE4_qW}V3B0uV%GgrOJ literal 0 HcmV?d00001