diff --git a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java
index dad32dc8222..f0388955387 100644
--- a/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java
+++ b/jetty-http2/http2-client/src/main/java/org/eclipse/jetty/http2/client/HTTP2Client.java
@@ -137,7 +137,18 @@ public class HTTP2Client extends ContainerLifeCycle
setByteBufferPool(new MappedByteBufferPool());
if (connectionFactory == null)
- setClientConnectionFactory(new HTTP2ClientConnectionFactory());
+ {
+ HTTP2ClientConnectionFactory h2 = new HTTP2ClientConnectionFactory();
+ ALPNClientConnectionFactory alpn = new ALPNClientConnectionFactory(getExecutor(), h2, getProtocols());
+ setClientConnectionFactory((endPoint, context) ->
+ {
+ ClientConnectionFactory factory = h2;
+ SslContextFactory sslContextFactory = (SslContextFactory)context.get(SslClientConnectionFactory.SSL_CONTEXT_FACTORY_CONTEXT_KEY);
+ if (sslContextFactory != null)
+ factory = new SslClientConnectionFactory(sslContextFactory, getByteBufferPool(), getExecutor(), alpn);
+ return factory.newConnection(endPoint, context);
+ });
+ }
if (sessions == null)
{
@@ -356,17 +367,7 @@ public class HTTP2Client extends ContainerLifeCycle
context.put(HTTP2ClientConnectionFactory.BYTE_BUFFER_POOL_CONTEXT_KEY, getByteBufferPool());
context.put(HTTP2ClientConnectionFactory.EXECUTOR_CONTEXT_KEY, getExecutor());
context.put(HTTP2ClientConnectionFactory.SCHEDULER_CONTEXT_KEY, getScheduler());
-
- ClientConnectionFactory factory = getClientConnectionFactory();
-
- SslContextFactory sslContextFactory = (SslContextFactory)context.get(SslClientConnectionFactory.SSL_CONTEXT_FACTORY_CONTEXT_KEY);
- if (sslContextFactory != null)
- {
- ALPNClientConnectionFactory alpn = new ALPNClientConnectionFactory(getExecutor(), factory, getProtocols());
- factory = new SslClientConnectionFactory(sslContextFactory, getByteBufferPool(), getExecutor(), alpn);
- }
-
- return factory.newConnection(endpoint, context);
+ return getClientConnectionFactory().newConnection(endpoint, context);
}
@Override
diff --git a/jetty-http2/http2-http-client-transport/pom.xml b/jetty-http2/http2-http-client-transport/pom.xml
index be073c272d9..df28dd82e04 100644
--- a/jetty-http2/http2-http-client-transport/pom.xml
+++ b/jetty-http2/http2-http-client-transport/pom.xml
@@ -15,6 +15,38 @@
+
+
+ maven-dependency-plugin
+
+
+ copy
+ generate-resources
+
+ copy
+
+
+
+
+ org.mortbay.jetty.alpn
+ alpn-boot
+ ${alpn.version}
+ jar
+ false
+ ${project.build.directory}/alpn
+
+
+
+
+
+
+
+ maven-surefire-plugin
+
+ -Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar
+
+
+
diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java
index 82e4ba3f92f..ea16c18feaf 100644
--- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java
+++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java
@@ -22,19 +22,24 @@ import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Map;
+import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpClientTransport;
import org.eclipse.jetty.client.HttpDestination;
import org.eclipse.jetty.client.Origin;
import org.eclipse.jetty.client.api.Connection;
+import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.client.HTTP2Client;
+import org.eclipse.jetty.http2.client.HTTP2ClientConnectionFactory;
import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;
import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
@ManagedObject("The HTTP/2 client transport")
public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements HttpClientTransport
@@ -68,7 +73,7 @@ public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements
addBean(client);
super.doStart();
- this.connectionFactory = client.getClientConnectionFactory();
+ this.connectionFactory = new HTTP2ClientConnectionFactory();
client.setClientConnectionFactory((endPoint, context) ->
{
HttpDestination destination = (HttpDestination)context.get(HTTP_DESTINATION_CONTEXT_KEY);
@@ -128,13 +133,21 @@ public class HttpClientTransportOverHTTP2 extends ContainerLifeCycle implements
}
};
- client.connect(httpClient.getSslContextFactory(), address, listener, promise, context);
+ SslContextFactory sslContextFactory = null;
+ if (HttpScheme.HTTPS.is(destination.getScheme()))
+ sslContextFactory = httpClient.getSslContextFactory();
+
+ client.connect(sslContextFactory, address, listener, promise, context);
}
@Override
public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map context) throws IOException
{
- return connectionFactory.newConnection(endPoint, context);
+ ClientConnectionFactory factory = connectionFactory;
+ SslContextFactory sslContextFactory = (SslContextFactory)context.get(SslClientConnectionFactory.SSL_CONTEXT_FACTORY_CONTEXT_KEY);
+ if (sslContextFactory != null)
+ factory = new ALPNClientConnectionFactory(client.getExecutor(), factory, client.getProtocols());
+ return factory.newConnection(endPoint, context);
}
protected HttpConnectionOverHTTP2 newHttpConnection(HttpDestination destination, Session session)
diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java
index 40f322098cd..7a061eca852 100644
--- a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java
+++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java
@@ -21,9 +21,13 @@ package org.eclipse.jetty.http2.client.http;
import java.util.concurrent.Executor;
import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http2.client.HTTP2Client;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.Assert;
+import org.junit.Ignore;
import org.junit.Test;
public class HttpClientTransportOverHTTP2Test
@@ -51,4 +55,24 @@ public class HttpClientTransportOverHTTP2Test
Assert.assertTrue(http2Client.isStopped());
}
+
+ @Ignore
+ @Test
+ public void testExternalServer() throws Exception
+ {
+ HTTP2Client http2Client = new HTTP2Client();
+ SslContextFactory sslContextFactory = new SslContextFactory();
+ HttpClient httpClient = new HttpClient(new HttpClientTransportOverHTTP2(http2Client), sslContextFactory);
+ Executor executor = new QueuedThreadPool();
+ httpClient.setExecutor(executor);
+
+ httpClient.start();
+
+// ContentResponse response = httpClient.GET("https://http2.akamai.com/");
+ ContentResponse response = httpClient.GET("https://webtide.com/");
+
+ Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
+
+ httpClient.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
new file mode 100644
index 00000000000..287d28319e0
--- /dev/null
+++ b/jetty-http2/http2-http-client-transport/src/test/resources/jetty-logging.properties
@@ -0,0 +1,5 @@
+org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
+#org.eclipse.jetty.client.LEVEL=DEBUG
+org.eclipse.jetty.http2.hpack.LEVEL=INFO
+#org.eclipse.jetty.http2.LEVEL=DEBUG
+#org.eclipse.jetty.io.ssl.LEVEL=DEBUG
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java
index b213a5b0285..1ae1a7a0c33 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java
@@ -84,29 +84,42 @@ public abstract class AbstractConnection implements Connection
protected void failedCallback(final Callback callback, final Throwable x)
{
- // TODO always dispatch failure ?
- try
+ if (callback.isNonBlocking())
{
- getExecutor().execute(new Runnable()
+ try
{
- @Override
- public void run()
- {
- try
- {
- callback.failed(x);
- }
- catch (Exception e)
- {
- LOG.warn(e);
- }
- }
- });
+ callback.failed(x);
+ }
+ catch (Exception e)
+ {
+ LOG.warn(e);
+ }
}
- catch(RejectedExecutionException e)
+ else
{
- LOG.debug(e);
- callback.failed(x);
+ try
+ {
+ getExecutor().execute(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ callback.failed(x);
+ }
+ catch (Exception e)
+ {
+ LOG.warn(e);
+ }
+ }
+ });
+ }
+ catch(RejectedExecutionException e)
+ {
+ LOG.debug(e);
+ callback.failed(x);
+ }
}
}
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java
index 73acb763aaf..0444f788aba 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractEndPoint.java
@@ -216,8 +216,8 @@ public abstract class AbstractEndPoint extends IdleTimeout implements EndPoint
isOpen()?"Open":"CLOSED",
isInputShutdown()?"ISHUT":"in",
isOutputShutdown()?"OSHUT":"out",
- _fillInterest.isInterested()?"R":"-",
- _writeFlusher.isInProgress()?"W":"-",
+ _fillInterest.toStateString(),
+ _writeFlusher.toStateString(),
getIdleFor(),
getIdleTimeout(),
getConnection()==null?null:getConnection().getClass().getSimpleName());
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java b/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java
index 4eff032a8ab..b5c48c4b088 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/FillInterest.java
@@ -138,7 +138,13 @@ public abstract class FillInterest
@Override
public String toString()
{
- return String.format("FillInterest@%x{%b,%s}", hashCode(), _interested.get(), _interested.get());
+ return String.format("FillInterest@%x{%b,%s}", hashCode(), _interested.get()!=null, _interested.get());
+ }
+
+
+ public String toStateString()
+ {
+ return _interested.get()==null?"-":"FI";
}
/**
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java b/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java
index 612fa5603d0..f2dea7d8c36 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java
@@ -522,4 +522,23 @@ abstract public class WriteFlusher
{
return String.format("WriteFlusher@%x{%s}", hashCode(), _state.get());
}
+
+ public String toStateString()
+ {
+ switch(_state.get().getType())
+ {
+ case WRITING:
+ return "W";
+ case PENDING:
+ return "P";
+ case COMPLETING:
+ return "C";
+ case IDLE:
+ return "-";
+ case FAILED:
+ return "F";
+ default:
+ return "?";
+ }
+ }
}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
index 0c8a463c67c..d92cb3a03ea 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
@@ -2435,25 +2435,6 @@ public class Request implements HttpServletRequest
@Override
public T upgrade(Class handlerClass) throws IOException, ServletException
{
- if (getContext() == null)
- throw new ServletException ("Unable to instantiate "+handlerClass);
-
- try
- {
- //Instantiate an instance and inject it
- T h = getContext().createInstance(handlerClass);
-
- //TODO handle the rest of the upgrade process
-
- return h;
- }
- catch (Exception e)
- {
- if (e instanceof ServletException)
- throw (ServletException)e;
- throw new ServletException(e);
- }
+ throw new ServletException("HttpServletRequest.upgrade() not supported in Jetty");
}
-
-
}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java
index 42b7086d4cc..1ae25d8a668 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHolder.java
@@ -73,6 +73,7 @@ public class ServletHolder extends Holder implements UserIdentity.Scope
private static final Logger LOG = Log.getLogger(ServletHolder.class);
private int _initOrder = -1;
private boolean _initOnStartup=false;
+ private boolean _initialized = false;
private Map _roleMap;
private String _forcedPath;
private String _runAsRole;
@@ -81,7 +82,6 @@ public class ServletHolder extends Holder implements UserIdentity.Scope
private ServletRegistration.Dynamic _registration;
private JspContainer _jspContainer;
-
private transient Servlet _servlet;
private transient Config _config;
private transient long _unavailable;
@@ -396,21 +396,24 @@ public class ServletHolder extends Holder implements UserIdentity.Scope
public void initialize ()
throws Exception
{
- super.initialize();
- if (_extInstance || _initOnStartup)
- {
- try
+ if(!_initialized){
+ super.initialize();
+ if (_extInstance || _initOnStartup)
{
- initServlet();
- }
- catch(Exception e)
- {
- if (_servletHandler.isStartWithUnavailable())
- LOG.ignore(e);
- else
- throw e;
+ try
+ {
+ initServlet();
+ }
+ catch(Exception e)
+ {
+ if (_servletHandler.isStartWithUnavailable())
+ LOG.ignore(e);
+ else
+ throw e;
+ }
}
}
+ _initialized = true;
}
@@ -443,6 +446,7 @@ public class ServletHolder extends Holder implements UserIdentity.Scope
_servlet=null;
_config=null;
+ _initialized = false;
}
/* ------------------------------------------------------------ */
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherForwardTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherForwardTest.java
index 825a4ae60bd..51e9f0d910d 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherForwardTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherForwardTest.java
@@ -21,6 +21,8 @@ package org.eclipse.jetty.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
@@ -88,6 +90,7 @@ public class DispatcherForwardTest
// 2. assert query => a=1 one
// 1. assert query => a=1 one
+ CountDownLatch latch = new CountDownLatch(1);
final String query1 = "a=1%20one";
servlet1 = new HttpServlet()
{
@@ -100,6 +103,7 @@ public class DispatcherForwardTest
checkThat(req.getQueryString(),Matchers.equalTo(query1));
checkThat(req.getParameter("a"),Matchers.equalTo("1 one"));
+ latch.countDown();
}
};
servlet2 = new HttpServlet()
@@ -120,6 +124,7 @@ public class DispatcherForwardTest
"Connection: close\r\n" +
"\r\n";
String response = connector.getResponses(request);
+ Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
}
@@ -131,7 +136,8 @@ public class DispatcherForwardTest
// 2. assert query => a=2
// 1. assert query => a=1
- final String query1 = "a=1$20one&b=2%20two";
+ CountDownLatch latch = new CountDownLatch(1);
+ final String query1 = "a=1%20one&b=2%20two";
final String query2 = "a=3%20three";
final String query3 = "a=3%20three&b=2%20two";
servlet1 = new HttpServlet()
@@ -143,9 +149,10 @@ public class DispatcherForwardTest
req.getRequestDispatcher("/two?" + query2).forward(req, resp);
- checkThat(req.getQueryString(),Matchers.equalTo(query1));
+ checkThat(req.getQueryString(), Matchers.equalTo(query1));
checkThat(req.getParameter("a"),Matchers.equalTo("1 one"));
checkThat(req.getParameter("b"),Matchers.equalTo("2 two"));
+ latch.countDown();
}
};
servlet2 = new HttpServlet()
@@ -167,6 +174,7 @@ public class DispatcherForwardTest
"Connection: close\r\n" +
"\r\n";
String response = connector.getResponses(request);
+ Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
}
@@ -178,6 +186,7 @@ public class DispatcherForwardTest
// 2. assert query => a=1&b=2
// 1. assert query => a=1
+ CountDownLatch latch = new CountDownLatch(1);
final String query1 = "a=1%20one";
final String query2 = "b=2%20two";
final String query3 = "b=2%20two&a=1%20one";
@@ -192,6 +201,7 @@ public class DispatcherForwardTest
checkThat(req.getQueryString(),Matchers.equalTo(query1));
checkThat(req.getParameter("a"),Matchers.equalTo("1 one"));
+ latch.countDown();
}
};
servlet2 = new HttpServlet()
@@ -213,6 +223,7 @@ public class DispatcherForwardTest
"Connection: close\r\n" +
"\r\n";
String response = connector.getResponses(request);
+ Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
}
@@ -224,6 +235,7 @@ public class DispatcherForwardTest
// 2. assert query => a=1 + params => a=1,2
// 1. assert query => a=1 + params => a=1,2
+ CountDownLatch latch = new CountDownLatch(1);
final String query1 = "a=1%20one";
final String form = "a=2%20two";
servlet1 = new HttpServlet()
@@ -240,6 +252,7 @@ public class DispatcherForwardTest
checkThat(values, Matchers.notNullValue());
checkThat(2, Matchers.equalTo(values.length));
checkThat(values, Matchers.arrayContainingInAnyOrder("1 one", "2 two"));
+ latch.countDown();
}
};
servlet2 = new HttpServlet()
@@ -266,6 +279,7 @@ public class DispatcherForwardTest
"\r\n" +
form;
String response = connector.getResponses(request);
+ Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
}
@@ -277,6 +291,7 @@ public class DispatcherForwardTest
// 2. assert query => a=3 + params => a=3,2,1
// 1. assert query => a=1 + params => a=1,2
+ CountDownLatch latch = new CountDownLatch(1);
final String query1 = "a=1%20one";
final String query2 = "a=3%20three";
final String form = "a=2%20two";
@@ -294,6 +309,7 @@ public class DispatcherForwardTest
checkThat(values, Matchers.notNullValue());
checkThat(2, Matchers.equalTo(values.length));
checkThat(values, Matchers.arrayContainingInAnyOrder("1 one", "2 two"));
+ latch.countDown();
}
};
servlet2 = new HttpServlet()
@@ -320,6 +336,7 @@ public class DispatcherForwardTest
"\r\n" +
form;
String response = connector.getResponses(request);
+ Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
}
@@ -331,6 +348,7 @@ public class DispatcherForwardTest
// 2. assert query => a=1&c=3 + params => a=1&b=2&c=3
// 1. assert query => a=1 + params => a=1&b=2
+ CountDownLatch latch = new CountDownLatch(1);
final String query1 = "a=1%20one";
final String query2 = "c=3%20three";
final String query3 = "c=3%20three&a=1%20one";
@@ -348,6 +366,7 @@ public class DispatcherForwardTest
checkThat(req.getParameter("a"),Matchers.equalTo("1 one"));
checkThat(req.getParameter("b"),Matchers.equalTo("2 two"));
checkThat(req.getParameter("c"), Matchers.nullValue());
+ latch.countDown();
}
};
servlet2 = new HttpServlet()
@@ -373,6 +392,7 @@ public class DispatcherForwardTest
"\r\n" +
form;
String response = connector.getResponses(request);
+ Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
}
@@ -385,6 +405,7 @@ public class DispatcherForwardTest
// 2. assert query => a=1&c=3 + params => a=1&b=2&c=3
// 1. assert query => a=1 + params => a=1&b=2
+ CountDownLatch latch = new CountDownLatch(1);
final String query1 = "a=1%20one";
final String query2 = "c=3%20three";
final String query3 = "c=3%20three&a=1%20one";
@@ -404,6 +425,7 @@ public class DispatcherForwardTest
checkThat(req.getParameter("a"),Matchers.equalTo("1 one"));
checkThat(req.getParameter("b"),Matchers.equalTo("2 two"));
checkThat(req.getParameter("c"), Matchers.nullValue());
+ latch.countDown();
}
};
servlet2 = new HttpServlet()
@@ -429,12 +451,14 @@ public class DispatcherForwardTest
"\r\n" +
form;
String response = connector.getResponses(request);
+ Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
}
@Test
public void testContentCanBeReadViaInputStreamAfterForwardWithoutQuery() throws Exception
{
+ CountDownLatch latch = new CountDownLatch(1);
final String query1 = "a=1%20one";
final String form = "c=3%20three";
servlet1 = new HttpServlet()
@@ -448,6 +472,7 @@ public class DispatcherForwardTest
checkThat(req.getQueryString(),Matchers.equalTo(query1));
checkThat(req.getParameter("c"), Matchers.nullValue());
+ latch.countDown();
}
};
servlet2 = new HttpServlet()
@@ -473,12 +498,14 @@ public class DispatcherForwardTest
"\r\n" +
form;
String response = connector.getResponses(request);
+ Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
}
@Test
public void testContentCanBeReadViaInputStreamAfterForwardWithQuery() throws Exception
{
+ CountDownLatch latch = new CountDownLatch(1);
final String query1 = "a=1%20one";
final String query2 = "b=2%20two";
final String query3 = "b=2%20two&a=1%20one";
@@ -494,6 +521,7 @@ public class DispatcherForwardTest
checkThat(req.getQueryString(),Matchers.equalTo(query1));
checkThat(req.getParameter("c"), Matchers.nullValue());
+ latch.countDown();
}
};
servlet2 = new HttpServlet()
@@ -520,6 +548,7 @@ public class DispatcherForwardTest
"\r\n" +
form;
String response = connector.getResponses(request);
+ Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(response, response.startsWith("HTTP/1.1 200"));
}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DefaultServletStarvationTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DefaultServletStarvationTest.java
deleted file mode 100644
index e0908085797..00000000000
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DefaultServletStarvationTest.java
+++ /dev/null
@@ -1,213 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995-2015 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.servlets;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.Socket;
-import java.nio.channels.SelectionKey;
-import java.nio.channels.SocketChannel;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.jetty.io.ManagedSelector;
-import org.eclipse.jetty.io.SelectChannelEndPoint;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.servlet.DefaultServlet;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
-import org.eclipse.jetty.toolchain.test.TestTracker;
-import org.eclipse.jetty.util.thread.QueuedThreadPool;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-
-public class DefaultServletStarvationTest
-{
- @Rule
- public TestTracker tracker = new TestTracker();
- private Server _server;
-
- @After
- public void dispose() throws Exception
- {
- if (_server != null)
- _server.stop();
- }
-
- @Test
- public void testDefaultServletStarvation() throws Exception
- {
- int maxThreads = 2;
- QueuedThreadPool threadPool = new QueuedThreadPool(maxThreads, maxThreads);
- threadPool.setDetailedDump(true);
- _server = new Server(threadPool);
-
- // Prepare a big file to download.
- File directory = MavenTestingUtils.getTargetTestingDir();
- Files.createDirectories(directory.toPath());
- String resourceName = "resource.bin";
- Path resourcePath = Paths.get(directory.getPath(), resourceName);
- try (OutputStream output = Files.newOutputStream(resourcePath, StandardOpenOption.CREATE, StandardOpenOption.WRITE))
- {
- byte[] chunk = new byte[1024];
- Arrays.fill(chunk,(byte)'X');
- chunk[chunk.length-2]='\r';
- chunk[chunk.length-1]='\n';
- for (int i = 0; i < 256 * 1024; ++i)
- output.write(chunk);
- }
-
- final CountDownLatch writePending = new CountDownLatch(1);
- ServerConnector connector = new ServerConnector(_server, 0, 1)
- {
- @Override
- protected SelectChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException
- {
- return new SelectChannelEndPoint(channel, selectSet, key, getScheduler(), getIdleTimeout())
- {
- @Override
- protected void onIncompleteFlush()
- {
- super.onIncompleteFlush();
- writePending.countDown();
- }
- };
- }
- };
- _server.addConnector(connector);
-
- ServletContextHandler context = new ServletContextHandler(_server, "/");
- context.setResourceBase(directory.toURI().toString());
- context.addServlet(DefaultServlet.class, "/*").setAsyncSupported(false);
- _server.setHandler(context);
-
- _server.start();
-
- List sockets = new ArrayList<>();
- for (int i = 0; i < maxThreads; ++i)
- {
- Socket socket = new Socket("localhost", connector.getLocalPort());
- sockets.add(socket);
- OutputStream output = socket.getOutputStream();
- String request = "" +
- "GET /" + resourceName + " HTTP/1.1\r\n" +
- "Host: localhost\r\n" +
-// "Connection: close\r\n" +
- "\r\n";
- output.write(request.getBytes(StandardCharsets.UTF_8));
- output.flush();
- Thread.sleep(100);
- }
-
-
- // Wait for a the servlet to block.
- Assert.assertTrue(writePending.await(5, TimeUnit.SECONDS));
-
- Thread.sleep(1000);
- _server.dumpStdErr();
- Thread.sleep(1000);
-
-
- ScheduledFuture> dumper = Executors.newSingleThreadScheduledExecutor().schedule(new Runnable()
- {
- @Override
- public void run()
- {
- _server.dumpStdErr();
- }
- }, 10, TimeUnit.SECONDS);
-
-
- long expected = Files.size(resourcePath);
- byte[] buffer = new byte[48 * 1024];
- for (Socket socket : sockets)
- {
- String socketString = socket.toString();
- long total = 0;
- InputStream input = socket.getInputStream();
-
- // look for CRLFCRLF
- StringBuilder header = new StringBuilder();
- int state=0;
- while (state<4 && header.length()<2048)
- {
- int ch=input.read();
- if (ch<0)
- break;
- header.append((char)ch);
- switch(state)
- {
- case 0:
- if (ch=='\r')
- state=1;
- break;
- case 1:
- if (ch=='\n')
- state=2;
- else
- state=0;
- break;
- case 2:
- if (ch=='\r')
- state=3;
- else
- state=0;
- break;
- case 3:
- if (ch=='\n')
- state=4;
- else
- state=0;
- break;
- }
- }
-
- while (total sockets = new ArrayList<>();
+ for (int i = 0; i < maxThreads*2; ++i)
+ {
+ Socket socket = new Socket("localhost", connector.getLocalPort());
+ sockets.add(socket);
+ OutputStream output = socket.getOutputStream();
+ String request = "" +
+ "GET /" + resourceName + " HTTP/1.1\r\n" +
+ "Host: localhost\r\n" +
+ "\r\n";
+ output.write(request.getBytes(StandardCharsets.UTF_8));
+ output.flush();
+ Thread.sleep(100);
+ }
+
+ // Wait for a the servlet to block.
+ Assert.assertTrue(writePending.await(5, TimeUnit.SECONDS));
+
+ long expected = Files.size(resourcePath);
+ byte[] buffer = new byte[48 * 1024];
+ List> totals = new ArrayList<>();
+ for (Socket socket : sockets)
+ {
+ final Exchanger x = new Exchanger<>();
+ totals.add(x);
+ final InputStream input = socket.getInputStream();
+
+ new Thread()
+ {
+ @Override
+ public void run()
+ {
+ long total=0;
+ try
+ {
+ // look for CRLFCRLF
+ StringBuilder header = new StringBuilder();
+ int state=0;
+ while (state<4 && header.length()<2048)
+ {
+ int ch=input.read();
+ if (ch<0)
+ break;
+ header.append((char)ch);
+ switch(state)
+ {
+ case 0:
+ if (ch=='\r')
+ state=1;
+ break;
+ case 1:
+ if (ch=='\n')
+ state=2;
+ else
+ state=0;
+ break;
+ case 2:
+ if (ch=='\r')
+ state=3;
+ else
+ state=0;
+ break;
+ case 3:
+ if (ch=='\n')
+ state=4;
+ else
+ state=0;
+ break;
+ }
+ }
+
+ while (total x : totals)
+ {
+ Long total = x.exchange(-1L,10000,TimeUnit.SECONDS);
+ Assert.assertEquals(expected,total.longValue());
+ }
+
+ // We could read everything, good.
+ for (Socket socket : sockets)
+ socket.close();
+ }
+
+ @Test
+ public void testFailureStarvation() throws Exception
+ {
+ try
+ {
+ ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(true);
+
+ int acceptors = 0;
+ int selectors = 1;
+ int maxThreads = 10;
+ final int barried=maxThreads-acceptors-selectors;
+ final CyclicBarrier barrier = new CyclicBarrier(barried);
+
+
+ QueuedThreadPool threadPool = new QueuedThreadPool(maxThreads, maxThreads);
+ threadPool.setDetailedDump(true);
+ _server = new Server(threadPool);
+
+
+ ServerConnector connector = new ServerConnector(_server, acceptors, selectors)
+ {
+ @Override
+ protected SelectChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException
+ {
+ return new SelectChannelEndPoint(channel, selectSet, key, getScheduler(), getIdleTimeout())
+ {
+
+ @Override
+ public boolean flush(ByteBuffer... buffers) throws IOException
+ {
+ super.flush(buffers[0]);
+ throw new IOException("TEST FAILURE");
+ }
+
+ };
+ }
+ };
+ connector.setIdleTimeout(Long.MAX_VALUE);
+ _server.addConnector(connector);
+
+ final AtomicInteger count = new AtomicInteger(0);
+ _server.setHandler(new AbstractHandler()
+ {
+ @Override
+ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ int c=count.getAndIncrement();
+ try
+ {
+ if (c sockets = new ArrayList<>();
+ for (int i = 0; i < maxThreads*2; ++i)
+ {
+ Socket socket = new Socket("localhost", connector.getLocalPort());
+ sockets.add(socket);
+ OutputStream output = socket.getOutputStream();
+ String request = "" +
+ "GET / HTTP/1.1\r\n" +
+ "Host: localhost\r\n" +
+ // "Connection: close\r\n" +
+ "\r\n";
+ output.write(request.getBytes(StandardCharsets.UTF_8));
+ output.flush();
+ }
+
+
+ byte[] buffer = new byte[48 * 1024];
+ List> totals = new ArrayList<>();
+ for (Socket socket : sockets)
+ {
+ final Exchanger x = new Exchanger<>();
+ totals.add(x);
+ final InputStream input = socket.getInputStream();
+
+ new Thread()
+ {
+ @Override
+ public void run()
+ {
+ int read=0;
+ try
+ {
+ // look for CRLFCRLF
+ StringBuilder header = new StringBuilder();
+ int state=0;
+ while (state<4 && header.length()<2048)
+ {
+ int ch=input.read();
+ if (ch<0)
+ break;
+ header.append((char)ch);
+ switch(state)
+ {
+ case 0:
+ if (ch=='\r')
+ state=1;
+ break;
+ case 1:
+ if (ch=='\n')
+ state=2;
+ else
+ state=0;
+ break;
+ case 2:
+ if (ch=='\r')
+ state=3;
+ else
+ state=0;
+ break;
+ case 3:
+ if (ch=='\n')
+ state=4;
+ else
+ state=0;
+ break;
+ }
+ }
+
+ read=input.read(buffer);
+ }
+ catch (IOException e)
+ {
+ // e.printStackTrace();
+ }
+ finally
+ {
+ try
+ {
+ x.exchange(read);
+ }
+ catch (InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+ }.start();
+ }
+
+ for (Exchanger x : totals)
+ {
+ Integer read = x.exchange(-1,10,TimeUnit.SECONDS);
+ Assert.assertEquals(-1,read.intValue());
+ }
+
+ // We could read everything, good.
+ for (Socket socket : sockets)
+ socket.close();
+
+ _server.stop();
+ }
+ finally
+ {
+ ((StdErrLog)Log.getLogger(HttpChannel.class)).setHideStacks(false);
+ }
+ }
+}
diff --git a/tests/test-http-client-transport/pom.xml b/tests/test-http-client-transport/pom.xml
index ec8e245353e..5913b35443e 100644
--- a/tests/test-http-client-transport/pom.xml
+++ b/tests/test-http-client-transport/pom.xml
@@ -17,6 +17,36 @@
+
+ maven-dependency-plugin
+
+
+ copy
+ generate-resources
+
+ copy
+
+
+
+
+ org.mortbay.jetty.alpn
+ alpn-boot
+ ${alpn.version}
+ jar
+ false
+ ${project.build.directory}/alpn
+
+
+
+
+
+
+
+ maven-surefire-plugin
+
+ -Xbootclasspath/p:${project.build.directory}/alpn/alpn-boot-${alpn.version}.jar
+
+
org.apache.maven.plugins
maven-deploy-plugin
@@ -47,6 +77,12 @@
${project.version}
test
+
+ org.eclipse.jetty
+ jetty-alpn-server
+ ${project.version}
+ test
+
org.eclipse.jetty.http2
http2-http-client-transport
diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java
index 0cc5a0fb89b..ca377c311c2 100644
--- a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java
+++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AbstractTest.java
@@ -18,22 +18,28 @@
package org.eclipse.jetty.http.client;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.List;
+import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpClientTransport;
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
+import org.eclipse.jetty.http2.HTTP2Cipher;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2;
+import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.Handler;
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.toolchain.test.TestTracker;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.After;
import org.junit.Rule;
@@ -44,15 +50,16 @@ import org.junit.runners.Parameterized;
public abstract class AbstractTest
{
@Parameterized.Parameters(name = "transport: {0}")
- public static List