Merge branch 'jetty-9.4.x' of github.com:eclipse/jetty.project into jetty-9.4.x
This commit is contained in:
commit
04c1447f88
|
@ -46,7 +46,7 @@ def getFullBuild(jdk, os) {
|
|||
publisherStrategy: 'EXPLICIT',
|
||||
globalMavenSettingsConfig: settingsName,
|
||||
mavenLocalRepo: localRepo) {
|
||||
sh "mvn -V -B clean install -DskipTests -T6"
|
||||
sh "mvn -V -B clean install -DskipTests -T6 -e"
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ def getFullBuild(jdk, os) {
|
|||
publisherStrategy: 'EXPLICIT',
|
||||
globalMavenSettingsConfig: settingsName,
|
||||
mavenLocalRepo: localRepo) {
|
||||
sh "mvn -V -B javadoc:javadoc -T6"
|
||||
sh "mvn -V -B javadoc:javadoc -T6 -e"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.9.v20160720/alpn-boot-8.1.9.v20160720.jar|lib/alpn/alpn-boot-8.1.9.v20160720.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.9.v20160720|lib/alpn/alpn-boot-8.1.9.v20160720.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.9.v20160720.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.9.v20160720/alpn-boot-8.1.9.v20160720.jar|lib/alpn/alpn-boot-8.1.9.v20160720.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.9.v20160720|lib/alpn/alpn-boot-8.1.9.v20160720.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.9.v20160720.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.9.v20160720/alpn-boot-8.1.9.v20160720.jar|lib/alpn/alpn-boot-8.1.9.v20160720.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.9.v20160720|lib/alpn/alpn-boot-8.1.9.v20160720.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.9.v20160720.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.10.v20161026/alpn-boot-8.1.10.v20161026.jar|lib/alpn/alpn-boot-8.1.10.v20161026.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.10.v20161026|lib/alpn/alpn-boot-8.1.10.v20161026.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.10.v20161026.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar|lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar|lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar|lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar|lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar|lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.11.v20170118/alpn-boot-8.1.11.v20170118.jar|lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.11.v20170118|lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.11.v20170118.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.12.v20180117/alpn-boot-8.1.12.v20180117.jar|lib/alpn/alpn-boot-8.1.12.v20180117.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.12.v20180117|lib/alpn/alpn-boot-8.1.12.v20180117.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.12.v20180117/alpn-boot-8.1.12.v20180117.jar|lib/alpn/alpn-boot-8.1.12.v20180117.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.12.v20180117|lib/alpn/alpn-boot-8.1.12.v20180117.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.12.v20180117/alpn-boot-8.1.12.v20180117.jar|lib/alpn/alpn-boot-8.1.12.v20180117.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.12.v20180117|lib/alpn/alpn-boot-8.1.12.v20180117.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.12.v20180117/alpn-boot-8.1.12.v20180117.jar|lib/alpn/alpn-boot-8.1.12.v20180117.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.12.v20180117|lib/alpn/alpn-boot-8.1.12.v20180117.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.3.v20150130/alpn-boot-8.1.3.v20150130.jar|lib/alpn/alpn-boot-8.1.3.v20150130.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.3.v20150130|lib/alpn/alpn-boot-8.1.3.v20150130.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.3.v20150130.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.3.v20150130/alpn-boot-8.1.3.v20150130.jar|lib/alpn/alpn-boot-8.1.3.v20150130.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.3.v20150130|lib/alpn/alpn-boot-8.1.3.v20150130.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.3.v20150130.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.4.v20150727/alpn-boot-8.1.4.v20150727.jar|lib/alpn/alpn-boot-8.1.4.v20150727.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.4.v20150727|lib/alpn/alpn-boot-8.1.4.v20150727.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.4.v20150727.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.5.v20150921/alpn-boot-8.1.5.v20150921.jar|lib/alpn/alpn-boot-8.1.5.v20150921.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.5.v20150921|lib/alpn/alpn-boot-8.1.5.v20150921.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.5.v20150921.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.6.v20151105/alpn-boot-8.1.6.v20151105.jar|lib/alpn/alpn-boot-8.1.6.v20151105.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.6.v20151105|lib/alpn/alpn-boot-8.1.6.v20151105.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.6.v20151105.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.6.v20151105/alpn-boot-8.1.6.v20151105.jar|lib/alpn/alpn-boot-8.1.6.v20151105.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.6.v20151105|lib/alpn/alpn-boot-8.1.6.v20151105.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.6.v20151105.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.7.v20160121|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.7.v20160121|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.7.v20160121|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.7.v20160121|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.7.v20160121|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.7.v20160121/alpn-boot-8.1.7.v20160121.jar|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.7.v20160121|lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.7.v20160121.jar
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[files]
|
||||
http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.8.v20160420/alpn-boot-8.1.8.v20160420.jar|lib/alpn/alpn-boot-8.1.8.v20160420.jar
|
||||
maven://org.mortbay.jetty.alpn/alpn-boot/8.1.8.v20160420|lib/alpn/alpn-boot-8.1.8.v20160420.jar
|
||||
|
||||
[exec]
|
||||
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.8.v20160420.jar
|
||||
|
|
|
@ -14,7 +14,7 @@ specific version of Java.
|
|||
# Java versions.
|
||||
#
|
||||
# All versions of the alpn-boot jar can be found at
|
||||
# http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/
|
||||
# https://repo1.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/
|
||||
|
||||
[depend]
|
||||
alpn-impl/alpn-${java.version}
|
||||
|
|
|
@ -54,8 +54,7 @@ public class ContinueProtocolHandler implements ProtocolHandler
|
|||
{
|
||||
boolean is100 = response.getStatus() == HttpStatus.CONTINUE_100;
|
||||
boolean expect100 = request.getHeaders().contains(HttpHeader.EXPECT, HttpHeaderValue.CONTINUE.asString());
|
||||
HttpConversation conversation = ((HttpRequest)request).getConversation();
|
||||
boolean handled100 = conversation.getAttribute(ATTRIBUTE) != null;
|
||||
boolean handled100 = request.getAttributes().containsKey(ATTRIBUTE);
|
||||
return (is100 || expect100) && !handled100;
|
||||
}
|
||||
|
||||
|
@ -81,34 +80,28 @@ public class ContinueProtocolHandler implements ProtocolHandler
|
|||
Request request = response.getRequest();
|
||||
HttpConversation conversation = ((HttpRequest)request).getConversation();
|
||||
// Mark the 100 Continue response as handled
|
||||
conversation.setAttribute(ATTRIBUTE, Boolean.TRUE);
|
||||
request.attribute(ATTRIBUTE, Boolean.TRUE);
|
||||
|
||||
// Reset the conversation listeners, since we are going to receive another response code
|
||||
conversation.updateResponseListeners(null);
|
||||
|
||||
HttpExchange exchange = conversation.getExchanges().peekLast();
|
||||
assert exchange.getResponse() == response;
|
||||
switch (response.getStatus())
|
||||
if (response.getStatus() == HttpStatus.CONTINUE_100)
|
||||
{
|
||||
case 100:
|
||||
{
|
||||
// All good, continue
|
||||
exchange.resetResponse();
|
||||
exchange.proceed(null);
|
||||
onContinue(request);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// Server either does not support 100 Continue,
|
||||
// or it does and wants to refuse the request content,
|
||||
// or we got some other HTTP status code like a redirect.
|
||||
List<Response.ResponseListener> listeners = exchange.getResponseListeners();
|
||||
HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getMediaType(), getEncoding());
|
||||
notifier.forwardSuccess(listeners, contentResponse);
|
||||
exchange.proceed(new HttpRequestException("Expectation failed", request));
|
||||
break;
|
||||
}
|
||||
// All good, continue.
|
||||
exchange.resetResponse();
|
||||
exchange.proceed(null);
|
||||
onContinue(request);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Server either does not support 100 Continue,
|
||||
// or it does and wants to refuse the request content,
|
||||
// or we got some other HTTP status code like a redirect.
|
||||
List<Response.ResponseListener> listeners = exchange.getResponseListeners();
|
||||
HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getMediaType(), getEncoding());
|
||||
notifier.forwardSuccess(listeners, contentResponse);
|
||||
exchange.proceed(new HttpRequestException("Expectation failed", request));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
|
@ -72,6 +73,7 @@ public abstract class HttpReceiver
|
|||
|
||||
private final AtomicReference<ResponseState> responseState = new AtomicReference<>(ResponseState.IDLE);
|
||||
private final HttpChannel channel;
|
||||
private List<Response.AsyncContentListener> contentListeners;
|
||||
private ContentDecoder decoder;
|
||||
private Throwable failure;
|
||||
|
||||
|
@ -262,7 +264,12 @@ public abstract class HttpReceiver
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Response headers {}{}{}", response, System.lineSeparator(), response.getHeaders().toString().trim());
|
||||
ResponseNotifier notifier = getHttpDestination().getResponseNotifier();
|
||||
notifier.notifyHeaders(exchange.getConversation().getResponseListeners(), response);
|
||||
List<Response.ResponseListener> responseListeners = exchange.getConversation().getResponseListeners();
|
||||
notifier.notifyHeaders(responseListeners, response);
|
||||
contentListeners = responseListeners.stream()
|
||||
.filter(Response.AsyncContentListener.class::isInstance)
|
||||
.map(Response.AsyncContentListener.class::cast)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Enumeration<String> contentEncodings = response.getHeaders().getValues(HttpHeader.CONTENT_ENCODING.asString(), ",");
|
||||
if (contentEncodings != null)
|
||||
|
@ -297,7 +304,7 @@ public abstract class HttpReceiver
|
|||
* @param callback the callback
|
||||
* @return whether the processing should continue
|
||||
*/
|
||||
protected boolean responseContent(HttpExchange exchange, ByteBuffer buffer, final Callback callback)
|
||||
protected boolean responseContent(HttpExchange exchange, ByteBuffer buffer, Callback callback)
|
||||
{
|
||||
out: while (true)
|
||||
{
|
||||
|
@ -324,12 +331,11 @@ public abstract class HttpReceiver
|
|||
LOG.debug("Response content {}{}{}", response, System.lineSeparator(), BufferUtil.toDetailString(buffer));
|
||||
|
||||
ResponseNotifier notifier = getHttpDestination().getResponseNotifier();
|
||||
List<Response.ResponseListener> listeners = exchange.getConversation().getResponseListeners();
|
||||
|
||||
ContentDecoder decoder = this.decoder;
|
||||
if (decoder == null)
|
||||
{
|
||||
notifier.notifyContent(listeners, response, buffer, callback);
|
||||
notifier.notifyContent(response, buffer, callback, contentListeners);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -354,8 +360,8 @@ public abstract class HttpReceiver
|
|||
{
|
||||
int size = decodeds.size();
|
||||
CountingCallback counter = new CountingCallback(callback, size);
|
||||
for (int i = 0; i < size; ++i)
|
||||
notifier.notifyContent(listeners, response, decodeds.get(i), counter);
|
||||
for (ByteBuffer decoded : decodeds)
|
||||
notifier.notifyContent(response, decoded, counter, contentListeners);
|
||||
}
|
||||
}
|
||||
catch (Throwable x)
|
||||
|
@ -476,6 +482,7 @@ public abstract class HttpReceiver
|
|||
*/
|
||||
protected void reset()
|
||||
{
|
||||
contentListeners = null;
|
||||
destroyDecoder(decoder);
|
||||
decoder = null;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.client;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
|
@ -28,7 +29,9 @@ import org.eclipse.jetty.client.api.Response;
|
|||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.CountingCallback;
|
||||
import org.eclipse.jetty.util.IteratingNestedCallback;
|
||||
import org.eclipse.jetty.util.Retainable;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
@ -110,11 +113,31 @@ public class ResponseNotifier
|
|||
|
||||
public void notifyContent(List<Response.ResponseListener> listeners, Response response, ByteBuffer buffer, Callback callback)
|
||||
{
|
||||
// Here we use an IteratingNestedCallback not to avoid the stack overflow, but to
|
||||
// invoke the listeners one after the other. When all of them have invoked the
|
||||
// callback they got passed, the callback passed to this method is finally invoked.
|
||||
ContentCallback contentCallback = new ContentCallback(listeners, response, buffer, callback);
|
||||
contentCallback.iterate();
|
||||
List<Response.AsyncContentListener> contentListeners = listeners.stream()
|
||||
.filter(Response.AsyncContentListener.class::isInstance)
|
||||
.map(Response.AsyncContentListener.class::cast)
|
||||
.collect(Collectors.toList());
|
||||
notifyContent(response, buffer, callback, contentListeners);
|
||||
}
|
||||
|
||||
public void notifyContent(Response response, ByteBuffer buffer, Callback callback, List<Response.AsyncContentListener> contentListeners)
|
||||
{
|
||||
if (contentListeners.isEmpty())
|
||||
{
|
||||
callback.succeeded();
|
||||
}
|
||||
else
|
||||
{
|
||||
CountingCallback counter = new CountingCallback(callback, contentListeners.size());
|
||||
Retainable retainable = callback instanceof Retainable ? (Retainable)callback : null;
|
||||
for (Response.AsyncContentListener listener : contentListeners)
|
||||
{
|
||||
ByteBuffer slice = buffer.slice();
|
||||
if (retainable != null)
|
||||
retainable.retain();
|
||||
listener.onContent(response, slice, counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyContent(Response.AsyncContentListener listener, Response response, ByteBuffer buffer, Callback callback)
|
||||
|
|
|
@ -102,8 +102,8 @@ public class HttpChannelOverHTTP extends HttpChannel
|
|||
if ((response.getVersion() == HttpVersion.HTTP_1_1) &&
|
||||
(response.getStatus() == HttpStatus.SWITCHING_PROTOCOLS_101))
|
||||
{
|
||||
String connection = response.getHeaders().get(HttpHeader.CONNECTION);
|
||||
if ((connection == null) || !connection.toLowerCase(Locale.US).contains("upgrade"))
|
||||
String next_connection = response.getHeaders().get(HttpHeader.CONNECTION);
|
||||
if ((next_connection == null) || !next_connection.toLowerCase(Locale.US).contains("upgrade"))
|
||||
{
|
||||
return new Result(result,new HttpResponseException("101 Switching Protocols without Connection: Upgrade not supported",response));
|
||||
}
|
||||
|
|
|
@ -44,11 +44,13 @@ import org.eclipse.jetty.server.ServerConnector;
|
|||
import org.eclipse.jetty.util.IO;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
@Ignore
|
||||
public class ConnectionPoolTest
|
||||
{
|
||||
private Server server;
|
||||
|
|
|
@ -479,39 +479,41 @@ public class HttpClientTLSTest
|
|||
latch.countDown();
|
||||
});
|
||||
|
||||
Socket socket = server.accept();
|
||||
SSLSocket sslSocket = (SSLSocket)serverTLSFactory.getSslContext().getSocketFactory().createSocket(socket, null, socket.getPort(), true);
|
||||
sslSocket.setUseClientMode(false);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(sslSocket.getInputStream(), StandardCharsets.UTF_8));
|
||||
while (true)
|
||||
try (Socket socket = server.accept())
|
||||
{
|
||||
String line = reader.readLine();
|
||||
if (line == null || line.isEmpty())
|
||||
break;
|
||||
SSLSocket sslSocket = (SSLSocket)serverTLSFactory.getSslContext().getSocketFactory().createSocket(socket, null, socket.getPort(), true);
|
||||
sslSocket.setUseClientMode(false);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(sslSocket.getInputStream(), StandardCharsets.UTF_8));
|
||||
while (true)
|
||||
{
|
||||
String line = reader.readLine();
|
||||
if (line == null || line.isEmpty())
|
||||
break;
|
||||
}
|
||||
|
||||
// If the response is Content-Length delimited, allowing the
|
||||
// missing TLS Close Message is fine because the application
|
||||
// will see a EOFException anyway.
|
||||
// If the response is connection delimited, allowing the
|
||||
// missing TLS Close Message is bad because the application
|
||||
// will see a successful response with truncated content.
|
||||
|
||||
// Verify that by not allowing the missing
|
||||
// TLS Close Message we get a response failure.
|
||||
|
||||
byte[] half = new byte[8];
|
||||
String response = "HTTP/1.1 200 OK\r\n" +
|
||||
// "Content-Length: " + (half.length * 2) + "\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n";
|
||||
OutputStream output = sslSocket.getOutputStream();
|
||||
output.write(response.getBytes(StandardCharsets.UTF_8));
|
||||
output.write(half);
|
||||
output.flush();
|
||||
// Simulate a truncation attack by raw closing
|
||||
// the socket in the try-with-resources block end.
|
||||
}
|
||||
|
||||
// If the response is Content-Length delimited, allowing the
|
||||
// missing TLS Close Message is fine because the application
|
||||
// will see a EOFException anyway.
|
||||
// If the response is connection delimited, allowing the
|
||||
// missing TLS Close Message is bad because the application
|
||||
// will see a successful response with truncated content.
|
||||
|
||||
// Verify that by not allowing the missing
|
||||
// TLS Close Message we get a response failure.
|
||||
|
||||
byte[] half = new byte[8];
|
||||
String response = "HTTP/1.1 200 OK\r\n" +
|
||||
// "Content-Length: " + (half.length * 2) + "\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n";
|
||||
OutputStream output = sslSocket.getOutputStream();
|
||||
output.write(response.getBytes(StandardCharsets.UTF_8));
|
||||
output.write(half);
|
||||
output.flush();
|
||||
// Simulate a truncation attack by raw closing.
|
||||
socket.close();
|
||||
|
||||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,63 +98,66 @@ public class ServerConnectionCloseTest
|
|||
|
||||
private void testServerSendsConnectionClose(boolean shutdownOutput, boolean chunked, String content) throws Exception
|
||||
{
|
||||
ServerSocket server = new ServerSocket(0);
|
||||
int port = server.getLocalPort();
|
||||
|
||||
startClient();
|
||||
|
||||
Request request = client.newRequest("localhost", port).path("/ctx/path");
|
||||
FutureResponseListener listener = new FutureResponseListener(request);
|
||||
request.send(listener);
|
||||
|
||||
Socket socket = server.accept();
|
||||
|
||||
InputStream input = socket.getInputStream();
|
||||
consumeRequest(input);
|
||||
|
||||
OutputStream output = socket.getOutputStream();
|
||||
String serverResponse = "" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Connection: close\r\n";
|
||||
if (chunked)
|
||||
try (ServerSocket server = new ServerSocket(0))
|
||||
{
|
||||
serverResponse += "" +
|
||||
"Transfer-Encoding: chunked\r\n" +
|
||||
"\r\n";
|
||||
int port = server.getLocalPort();
|
||||
|
||||
startClient();
|
||||
|
||||
Request request = client.newRequest("localhost", port).path("/ctx/path");
|
||||
FutureResponseListener listener = new FutureResponseListener(request);
|
||||
request.send(listener);
|
||||
|
||||
try (Socket socket = server.accept())
|
||||
{
|
||||
InputStream input = socket.getInputStream();
|
||||
consumeRequest(input);
|
||||
|
||||
OutputStream output = socket.getOutputStream();
|
||||
String serverResponse = "" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Connection: close\r\n";
|
||||
if (chunked)
|
||||
{
|
||||
serverResponse += "" +
|
||||
"Transfer-Encoding: chunked\r\n" +
|
||||
"\r\n";
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
serverResponse +=
|
||||
Integer.toHexString(content.length()) + "\r\n" +
|
||||
content + "\r\n";
|
||||
content + "\r\n";
|
||||
}
|
||||
serverResponse += "" +
|
||||
"0\r\n" +
|
||||
"\r\n";
|
||||
serverResponse += "" +
|
||||
"0\r\n" +
|
||||
"\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
serverResponse += "Content-Length: " + content.length() + "\r\n";
|
||||
serverResponse += "\r\n";
|
||||
serverResponse += content;
|
||||
}
|
||||
|
||||
output.write(serverResponse.getBytes("UTF-8"));
|
||||
output.flush();
|
||||
if (shutdownOutput)
|
||||
socket.shutdownOutput();
|
||||
|
||||
ContentResponse response = listener.get(5, TimeUnit.SECONDS);
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
|
||||
// Give some time to process the connection.
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Connection should have been removed from pool.
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination("http", "localhost", port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
Assert.assertEquals(0, connectionPool.getConnectionCount());
|
||||
Assert.assertEquals(0, connectionPool.getIdleConnectionCount());
|
||||
Assert.assertEquals(0, connectionPool.getActiveConnectionCount());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
serverResponse += "Content-Length: " + content.length() + "\r\n";
|
||||
serverResponse += "\r\n";
|
||||
serverResponse += content;
|
||||
}
|
||||
|
||||
output.write(serverResponse.getBytes("UTF-8"));
|
||||
output.flush();
|
||||
if (shutdownOutput)
|
||||
socket.shutdownOutput();
|
||||
|
||||
ContentResponse response = listener.get(5, TimeUnit.SECONDS);
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
|
||||
// Give some time to process the connection.
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Connection should have been removed from pool.
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination("http", "localhost", port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
Assert.assertEquals(0, connectionPool.getConnectionCount());
|
||||
Assert.assertEquals(0, connectionPool.getIdleConnectionCount());
|
||||
Assert.assertEquals(0, connectionPool.getActiveConnectionCount());
|
||||
}
|
||||
|
||||
private boolean consumeRequest(InputStream input) throws IOException
|
||||
|
|
|
@ -79,41 +79,40 @@ public class Socks4ProxyTest
|
|||
latch.countDown();
|
||||
});
|
||||
|
||||
SocketChannel channel = server.accept();
|
||||
try (SocketChannel channel = server.accept())
|
||||
{
|
||||
int socks4MessageLength = 9;
|
||||
ByteBuffer buffer = ByteBuffer.allocate(socks4MessageLength);
|
||||
int read = channel.read(buffer);
|
||||
Assert.assertEquals(socks4MessageLength, read);
|
||||
Assert.assertEquals(4, buffer.get(0) & 0xFF);
|
||||
Assert.assertEquals(1, buffer.get(1) & 0xFF);
|
||||
Assert.assertEquals(serverPort, buffer.getShort(2) & 0xFFFF);
|
||||
Assert.assertEquals(ip1, buffer.get(4) & 0xFF);
|
||||
Assert.assertEquals(ip2, buffer.get(5) & 0xFF);
|
||||
Assert.assertEquals(ip3, buffer.get(6) & 0xFF);
|
||||
Assert.assertEquals(ip4, buffer.get(7) & 0xFF);
|
||||
Assert.assertEquals(0, buffer.get(8) & 0xFF);
|
||||
|
||||
int socks4MessageLength = 9;
|
||||
ByteBuffer buffer = ByteBuffer.allocate(socks4MessageLength);
|
||||
int read = channel.read(buffer);
|
||||
Assert.assertEquals(socks4MessageLength, read);
|
||||
Assert.assertEquals(4, buffer.get(0) & 0xFF);
|
||||
Assert.assertEquals(1, buffer.get(1) & 0xFF);
|
||||
Assert.assertEquals(serverPort, buffer.getShort(2) & 0xFFFF);
|
||||
Assert.assertEquals(ip1, buffer.get(4) & 0xFF);
|
||||
Assert.assertEquals(ip2, buffer.get(5) & 0xFF);
|
||||
Assert.assertEquals(ip3, buffer.get(6) & 0xFF);
|
||||
Assert.assertEquals(ip4, buffer.get(7) & 0xFF);
|
||||
Assert.assertEquals(0, buffer.get(8) & 0xFF);
|
||||
// Socks4 response.
|
||||
channel.write(ByteBuffer.wrap(new byte[]{0, 0x5A, 0, 0, 0, 0, 0, 0}));
|
||||
|
||||
// Socks4 response.
|
||||
channel.write(ByteBuffer.wrap(new byte[]{0, 0x5A, 0, 0, 0, 0, 0, 0}));
|
||||
buffer = ByteBuffer.allocate(method.length() + 1 + path.length());
|
||||
read = channel.read(buffer);
|
||||
Assert.assertEquals(buffer.capacity(), read);
|
||||
buffer.flip();
|
||||
Assert.assertEquals(method + " " + path, StandardCharsets.UTF_8.decode(buffer).toString());
|
||||
|
||||
buffer = ByteBuffer.allocate(method.length() + 1 + path.length());
|
||||
read = channel.read(buffer);
|
||||
Assert.assertEquals(buffer.capacity(), read);
|
||||
buffer.flip();
|
||||
Assert.assertEquals(method + " " + path, StandardCharsets.UTF_8.decode(buffer).toString());
|
||||
// Response
|
||||
String response = "" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Length: 0\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n";
|
||||
channel.write(ByteBuffer.wrap(response.getBytes("UTF-8")));
|
||||
|
||||
// Response
|
||||
String response = "" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Length: 0\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n";
|
||||
channel.write(ByteBuffer.wrap(response.getBytes("UTF-8")));
|
||||
|
||||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
channel.close();
|
||||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -139,39 +138,38 @@ public class Socks4ProxyTest
|
|||
result.getFailure().printStackTrace();
|
||||
});
|
||||
|
||||
SocketChannel channel = server.accept();
|
||||
try (SocketChannel channel = server.accept())
|
||||
{
|
||||
int socks4MessageLength = 9;
|
||||
ByteBuffer buffer = ByteBuffer.allocate(socks4MessageLength);
|
||||
int read = channel.read(buffer);
|
||||
Assert.assertEquals(socks4MessageLength, read);
|
||||
|
||||
int socks4MessageLength = 9;
|
||||
ByteBuffer buffer = ByteBuffer.allocate(socks4MessageLength);
|
||||
int read = channel.read(buffer);
|
||||
Assert.assertEquals(socks4MessageLength, read);
|
||||
// Socks4 response, with split bytes.
|
||||
byte[] chunk1 = new byte[]{0, 0x5A, 0};
|
||||
byte[] chunk2 = new byte[]{0, 0, 0, 0, 0};
|
||||
channel.write(ByteBuffer.wrap(chunk1));
|
||||
|
||||
// Socks4 response, with split bytes.
|
||||
byte[] chunk1 = new byte[]{0, 0x5A, 0};
|
||||
byte[] chunk2 = new byte[]{0, 0, 0, 0, 0};
|
||||
channel.write(ByteBuffer.wrap(chunk1));
|
||||
// Wait before sending the second chunk.
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Wait before sending the second chunk.
|
||||
Thread.sleep(1000);
|
||||
channel.write(ByteBuffer.wrap(chunk2));
|
||||
|
||||
channel.write(ByteBuffer.wrap(chunk2));
|
||||
buffer = ByteBuffer.allocate(method.length());
|
||||
read = channel.read(buffer);
|
||||
Assert.assertEquals(buffer.capacity(), read);
|
||||
buffer.flip();
|
||||
Assert.assertEquals(method, StandardCharsets.UTF_8.decode(buffer).toString());
|
||||
|
||||
buffer = ByteBuffer.allocate(method.length());
|
||||
read = channel.read(buffer);
|
||||
Assert.assertEquals(buffer.capacity(), read);
|
||||
buffer.flip();
|
||||
Assert.assertEquals(method, StandardCharsets.UTF_8.decode(buffer).toString());
|
||||
// Response
|
||||
String response = "" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Length: 0\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n";
|
||||
channel.write(ByteBuffer.wrap(response.getBytes("UTF-8")));
|
||||
|
||||
// Response
|
||||
String response = "" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Length: 0\r\n" +
|
||||
"Connection: close\r\n" +
|
||||
"\r\n";
|
||||
channel.write(ByteBuffer.wrap(response.getBytes("UTF-8")));
|
||||
|
||||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
channel.close();
|
||||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,87 +104,91 @@ public class TLSServerConnectionCloseTest
|
|||
|
||||
private void testServerSendsConnectionClose(boolean chunked, String content) throws Exception
|
||||
{
|
||||
ServerSocket server = new ServerSocket(0);
|
||||
int port = server.getLocalPort();
|
||||
|
||||
startClient();
|
||||
|
||||
Request request = client.newRequest("localhost", port).scheme("https").path("/ctx/path");
|
||||
FutureResponseListener listener = new FutureResponseListener(request);
|
||||
request.send(listener);
|
||||
|
||||
Socket socket = server.accept();
|
||||
SSLContext sslContext = client.getSslContextFactory().getSslContext();
|
||||
SSLSocket sslSocket = (SSLSocket)sslContext.getSocketFactory().createSocket(socket, "localhost", port, false);
|
||||
sslSocket.setUseClientMode(false);
|
||||
sslSocket.startHandshake();
|
||||
|
||||
InputStream input = sslSocket.getInputStream();
|
||||
consumeRequest(input);
|
||||
|
||||
OutputStream output = sslSocket.getOutputStream();
|
||||
String serverResponse = "" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Connection: close\r\n";
|
||||
if (chunked)
|
||||
try (ServerSocket server = new ServerSocket(0))
|
||||
{
|
||||
serverResponse += "" +
|
||||
"Transfer-Encoding: chunked\r\n" +
|
||||
"\r\n";
|
||||
int port = server.getLocalPort();
|
||||
|
||||
startClient();
|
||||
|
||||
Request request = client.newRequest("localhost", port).scheme("https").path("/ctx/path");
|
||||
FutureResponseListener listener = new FutureResponseListener(request);
|
||||
request.send(listener);
|
||||
|
||||
try (Socket socket = server.accept())
|
||||
{
|
||||
SSLContext sslContext = client.getSslContextFactory().getSslContext();
|
||||
SSLSocket sslSocket = (SSLSocket)sslContext.getSocketFactory().createSocket(socket, "localhost", port, false);
|
||||
sslSocket.setUseClientMode(false);
|
||||
sslSocket.startHandshake();
|
||||
|
||||
InputStream input = sslSocket.getInputStream();
|
||||
consumeRequest(input);
|
||||
|
||||
OutputStream output = sslSocket.getOutputStream();
|
||||
String serverResponse = "" +
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Connection: close\r\n";
|
||||
if (chunked)
|
||||
{
|
||||
serverResponse += "" +
|
||||
"Transfer-Encoding: chunked\r\n" +
|
||||
"\r\n";
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
serverResponse +=
|
||||
Integer.toHexString(content.length()) + "\r\n" +
|
||||
content + "\r\n";
|
||||
content + "\r\n";
|
||||
}
|
||||
serverResponse += "" +
|
||||
"0\r\n" +
|
||||
"\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
serverResponse += "Content-Length: " + content.length() + "\r\n";
|
||||
serverResponse += "\r\n";
|
||||
serverResponse += content;
|
||||
}
|
||||
serverResponse += "" +
|
||||
"0\r\n" +
|
||||
"\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
serverResponse += "Content-Length: " + content.length() + "\r\n";
|
||||
serverResponse += "\r\n";
|
||||
serverResponse += content;
|
||||
}
|
||||
|
||||
output.write(serverResponse.getBytes("UTF-8"));
|
||||
output.flush();
|
||||
output.write(serverResponse.getBytes("UTF-8"));
|
||||
output.flush();
|
||||
|
||||
switch (closeMode)
|
||||
{
|
||||
case NONE:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case CLOSE:
|
||||
{
|
||||
sslSocket.close();
|
||||
break;
|
||||
}
|
||||
case ABRUPT:
|
||||
{
|
||||
socket.shutdownOutput();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
switch (closeMode)
|
||||
{
|
||||
case NONE:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case CLOSE:
|
||||
{
|
||||
sslSocket.close();
|
||||
break;
|
||||
}
|
||||
case ABRUPT:
|
||||
{
|
||||
socket.shutdownOutput();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
ContentResponse response = listener.get(5, TimeUnit.SECONDS);
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
|
||||
// Give some time to process the connection.
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Connection should have been removed from pool.
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination("http", "localhost", port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
Assert.assertEquals(0, connectionPool.getConnectionCount());
|
||||
Assert.assertEquals(0, connectionPool.getIdleConnectionCount());
|
||||
Assert.assertEquals(0, connectionPool.getActiveConnectionCount());
|
||||
}
|
||||
}
|
||||
|
||||
ContentResponse response = listener.get(5, TimeUnit.SECONDS);
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
|
||||
// Give some time to process the connection.
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Connection should have been removed from pool.
|
||||
HttpDestinationOverHTTP destination = (HttpDestinationOverHTTP)client.getDestination("http", "localhost", port);
|
||||
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
|
||||
Assert.assertEquals(0, connectionPool.getConnectionCount());
|
||||
Assert.assertEquals(0, connectionPool.getIdleConnectionCount());
|
||||
Assert.assertEquals(0, connectionPool.getActiveConnectionCount());
|
||||
}
|
||||
|
||||
private boolean consumeRequest(InputStream input) throws IOException
|
||||
|
|
|
@ -101,72 +101,72 @@ public class SslBytesClientTest extends SslBytesTest
|
|||
|
||||
Assert.assertTrue(proxy.awaitClient(5, TimeUnit.SECONDS));
|
||||
|
||||
final SSLSocket server = (SSLSocket)acceptor.accept();
|
||||
server.setUseClientMode(false);
|
||||
|
||||
Future<Object> handshake = threadPool.submit(() ->
|
||||
try (SSLSocket server = (SSLSocket)acceptor.accept())
|
||||
{
|
||||
server.startHandshake();
|
||||
return null;
|
||||
});
|
||||
server.setUseClientMode(false);
|
||||
|
||||
// Client Hello
|
||||
TLSRecord record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
Future<Object> handshake = threadPool.submit(() ->
|
||||
{
|
||||
server.startHandshake();
|
||||
return null;
|
||||
});
|
||||
|
||||
// Server Hello + Certificate + Server Done
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
// Client Hello
|
||||
TLSRecord record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Client Key Exchange
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
// Server Hello + Certificate + Server Done
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Change Cipher Spec
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
// Client Key Exchange
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Client Done
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
// Change Cipher Spec
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Change Cipher Spec
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
// Client Done
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Server Done
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
// Change Cipher Spec
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
Assert.assertNull(handshake.get(5, TimeUnit.SECONDS));
|
||||
// Server Done
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
|
||||
// Read request
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(server.getInputStream(), StandardCharsets.UTF_8));
|
||||
String line = reader.readLine();
|
||||
Assert.assertTrue(line.startsWith("GET"));
|
||||
while (line.length() > 0)
|
||||
line = reader.readLine();
|
||||
Assert.assertNull(handshake.get(5, TimeUnit.SECONDS));
|
||||
|
||||
// Write response
|
||||
OutputStream output = server.getOutputStream();
|
||||
output.write(("HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Length: 0\r\n" +
|
||||
"\r\n").getBytes(StandardCharsets.UTF_8));
|
||||
output.flush();
|
||||
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
|
||||
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
|
||||
// Read request
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(server.getInputStream(), StandardCharsets.UTF_8));
|
||||
String line = reader.readLine();
|
||||
Assert.assertTrue(line.startsWith("GET"));
|
||||
while (line.length() > 0)
|
||||
line = reader.readLine();
|
||||
|
||||
ContentResponse response = listener.get(5, TimeUnit.SECONDS);
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
// Write response
|
||||
OutputStream output = server.getOutputStream();
|
||||
output.write(("HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Length: 0\r\n" +
|
||||
"\r\n").getBytes(StandardCharsets.UTF_8));
|
||||
output.flush();
|
||||
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
|
||||
|
||||
server.close();
|
||||
ContentResponse response = listener.get(5, TimeUnit.SECONDS);
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -178,109 +178,109 @@ public class SslBytesClientTest extends SslBytesTest
|
|||
|
||||
Assert.assertTrue(proxy.awaitClient(5, TimeUnit.SECONDS));
|
||||
|
||||
final SSLSocket server = (SSLSocket)acceptor.accept();
|
||||
server.setUseClientMode(false);
|
||||
|
||||
Future<Object> handshake = threadPool.submit(() ->
|
||||
try (SSLSocket server = (SSLSocket)acceptor.accept())
|
||||
{
|
||||
server.startHandshake();
|
||||
return null;
|
||||
});
|
||||
server.setUseClientMode(false);
|
||||
|
||||
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
|
||||
Assert.assertNull(handshake.get(5, TimeUnit.SECONDS));
|
||||
Future<Object> handshake = threadPool.submit(() ->
|
||||
{
|
||||
server.startHandshake();
|
||||
return null;
|
||||
});
|
||||
|
||||
// Read request
|
||||
InputStream serverInput = server.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(serverInput, StandardCharsets.UTF_8));
|
||||
String line = reader.readLine();
|
||||
Assert.assertTrue(line.startsWith("GET"));
|
||||
while (line.length() > 0)
|
||||
line = reader.readLine();
|
||||
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
|
||||
Assert.assertNull(handshake.get(5, TimeUnit.SECONDS));
|
||||
|
||||
OutputStream serverOutput = server.getOutputStream();
|
||||
byte[] data1 = new byte[1024];
|
||||
Arrays.fill(data1, (byte)'X');
|
||||
String content1 = new String(data1, StandardCharsets.UTF_8);
|
||||
byte[] data2 = new byte[1024];
|
||||
Arrays.fill(data2, (byte)'Y');
|
||||
final String content2 = new String(data2, StandardCharsets.UTF_8);
|
||||
// Write first part of the response
|
||||
serverOutput.write(("HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Type: text/plain\r\n" +
|
||||
"Content-Length: " + (content1.length() + content2.length()) + "\r\n" +
|
||||
"\r\n" +
|
||||
content1).getBytes(StandardCharsets.UTF_8));
|
||||
serverOutput.flush();
|
||||
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
|
||||
// Read request
|
||||
InputStream serverInput = server.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(serverInput, StandardCharsets.UTF_8));
|
||||
String line = reader.readLine();
|
||||
Assert.assertTrue(line.startsWith("GET"));
|
||||
while (line.length() > 0)
|
||||
line = reader.readLine();
|
||||
|
||||
// Renegotiate
|
||||
Future<Object> renegotiation = threadPool.submit(() ->
|
||||
{
|
||||
server.startHandshake();
|
||||
return null;
|
||||
});
|
||||
OutputStream serverOutput = server.getOutputStream();
|
||||
byte[] data1 = new byte[1024];
|
||||
Arrays.fill(data1, (byte)'X');
|
||||
String content1 = new String(data1, StandardCharsets.UTF_8);
|
||||
byte[] data2 = new byte[1024];
|
||||
Arrays.fill(data2, (byte)'Y');
|
||||
final String content2 = new String(data2, StandardCharsets.UTF_8);
|
||||
// Write first part of the response
|
||||
serverOutput.write(("HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Type: text/plain\r\n" +
|
||||
"Content-Length: " + (content1.length() + content2.length()) + "\r\n" +
|
||||
"\r\n" +
|
||||
content1).getBytes(StandardCharsets.UTF_8));
|
||||
serverOutput.flush();
|
||||
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
|
||||
|
||||
// Renegotiation Handshake
|
||||
TLSRecord record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
// Renegotiate
|
||||
Future<Object> renegotiation = threadPool.submit(() ->
|
||||
{
|
||||
server.startHandshake();
|
||||
return null;
|
||||
});
|
||||
|
||||
// Renegotiation Handshake
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
// Renegotiation Handshake
|
||||
TLSRecord record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Trigger a read to have the server write the final renegotiation steps
|
||||
server.setSoTimeout(100);
|
||||
try
|
||||
{
|
||||
serverInput.read();
|
||||
Assert.fail();
|
||||
// Renegotiation Handshake
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Trigger a read to have the server write the final renegotiation steps
|
||||
server.setSoTimeout(100);
|
||||
try
|
||||
{
|
||||
serverInput.read();
|
||||
Assert.fail();
|
||||
}
|
||||
catch (SocketTimeoutException x)
|
||||
{
|
||||
// Expected
|
||||
}
|
||||
|
||||
// Renegotiation Handshake
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Renegotiation Change Cipher
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Renegotiation Handshake
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Renegotiation Change Cipher
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Renegotiation Handshake
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
|
||||
Assert.assertNull(renegotiation.get(5, TimeUnit.SECONDS));
|
||||
|
||||
// Complete the response
|
||||
automaticProxyFlow = proxy.startAutomaticFlow();
|
||||
serverOutput.write(data2);
|
||||
serverOutput.flush();
|
||||
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
|
||||
|
||||
ContentResponse response = listener.get(5, TimeUnit.SECONDS);
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
Assert.assertEquals(data1.length + data2.length, response.getContent().length);
|
||||
}
|
||||
catch (SocketTimeoutException x)
|
||||
{
|
||||
// Expected
|
||||
}
|
||||
|
||||
// Renegotiation Handshake
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Renegotiation Change Cipher
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Renegotiation Handshake
|
||||
record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
// Renegotiation Change Cipher
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.CHANGE_CIPHER_SPEC, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
|
||||
// Renegotiation Handshake
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToServer(record);
|
||||
|
||||
Assert.assertNull(renegotiation.get(5, TimeUnit.SECONDS));
|
||||
|
||||
// Complete the response
|
||||
automaticProxyFlow = proxy.startAutomaticFlow();
|
||||
serverOutput.write(data2);
|
||||
serverOutput.flush();
|
||||
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
|
||||
|
||||
ContentResponse response = listener.get(5, TimeUnit.SECONDS);
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
Assert.assertEquals(data1.length + data2.length, response.getContent().length);
|
||||
|
||||
server.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -294,60 +294,60 @@ public class SslBytesClientTest extends SslBytesTest
|
|||
|
||||
Assert.assertTrue(proxy.awaitClient(5, TimeUnit.SECONDS));
|
||||
|
||||
final SSLSocket server = (SSLSocket)acceptor.accept();
|
||||
server.setUseClientMode(false);
|
||||
|
||||
Future<Object> handshake = threadPool.submit(() ->
|
||||
try (SSLSocket server = (SSLSocket)acceptor.accept())
|
||||
{
|
||||
server.startHandshake();
|
||||
return null;
|
||||
});
|
||||
server.setUseClientMode(false);
|
||||
|
||||
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
|
||||
Assert.assertNull(handshake.get(5, TimeUnit.SECONDS));
|
||||
Future<Object> handshake = threadPool.submit(() ->
|
||||
{
|
||||
server.startHandshake();
|
||||
return null;
|
||||
});
|
||||
|
||||
// Read request
|
||||
InputStream serverInput = server.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(serverInput, StandardCharsets.UTF_8));
|
||||
String line = reader.readLine();
|
||||
Assert.assertTrue(line.startsWith("GET"));
|
||||
while (line.length() > 0)
|
||||
line = reader.readLine();
|
||||
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
|
||||
Assert.assertNull(handshake.get(5, TimeUnit.SECONDS));
|
||||
|
||||
OutputStream serverOutput = server.getOutputStream();
|
||||
byte[] data1 = new byte[1024];
|
||||
Arrays.fill(data1, (byte)'X');
|
||||
String content1 = new String(data1, StandardCharsets.UTF_8);
|
||||
byte[] data2 = new byte[1024];
|
||||
Arrays.fill(data2, (byte)'Y');
|
||||
final String content2 = new String(data2, StandardCharsets.UTF_8);
|
||||
// Write first part of the response
|
||||
serverOutput.write(("HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Type: text/plain\r\n" +
|
||||
"Content-Length: " + (content1.length() + content2.length()) + "\r\n" +
|
||||
"\r\n" +
|
||||
content1).getBytes(StandardCharsets.UTF_8));
|
||||
serverOutput.flush();
|
||||
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
|
||||
// Read request
|
||||
InputStream serverInput = server.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(serverInput, StandardCharsets.UTF_8));
|
||||
String line = reader.readLine();
|
||||
Assert.assertTrue(line.startsWith("GET"));
|
||||
while (line.length() > 0)
|
||||
line = reader.readLine();
|
||||
|
||||
// Renegotiate
|
||||
threadPool.submit(() ->
|
||||
{
|
||||
server.startHandshake();
|
||||
return null;
|
||||
});
|
||||
OutputStream serverOutput = server.getOutputStream();
|
||||
byte[] data1 = new byte[1024];
|
||||
Arrays.fill(data1, (byte)'X');
|
||||
String content1 = new String(data1, StandardCharsets.UTF_8);
|
||||
byte[] data2 = new byte[1024];
|
||||
Arrays.fill(data2, (byte)'Y');
|
||||
final String content2 = new String(data2, StandardCharsets.UTF_8);
|
||||
// Write first part of the response
|
||||
serverOutput.write(("HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Type: text/plain\r\n" +
|
||||
"Content-Length: " + (content1.length() + content2.length()) + "\r\n" +
|
||||
"\r\n" +
|
||||
content1).getBytes(StandardCharsets.UTF_8));
|
||||
serverOutput.flush();
|
||||
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
|
||||
|
||||
// Renegotiation Handshake
|
||||
TLSRecord record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
// Renegotiate
|
||||
threadPool.submit(() ->
|
||||
{
|
||||
server.startHandshake();
|
||||
return null;
|
||||
});
|
||||
|
||||
// Client sends close alert.
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertNull(record);
|
||||
// Renegotiation Handshake
|
||||
TLSRecord record = proxy.readFromServer();
|
||||
Assert.assertEquals(TLSRecord.Type.HANDSHAKE, record.getType());
|
||||
proxy.flushToClient(record);
|
||||
|
||||
server.close();
|
||||
// Client sends close alert.
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
|
||||
record = proxy.readFromClient();
|
||||
Assert.assertNull(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
<JXURL>http://download.eclipse.org/jetty/stable-9/xref</JXURL>
|
||||
<SRCDIR>${basedir}/..</SRCDIR>
|
||||
<GITBROWSEURL>https://github.com/eclipse/jetty.project/tree/jetty-9.4.x</GITBROWSEURL>
|
||||
<MVNCENTRAL>http://central.maven.org/maven2</MVNCENTRAL>
|
||||
<MVNCENTRAL>https://repo1.maven.org/maven2</MVNCENTRAL>
|
||||
<VERSION>${project.version}</VERSION>
|
||||
</attributes>
|
||||
</configuration>
|
||||
|
|
|
@ -113,7 +113,7 @@ When using JDK 9 or later and Jetty embedded, the ALPN service implementation is
|
|||
To use ALPN in an OSGi environment, in addition to what described above, you will also need to deploy the `jetty-osgi-alpn` jar.
|
||||
This jar contains a `Fragment-Host` directive that ensures the ALPN classes will be available from the system bundle.
|
||||
|
||||
You can download the http://central.maven.org/maven2/org/eclipse/jetty/osgi/jetty-osgi-alpn/[jetty-osgi-alpn jar] from Maven Central.
|
||||
You can download the https://repo1.maven.org/maven2/org/eclipse/jetty/osgi/jetty-osgi-alpn/[jetty-osgi-alpn jar] from Maven Central.
|
||||
|
||||
____
|
||||
[NOTE]
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
==== Setting up the Classpath
|
||||
|
||||
You will need to place the following Jetty jar files onto the classpath of your application.
|
||||
You can obtain them from the https://www.eclipse.org/jetty/download.html[Jetty distribution], or the http://central.maven.org/maven2/org/eclipse/jetty/jetty-annotations[Maven repository]:
|
||||
You can obtain them from the https://www.eclipse.org/jetty/download.html[Jetty distribution], or the https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-annotations[Maven repository]:
|
||||
|
||||
....
|
||||
jetty-plus.jar
|
||||
|
|
|
@ -44,7 +44,7 @@ This is extremely useful in CometD web applications where it is now possible to
|
|||
You will need to put the `jetty-servlets.jar` file onto your classpath.
|
||||
If you are creating a webapp, ensure that this jar is included in your webapp's `WEB-INF/lib`.
|
||||
Or, if you are running Jetty embedded you will need to ensure that `jetty-servlets.jar` is on the execution classpath.
|
||||
You can download the `jetty-servlets.jar` from the Maven Central Repository at http://central.maven.org/maven2/org/eclipse/jetty/jetty-servlets/.
|
||||
You can download the `jetty-servlets.jar` from the Maven Central Repository at https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-servlets/.
|
||||
It is also available as part of the Jetty distribution in the `$JETTY_HOME/lib` directory.
|
||||
|
||||
[[cross-origin-config]]
|
||||
|
|
|
@ -126,7 +126,7 @@ All configuration options for BoneCP are described here: http://jolbox.com/bonec
|
|||
[[c3p0-datasource]]
|
||||
===== c3p0
|
||||
|
||||
Connection pooling, available at http://central.maven.org/maven2/c3p0/c3p0/0.9.1.2/c3p0-0.9.1.2.jar[c3p0 Jar].
|
||||
Connection pooling, available at https://repo1.maven.org/maven2/c3p0/c3p0/0.9.1.2/c3p0-0.9.1.2.jar[c3p0 Jar].
|
||||
|
||||
[source, xml, subs="{sub-order}"]
|
||||
----
|
||||
|
@ -147,7 +147,7 @@ Connection pooling, available at http://central.maven.org/maven2/c3p0/c3p0/0.9.1
|
|||
[[dbcp-datasource]]
|
||||
===== DBCP
|
||||
|
||||
Connection pooling, available at http://central.maven.org/maven2/commons-dbcp/commons-dbcp/1.2/commons-dbcp-1.2.jar[dbcp Jar].
|
||||
Connection pooling, available at https://repo1.maven.org/maven2/commons-dbcp/commons-dbcp/1.2/commons-dbcp-1.2.jar[dbcp Jar].
|
||||
|
||||
[source, xml, subs="{sub-order}"]
|
||||
----
|
||||
|
|
|
@ -118,7 +118,7 @@ Proceed (y/N)? y
|
|||
INFO : slf4j-api transitively enabled
|
||||
INFO : logging-slf4j initialized in ${jetty.base}/start.d/logging-slf4j.ini
|
||||
MKDIR : ${jetty.base}/lib/slf4j
|
||||
DOWNLD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
|
||||
INFO : Base directory was modified
|
||||
ERROR : Module logging-slf4j requires a module providing slf4j-impl from one of [slf4j-simple-impl, slf4j-logback, slf4j-jul, slf4j-log4j2, slf4j-log4j]
|
||||
|
||||
|
@ -137,7 +137,7 @@ To enable the simple SLF4J implementation, we will also need to activate the `sl
|
|||
[my-base]$ java -jar ../start.jar --add-to-start=slf4j-simple-impl
|
||||
INFO : slf4j-simple-impl initialized in ${jetty.base}/start.d/slf4j-simple-impl.ini
|
||||
INFO : resources transitively enabled
|
||||
DOWNLD: http://central.maven.org/maven2/org/slf4j/slf4j-simple/1.7.21/slf4j-simple-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-simple-1.7.21.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-simple/1.7.21/slf4j-simple-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-simple-1.7.21.jar
|
||||
MKDIR : ${jetty.base}/resources
|
||||
COPY : ${jetty.home}/modules/slf4j-simple-impl/resources/simplelogger.properties to ${jetty.base}/resources/simplelogger.properties
|
||||
INFO : Base directory was modified
|
||||
|
@ -207,12 +207,12 @@ INFO : resources transitively enabled
|
|||
INFO : slf4j-log4j transitively enabled
|
||||
INFO : logging-log4j initialized in ${jetty.base}/start.d/logging-log4j.ini
|
||||
MKDIR : ${jetty.base}/lib/slf4j
|
||||
DOWNLD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
|
||||
MKDIR : ${jetty.base}/lib/log4j
|
||||
COPY : /Users/admin/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar to ${jetty.base}/lib/log4j/log4j-1.2.17.jar
|
||||
MKDIR : ${jetty.base}/resources
|
||||
COPY : ${jetty.home}/modules/log4j-impl/resources/log4j.xml to ${jetty.base}/resources/log4j.xml
|
||||
DOWNLD: http://central.maven.org/maven2/org/slf4j/slf4j-log4j12/1.7.21/slf4j-log4j12-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-log4j12-1.7.21.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-log4j12/1.7.21/slf4j-log4j12-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-log4j12-1.7.21.jar
|
||||
INFO : Base directory was modified
|
||||
|
||||
[my-base]$ tree
|
||||
|
@ -277,12 +277,12 @@ INFO : resources transitively enabled
|
|||
INFO : slf4j-log4j2 transitively enabled
|
||||
INFO : log4j2-impl transitively enabled
|
||||
MKDIR : ${jetty.base}/lib/slf4j
|
||||
DOWNLD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
|
||||
MKDIR : ${jetty.base}/lib/log4j2
|
||||
DOWNLD: http://central.maven.org/maven2/org/apache/logging/log4j/log4j-api/2.6.1/log4j-api-2.6.1.jar to ${jetty.base}/lib/log4j2/log4j-api-2.6.1.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-api/2.6.1/log4j-api-2.6.1.jar to ${jetty.base}/lib/log4j2/log4j-api-2.6.1.jar
|
||||
MKDIR : ${jetty.base}/resources
|
||||
DOWNLD: http://central.maven.org/maven2/org/apache/logging/log4j/log4j-slf4j-impl/2.6.1/log4j-slf4j-impl-2.6.1.jar to ${jetty.base}/lib/log4j2/log4j-slf4j-impl-2.6.1.jar
|
||||
DOWNLD: http://central.maven.org/maven2/org/apache/logging/log4j/log4j-core/2.6.1/log4j-core-2.6.1.jar to ${jetty.base}/lib/log4j2/log4j-core-2.6.1.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-slf4j-impl/2.6.1/log4j-slf4j-impl-2.6.1.jar to ${jetty.base}/lib/log4j2/log4j-slf4j-impl-2.6.1.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-core/2.6.1/log4j-core-2.6.1.jar to ${jetty.base}/lib/log4j2/log4j-core-2.6.1.jar
|
||||
COPY : ${jetty.home}/modules/log4j2-impl/resources/log4j2.xml to ${jetty.base}/resources/log4j2.xml
|
||||
INFO : Base directory was modified
|
||||
|
||||
|
@ -362,12 +362,12 @@ INFO : slf4j-logback transitively enabled
|
|||
INFO : logging-logback initialized in ${jetty.base}/start.d/logging-logback.ini
|
||||
INFO : resources transitively enabled
|
||||
MKDIR : ${jetty.base}/lib/slf4j
|
||||
DOWNLD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
|
||||
MKDIR : ${jetty.base}/lib/logback
|
||||
DOWNLD: http://central.maven.org/maven2/ch/qos/logback/logback-core/1.1.7/logback-core-1.1.7.jar to ${jetty.base}/lib/logback/logback-core-1.1.7.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.1.7/logback-core-1.1.7.jar to ${jetty.base}/lib/logback/logback-core-1.1.7.jar
|
||||
MKDIR : ${jetty.base}/resources
|
||||
COPY : ${jetty.home}/modules/logback-impl/resources/logback.xml to ${jetty.base}/resources/logback.xml
|
||||
DOWNLD: http://central.maven.org/maven2/ch/qos/logback/logback-classic/1.1.7/logback-classic-1.1.7.jar to ${jetty.base}/lib/logback/logback-classic-1.1.7.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.1.7/logback-classic-1.1.7.jar to ${jetty.base}/lib/logback/logback-classic-1.1.7.jar
|
||||
INFO : Base directory was modified
|
||||
|
||||
[my-base]$ tree
|
||||
|
@ -434,8 +434,8 @@ INFO : resources transitively enabled
|
|||
MKDIR : ${jetty.base}/etc
|
||||
COPY : ${jetty.home}/modules/jul-impl/etc/java-util-logging.properties to ${jetty.base}/etc/java-util-logging.properties
|
||||
MKDIR : ${jetty.base}/lib/slf4j
|
||||
DOWNLD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
|
||||
DOWNLD: http://central.maven.org/maven2/org/slf4j/slf4j-jdk14/1.7.21/slf4j-jdk14-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-jdk14-1.7.21.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-jdk14/1.7.21/slf4j-jdk14-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-jdk14-1.7.21.jar
|
||||
INFO : Base directory was modified
|
||||
|
||||
[my-base]$ tree
|
||||
|
|
|
@ -37,9 +37,9 @@ A convenient replacement `logging` module has been created to bootstrap your `${
|
|||
[mybase]$ java -jar /opt/jetty-dist/start.jar --add-to-start=logging
|
||||
INFO: logging initialised in ${jetty.base}/start.ini (appended)
|
||||
MKDIR: ${jetty.base}/logs
|
||||
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar
|
||||
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-log4j12/1.6.6/slf4j-log4j12-1.6.6.jar to lib/logging/slf4j-log4j12-1.6.6.jar
|
||||
DOWNLOAD: http://central.maven.org/maven2/log4j/log4j/1.2.17/log4j-1.2.17.jar to lib/logging/log4j-1.2.17.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/slf4j-log4j12/1.6.6/slf4j-log4j12-1.6.6.jar to lib/logging/slf4j-log4j12-1.6.6.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/log4j/log4j/1.2.17/log4j-1.2.17.jar to lib/logging/log4j-1.2.17.jar
|
||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/log4j-1.2/log4j.properties to resources/log4j.properties
|
||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/log4j-1.2/jetty-logging.properties to resources/jetty-logging.properties
|
||||
INFO: resources initialised transitively
|
||||
|
|
|
@ -39,8 +39,8 @@ A convenient replacement `logging` module has been created to bootstrap your `${
|
|||
[mybase]$ java -jar /opt/jetty-dist/start.jar --add-to-start=logging
|
||||
INFO: logging initialised in ${jetty.base}/start.ini (appended)
|
||||
MKDIR: ${jetty.base}/logs
|
||||
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-jdk14/1.6.6/slf4j-jdk14-1.6.6.jar to lib/logging/slf4j-jdk14-1.6.6.jar
|
||||
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/slf4j-jdk14/1.6.6/slf4j-jdk14-1.6.6.jar to lib/logging/slf4j-jdk14-1.6.6.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar
|
||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/java.util.logging-slf4j/jetty-logging.xml to etc/jetty-logging.xml
|
||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/java.util.logging-slf4j/logging.properties to resources/logging.properties
|
||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/java.util.logging-slf4j/jetty-logging.properties to resources/jetty-logging.properties
|
||||
|
|
|
@ -56,19 +56,19 @@ A convenient replacement `logging` module has been created to bootstrap your `${
|
|||
[mybase]$ java -jar /opt/jetty-dist/start.jar --add-to-start=logging,webapp-logging
|
||||
INFO: logging initialised in ${jetty.base}/start.ini (appended)
|
||||
MKDIR: ${jetty.base}/logs
|
||||
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar
|
||||
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/log4j-over-slf4j/1.6.6/log4j-over-slf4j-1.6.6.jar to lib/logging/log4j-over-slf4j-1.6.6.jar
|
||||
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/jul-to-slf4j/1.6.6/jul-to-slf4j-1.6.6.jar to lib/logging/jul-to-slf4j-1.6.6.jar
|
||||
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.6.6/jcl-over-slf4j-1.6.6.jar to lib/logging/jcl-over-slf4j-1.6.6.jar
|
||||
DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-core/1.0.7/logback-core-1.0.7.jar to lib/logging/logback-core-1.0.7.jar
|
||||
DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-classic/1.0.7/logback-classic-1.0.7.jar to lib/logging/logback-classic-1.0.7.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/log4j-over-slf4j/1.6.6/log4j-over-slf4j-1.6.6.jar to lib/logging/log4j-over-slf4j-1.6.6.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/jul-to-slf4j/1.6.6/jul-to-slf4j-1.6.6.jar to lib/logging/jul-to-slf4j-1.6.6.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.6.6/jcl-over-slf4j-1.6.6.jar to lib/logging/jcl-over-slf4j-1.6.6.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.0.7/logback-core-1.0.7.jar to lib/logging/logback-core-1.0.7.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.0.7/logback-classic-1.0.7.jar to lib/logging/logback-classic-1.0.7.jar
|
||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/logback.xml to resources/logback.xml
|
||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/jetty-logging.properties to resources/jetty-logging.properties
|
||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/jetty-logging.xml to etc/jetty-logging.xml
|
||||
INFO: resources initialised transitively
|
||||
INFO: resources enabled in ${jetty.base}/start.ini
|
||||
INFO: webapp-logging initialised in ${jetty.base}/start.ini (appended)
|
||||
DOWNLOAD: http://central.maven.org/maven2/org/eclipse/jetty/jetty-webapp-logging/9.0.0/jetty-webapp-logging-9.0.0.jar to lib/webapp-logging/jetty-webapp-logging-9.0.0.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-webapp-logging/9.0.0/jetty-webapp-logging-9.0.0.jar to lib/webapp-logging/jetty-webapp-logging-9.0.0.jar
|
||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/jetty-webapp-logging/master/src/main/config/etc/jetty-webapp-logging.xml to etc/jetty-webapp-logging.xml
|
||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/jetty-webapp-logging/master/src/main/config/etc/jetty-mdc-handler.xml to etc/jetty-mdc-handler.xml
|
||||
INFO: deploy initialised transitively
|
||||
|
|
|
@ -37,9 +37,9 @@ A convenient replacement `logging` module has been created to bootstrap the `${j
|
|||
[mybase]$ java -jar /opt/jetty-dist/start.jar --add-to-start=logging
|
||||
INFO: logging initialised in ${jetty.base}/start.ini (appended)
|
||||
MKDIR: ${jetty.base}/logs
|
||||
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar
|
||||
DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-core/1.0.7/logback-core-1.0.7.jar to lib/logging/logback-core-1.0.7.jar
|
||||
DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-classic/1.0.7/logback-classic-1.0.7.jar to lib/logging/logback-classic-1.0.7.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.0.7/logback-core-1.0.7.jar to lib/logging/logback-core-1.0.7.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.0.7/logback-classic-1.0.7.jar to lib/logging/logback-classic-1.0.7.jar
|
||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/logback/logback.xml to resources/logback.xml
|
||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/logback/jetty-logging.properties to resources/jetty-logging.properties
|
||||
|
||||
|
|
|
@ -102,12 +102,12 @@ A convenient replacement `logging` module has been created to bootstrap the `${j
|
|||
[mybase]$ java -jar /opt/jetty-dist/start.jar --add-to-start=logging
|
||||
INFO: logging initialised in ${jetty.base}/start.ini (appended)
|
||||
MKDIR: ${jetty.base}/logs
|
||||
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar
|
||||
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/log4j-over-slf4j/1.6.6/log4j-over-slf4j-1.6.6.jar to lib/logging/log4j-over-slf4j-1.6.6.jar
|
||||
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/jul-to-slf4j/1.6.6/jul-to-slf4j-1.6.6.jar to lib/logging/jul-to-slf4j-1.6.6.jar
|
||||
DOWNLOAD: http://central.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.6.6/jcl-over-slf4j-1.6.6.jar to lib/logging/jcl-over-slf4j-1.6.6.jar
|
||||
DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-core/1.0.7/logback-core-1.0.7.jar to lib/logging/logback-core-1.0.7.jar
|
||||
DOWNLOAD: http://central.maven.org/maven2/ch/qos/logback/logback-classic/1.0.7/logback-classic-1.0.7.jar to lib/logging/logback-classic-1.0.7.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.6.6/slf4j-api-1.6.6.jar to lib/logging/slf4j-api-1.6.6.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/log4j-over-slf4j/1.6.6/log4j-over-slf4j-1.6.6.jar to lib/logging/log4j-over-slf4j-1.6.6.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/jul-to-slf4j/1.6.6/jul-to-slf4j-1.6.6.jar to lib/logging/jul-to-slf4j-1.6.6.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.6.6/jcl-over-slf4j-1.6.6.jar to lib/logging/jcl-over-slf4j-1.6.6.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/ch/qos/logback/logback-core/1.0.7/logback-core-1.0.7.jar to lib/logging/logback-core-1.0.7.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/ch/qos/logback/logback-classic/1.0.7/logback-classic-1.0.7.jar to lib/logging/logback-classic-1.0.7.jar
|
||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/logback.xml to resources/logback.xml
|
||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/jetty-logging.properties to resources/jetty-logging.properties
|
||||
DOWNLOAD: https://raw.githubusercontent.com/jetty-project/logging-modules/master/capture-all/jetty-logging.xml to etc/jetty-logging.xml
|
||||
|
|
|
@ -27,7 +27,7 @@ Of course, if your webapp is not as straightforward, the `jetty-runner` has comm
|
|||
|
||||
You will need the `jetty-runner` jar:
|
||||
|
||||
1. Download the `jetty-runner` jar available at http://central.maven.org/maven2/org/eclipse/jetty/jetty-runner/[Maven Central].
|
||||
1. Download the `jetty-runner` jar available at https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-runner/[Maven Central].
|
||||
|
||||
==== Deploying a Simple Context
|
||||
|
||||
|
|
|
@ -123,23 +123,23 @@ INFO : jndi transitively enabled
|
|||
MKDIR : ${jetty.base}/etc
|
||||
COPY : ${jetty.home}/modules/jul-impl/etc/java-util-logging.properties to ${jetty.base}/etc/java-util-logging.properties
|
||||
MKDIR : ${jetty.base}/lib/slf4j
|
||||
DOWNLD: http://central.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-api-1.7.21.jar
|
||||
MKDIR : ${jetty.base}/lib/gcloud
|
||||
COPY : /Users/admin/.m2/repository/aopalliance/aopalliance/1.0/aopalliance-1.0.jar to ${jetty.base}/lib/gcloud/aopalliance-1.0.jar
|
||||
COPY : /Users/admin/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.1.3/jackson-core-2.1.3.jar to ${jetty.base}/lib/gcloud/jackson-core-2.1.3.jar
|
||||
COPY : /Users/admin/.m2/repository/com/google/api-client/google-api-client-appengine/1.21.0/google-api-client-appengine-1.21.0.jar to ${jetty.base}/lib/gcloud/google-api-client-appengine-1.21.0.jar
|
||||
COPY : /Users/admin/.m2/repository/com/google/api-client/google-api-client/1.20.0/google-api-client-1.20.0.jar to ${jetty.base}/lib/gcloud/google-api-client-1.20.0.jar
|
||||
COPY : /Users/admin/.m2/repository/com/google/api-client/google-api-client-servlet/1.21.0/google-api-client-servlet-1.21.0.jar to ${jetty.base}/lib/gcloud/google-api-client-servlet-1.21.0.jar
|
||||
DOWNLD: http://central.maven.org/maven2/com/google/api/gax/0.0.21/gax-0.0.21.jar to ${jetty.base}/lib/gcloud/gax-0.0.21.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/com/google/api/gax/0.0.21/gax-0.0.21.jar to ${jetty.base}/lib/gcloud/gax-0.0.21.jar
|
||||
COPY : /Users/admin/.m2/repository/com/google/api/grpc/grpc-google-common-protos/0.1.0/grpc-google-common-protos-0.1.0.jar to ${jetty.base}/lib/gcloud/grpc-google-common-protos-0.1.0.jar
|
||||
COPY : /Users/admin/.m2/repository/com/google/api/grpc/grpc-google-iam-v1/0.1.0/grpc-google-iam-v1-0.1.0.jar to ${jetty.base}/lib/gcloud/grpc-google-iam-v1-0.1.0.jar
|
||||
COPY : /Users/admin/.m2/repository/com/google/auth/google-auth-library-credentials/0.3.1/google-auth-library-credentials-0.3.1.jar to ${jetty.base}/lib/gcloud/google-auth-library-credentials-0.3.1.jar
|
||||
COPY : /Users/admin/.m2/repository/com/google/auth/google-auth-library-oauth2-http/0.3.1/google-auth-library-oauth2-http-0.3.1.jar to ${jetty.base}/lib/gcloud/google-auth-library-oauth2-http-0.3.1.jar
|
||||
DOWNLD: http://central.maven.org/maven2/com/google/auto/value/auto-value/1.2/auto-value-1.2.jar to ${jetty.base}/lib/gcloud/auto-value-1.2.jar
|
||||
DOWNLD: http://central.maven.org/maven2/com/google/cloud/datastore/datastore-v1-proto-client/1.3.0/datastore-v1-proto-client-1.3.0.jar to ${jetty.base}/lib/gcloud/datastore-v1-proto-client-1.3.0.jar
|
||||
DOWNLD: http://central.maven.org/maven2/com/google/cloud/datastore/datastore-v1-protos/1.3.0/datastore-v1-protos-1.3.0.jar to ${jetty.base}/lib/gcloud/datastore-v1-protos-1.3.0.jar
|
||||
DOWNLD: http://central.maven.org/maven2/com/google/cloud/google-cloud-core/0.5.1/google-cloud-core-0.5.1.jar to ${jetty.base}/lib/gcloud/google-cloud-core-0.5.0.jar
|
||||
DOWNLD: http://central.maven.org/maven2/com/google/cloud/google-cloud-datastore/0.5.1/google-cloud-datastore-0.5.1.jar to ${jetty.base}/lib/gcloud/google-cloud-datastore-0.5.1.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/com/google/auto/value/auto-value/1.2/auto-value-1.2.jar to ${jetty.base}/lib/gcloud/auto-value-1.2.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/com/google/cloud/datastore/datastore-v1-proto-client/1.3.0/datastore-v1-proto-client-1.3.0.jar to ${jetty.base}/lib/gcloud/datastore-v1-proto-client-1.3.0.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/com/google/cloud/datastore/datastore-v1-protos/1.3.0/datastore-v1-protos-1.3.0.jar to ${jetty.base}/lib/gcloud/datastore-v1-protos-1.3.0.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/com/google/cloud/google-cloud-core/0.5.1/google-cloud-core-0.5.1.jar to ${jetty.base}/lib/gcloud/google-cloud-core-0.5.0.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/com/google/cloud/google-cloud-datastore/0.5.1/google-cloud-datastore-0.5.1.jar to ${jetty.base}/lib/gcloud/google-cloud-datastore-0.5.1.jar
|
||||
COPY : /Users/admin/.m2/repository/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar to ${jetty.base}/lib/gcloud/jsr305-1.3.9.jar
|
||||
COPY : /Users/admin/.m2/repository/com/google/code/gson/gson/2.3/gson-2.3.jar to ${jetty.base}/lib/gcloud/gson-2.3.jar
|
||||
COPY : /Users/admin/.m2/repository/com/google/guava/guava/19.0/guava-19.0.jar to ${jetty.base}/lib/gcloud/guava-19.0.jar
|
||||
|
@ -168,7 +168,7 @@ COPY : /Users/admin/.m2/repository/org/apache/httpcomponents/httpclient/4.0.1/h
|
|||
COPY : /Users/admin/.m2/repository/org/apache/httpcomponents/httpcore/4.0.1/httpcore-4.0.1.jar to ${jetty.base}/lib/gcloud/httpcore-4.0.1.jar
|
||||
COPY : /Users/admin/.m2/repository/org/codehaus/jackson/jackson-core-asl/1.9.11/jackson-core-asl-1.9.11.jar to ${jetty.base}/lib/gcloud/jackson-core-asl-1.9.11.jar
|
||||
COPY : /Users/admin/.m2/repository/org/json/json/20151123/json-20151123.jar to ${jetty.base}/lib/gcloud/json-20151123.jar
|
||||
DOWNLD: http://central.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.7.21/jcl-over-slf4j-1.7.21.jar to ${jetty.base}/lib/slf4j/jcl-over-slf4j-1.7.21.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/jcl-over-slf4j/1.7.21/jcl-over-slf4j-1.7.21.jar to ${jetty.base}/lib/slf4j/jcl-over-slf4j-1.7.21.jar
|
||||
COPY : ${jetty.home}/modules/gcloud/index.yaml to ${jetty.base}/etc/index.yaml
|
||||
INFO : Base directory was modified
|
||||
ERROR : Module jcl-slf4j requires a module providing slf4j-impl from one of [slf4j-simple-impl, slf4j-logback, slf4j-jul, slf4j-log4j2, slf4j-log4j]
|
||||
|
@ -196,7 +196,7 @@ In this example, we will enable the `slf4j-simple-impl` module to provide a SLF4
|
|||
$ java -jar ../start.jar --add-to-start=slf4j-simple-impl
|
||||
INFO : slf4j-simple-impl initialized in ${jetty.base}/start.d/slf4j-simple-impl.ini
|
||||
INFO : resources transitively enabled
|
||||
DOWNLD: http://central.maven.org/maven2/org/slf4j/slf4j-simple/1.7.21/slf4j-simple-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-simple-1.7.21.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/slf4j/slf4j-simple/1.7.21/slf4j-simple-1.7.21.jar to ${jetty.base}/lib/slf4j/slf4j-simple-1.7.21.jar
|
||||
MKDIR : ${jetty.base}/resources
|
||||
COPY : ${jetty.home}/modules/slf4j-simple-impl/resources/simplelogger.properties to ${jetty.base}/resources/simplelogger.properties
|
||||
INFO : Base directory was modified
|
||||
|
|
|
@ -48,7 +48,7 @@ INFO : server transitively enabled, ini template available with --add-
|
|||
INFO : sessions transitively enabled, ini template available with --add-to-start=sessions
|
||||
INFO : session-store-hazelcast-remote initialized in ${jetty.base}/start.d/session-store-hazelcast-remote.ini
|
||||
MKDIR : /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2
|
||||
DOWNLD: http://central.maven.org/maven2/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar
|
||||
MKDIR : ${jetty.base}/lib/hazelcast
|
||||
COPY : /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-3.8.2.jar
|
||||
COPY : /Users/admin/mvn-repo/com/hazelcast/hazelcast-client/3.8.2/hazelcast-client-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-client-3.8.2.jar
|
||||
|
@ -136,7 +136,7 @@ INFO : server transitively enabled, ini template available with --add-
|
|||
INFO : sessions transitively enabled, ini template available with --add-to-start=sessions
|
||||
INFO : session-store-hazelcast-embedded initialized in ${jetty.base}/start.d/session-store-hazelcast-embedded.ini
|
||||
MKDIR : /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2
|
||||
DOWNLD: http://central.maven.org/maven2/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar
|
||||
MKDIR : ${jetty.base}/lib/hazelcast
|
||||
COPY : /Users/admin/mvn-repo/com/hazelcast/hazelcast/3.8.2/hazelcast-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-3.8.2.jar
|
||||
COPY : /Users/admin/mvn-repo/com/hazelcast/hazelcast-client/3.8.2/hazelcast-client-3.8.2.jar to ${jetty.base}/lib/hazelcast/hazelcast-client-3.8.2.jar
|
||||
|
|
|
@ -52,7 +52,7 @@ INFO : server transitively enabled, ini template available with --add-
|
|||
INFO : sessions transitively enabled, ini template available with --add-to-start=sessions
|
||||
INFO : session-store-infinispan-remote initialized in ${jetty.base}/start.d/session-store-infinispan-remote.ini
|
||||
MKDIR : ${jetty.base}/lib/infinispan
|
||||
DOWNLD: http://central.maven.org/maven2/org/infinispan/infinispan-remote/7.1.1.Final/infinispan-remote-7.1.1.Final.jar to ${jetty.base}/lib/infinispan/infinispan-remote-7.1.1.Final.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/infinispan/infinispan-remote/7.1.1.Final/infinispan-remote-7.1.1.Final.jar to ${jetty.base}/lib/infinispan/infinispan-remote-7.1.1.Final.jar
|
||||
MKDIR : ${jetty.base}/resources
|
||||
COPY : ${jetty.home}/modules/session-store-infinispan-remote/resources/hotrod-client.properties to ${jetty.base}/resources/hotrod-client.properties
|
||||
INFO : Base directory was modified
|
||||
|
@ -137,7 +137,7 @@ Proceed (y/N)? y
|
|||
INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini
|
||||
INFO : sessions initialised (transitively) in ${jetty.base}/start.d/sessions.ini
|
||||
INFO : session-store-infinispan-embedded initialised in ${jetty.base}/start.d/session-store-infinispan-embedded.ini
|
||||
DOWNLOAD: http://central.maven.org/maven2/org/infinispan/infinispan-embedded/7.1.1.Final/infinispan-embedded-7.1.1.Final.jar to ${jetty.base}/lib/infinispan/infinispan-embedded-7.1.1.Final.jar
|
||||
DOWNLOAD: https://repo1.maven.org/maven2/org/infinispan/infinispan-embedded/7.1.1.Final/infinispan-embedded-7.1.1.Final.jar to ${jetty.base}/lib/infinispan/infinispan-embedded-7.1.1.Final.jar
|
||||
INFO : Base directory was modified
|
||||
----
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ INFO : sessions transitively enabled, ini template available with --add-
|
|||
INFO : session-store-mongo initialized in ${jetty.base}/start.d/session-store-mongo.ini
|
||||
INFO : sessions/mongo/address dynamic dependency of session-store-mongo
|
||||
MKDIR : ${jetty.base}/lib/nosql
|
||||
DOWNLD: http://central.maven.org/maven2/org/mongodb/mongo-java-driver/2.13.2/mongo-java-driver-2.13.2.jar to ${jetty.base}/lib/nosql/mongo-java-driver-2.13.2.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/mongodb/mongo-java-driver/2.13.2/mongo-java-driver-2.13.2.jar to ${jetty.base}/lib/nosql/mongo-java-driver-2.13.2.jar
|
||||
INFO : Base directory was modified
|
||||
----
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@ MKDIR : ${jetty.base}/lib/alpn
|
|||
MKDIR : ${jetty.base}/etc
|
||||
COPY : ${jetty.home}/modules/ssl/keystore to ${jetty.base}/etc/keystore
|
||||
MKDIR : ${jetty.base}/webapps
|
||||
DOWNLD: http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.8.v20160420/alpn-boot-8.1.8.v20160420.jar to ${jetty.base}/lib/alpn/alpn-boot-8.1.8.v20160420.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.8.v20160420/alpn-boot-8.1.8.v20160420.jar to ${jetty.base}/lib/alpn/alpn-boot-8.1.8.v20160420.jar
|
||||
COPY : ${jetty.home}/modules/acme/acme.xml to ${jetty.base}/etc/acme.xml
|
||||
INFO : Base directory was modified
|
||||
----
|
||||
|
|
|
@ -261,4 +261,4 @@ You might need to escape the slash "\|" to use this on some environments.
|
|||
|
||||
maven.repo.uri=[url]::
|
||||
The url to use to download Maven dependencies.
|
||||
Default is http://central.maven.org/maven2/.
|
||||
Default is https://repo1.maven.org/maven2/.
|
||||
|
|
|
@ -83,7 +83,7 @@ INFO : server transitively enabled, ini template available with --add-
|
|||
INFO : conscrypt initialized in ${jetty.base}/start.d/conscrypt.ini
|
||||
INFO : ssl initialized in ${jetty.base}/start.d/ssl.ini
|
||||
MKDIR : ${jetty.base}/lib/conscrypt
|
||||
DOWNLD: http://central.maven.org/maven2/org/conscrypt/conscrypt-openjdk-uber/1.0.0.RC11/conscrypt-openjdk-uber-1.0.0.RC11.jar to ${jetty.base}/lib/conscrypt/conscrypt-uber-1.0.0.RC11.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/conscrypt/conscrypt-openjdk-uber/1.0.0.RC11/conscrypt-openjdk-uber-1.0.0.RC11.jar to ${jetty.base}/lib/conscrypt/conscrypt-uber-1.0.0.RC11.jar
|
||||
MKDIR : ${jetty.base}/etc
|
||||
COPY : ${jetty.home}/modules/conscrypt/conscrypt.xml to ${jetty.base}/etc/conscrypt.xml
|
||||
COPY : ${jetty.home}/modules/ssl/keystore to ${jetty.base}/etc/keystore
|
||||
|
|
|
@ -38,7 +38,7 @@ Its purpose is to provide almost the same functionality as the Jetty plugin for
|
|||
To set up your project for Ant to run Jetty, you need a Jetty distribution and the jetty-ant Jar:
|
||||
|
||||
1. https://www.eclipse.org/jetty/download.html[Download] a Jetty distribution and unpack it in the local filesystem.
|
||||
2. http://central.maven.org/maven2/org/eclipse/jetty/jetty-ant/[Get] the jetty-ant Jar.
|
||||
2. https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-ant/[Get] the jetty-ant Jar.
|
||||
3. Make a directory in your project called `jetty-lib/`.
|
||||
4. Copy all of the Jars in your Jetty distribution's `lib` directory, and all its subdirectories, into your new `jetty-lib` dir.
|
||||
When copying the Jars, _don't_ preserve the Jetty distribution's lib dir hierarchy – all the jars should be directly inside your ` jetty-lib` dir.
|
||||
|
|
|
@ -26,7 +26,7 @@ This section provides a tutorial that shows how you can quickly develop embedded
|
|||
|
||||
Jetty is decomposed into many jars and dependencies to achieve a minimal footprint by selecting the minimal set of jars.
|
||||
Typically it is best to use something like link:#jetty-maven-helloworld[Maven] to manage jars, however this tutorial uses an aggregate Jar that contains all of the required Jetty classes in one Jar.
|
||||
You can manually download the aggregate link:http://central.maven.org/maven2/org/eclipse/jetty/aggregate/jetty-all/{VERSION}/jetty-all-{VERSION}-uber.jar[`jetty-all.jar`] using `curl` or a browser.
|
||||
You can manually download the aggregate link:https://repo1.maven.org/maven2/org/eclipse/jetty/aggregate/jetty-all/{VERSION}/jetty-all-{VERSION}-uber.jar[`jetty-all.jar`] using `curl` or a browser.
|
||||
|
||||
____
|
||||
[NOTE]
|
||||
|
@ -46,7 +46,7 @@ Use curl as follows:
|
|||
....
|
||||
> mkdir Demo
|
||||
> cd Demo
|
||||
> curl -o jetty-all-uber.jar http://central.maven.org/maven2/org/eclipse/jetty/aggregate/jetty-all/{VERSION}/jetty-all-{VERSION}-uber.jar
|
||||
> curl -o jetty-all-uber.jar https://repo1.maven.org/maven2/org/eclipse/jetty/aggregate/jetty-all/{VERSION}/jetty-all-{VERSION}-uber.jar
|
||||
....
|
||||
|
||||
[[writing-helloworld-example]]
|
||||
|
|
|
@ -56,9 +56,9 @@ You *must also install the Apache Aries SPI Fly bundles* as many parts of Jetty
|
|||
|=======================================================================
|
||||
|Jar |Bundle Symbolic Name |Location
|
||||
|org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle-1.0.1.jar |org.apache.aries.spifly.dynamic.bundle
|
||||
|http://central.maven.org/maven2/org/apache/aries/spifly/org.apache.aries.spifly.dynamic.bundle/[Maven central]
|
||||
|https://repo1.maven.org/maven2/org/apache/aries/spifly/org.apache.aries.spifly.dynamic.bundle/[Maven central]
|
||||
|org.apache.aries:org.apache.aries.util-1.0.1.jar |org.apache.aries.util
|
||||
|http://central.maven.org/maven2/org/apache/aries/org.apache.aries.util/[Maven
|
||||
|https://repo1.maven.org/maven2/org/apache/aries/org.apache.aries.util/[Maven
|
||||
central]
|
||||
|=======================================================================
|
||||
|
||||
|
@ -74,7 +74,7 @@ If your OSGi container does not automatically make these available, you will nee
|
|||
|
||||
===== The jetty-osgi-boot jar
|
||||
|
||||
Now that you have the basic set of Jetty jars installed, you can install the http://central.maven.org/maven2/org/eclipse/jetty/osgi/jetty-osgi-boot/[jetty-osgi-boot.jar] bundle, downloadable from the maven central repo http://central.maven.org/maven2/org/eclipse/jetty/osgi/jetty-osgi-boot/[here.]
|
||||
Now that you have the basic set of Jetty jars installed, you can install the https://repo1.maven.org/maven2/org/eclipse/jetty/osgi/jetty-osgi-boot/[jetty-osgi-boot.jar] bundle, downloadable from the maven central repo https://repo1.maven.org/maven2/org/eclipse/jetty/osgi/jetty-osgi-boot/[here.]
|
||||
|
||||
This bundle will instantiate and make available the Jetty OSGi container when it is started.
|
||||
If this bundle is not auto-started upon installation into your OSGi container, you should start it manually using a command appropriate for your container.
|
||||
|
@ -663,7 +663,7 @@ The Jetty OSGi container failed to deploy a `WebAppContext` or `ContextHandler`
|
|||
===== Setup
|
||||
|
||||
In order to use JSPs with your webapps and bundles you will need to install the JSP and JSTL jars and their dependencies into your OSGi container.
|
||||
Some you will find in the Jetty distribution, whereas others you will need to download from http://central.maven.org/maven2/org/eclipse/jetty/orbit/[Maven central].
|
||||
Some you will find in the Jetty distribution, whereas others you will need to download from https://repo1.maven.org/maven2/org/eclipse/jetty/orbit/[Maven central].
|
||||
Here is the list of recommended jars (NOTE the version numbers may change in future):
|
||||
|
||||
[[osgi-jsp]]
|
||||
|
@ -688,7 +688,7 @@ Here is the list of recommended jars (NOTE the version numbers may change in fut
|
|||
|
||||
|org.eclipse.jetty.osgi:jetty-osgi-boot-jsp
|
||||
|org.eclipse.jetty.osgi.boot.jsp
|
||||
|http://central.maven.org/maven2/org/eclipse/jetty/osgi/jetty-osgi-boot-jsp[Maven central]
|
||||
|https://repo1.maven.org/maven2/org/eclipse/jetty/osgi/jetty-osgi-boot-jsp[Maven central]
|
||||
|=======================================================================
|
||||
|
||||
____
|
||||
|
@ -738,8 +738,8 @@ Orbit]
|
|||
|
||||
===== The jetty-osgi-boot-jsp jar
|
||||
|
||||
To be able to use JSPs you will need to also install the http://central.maven.org/maven2/org/eclipse/jetty/osgi/jetty-osgi-boot-jsp/[jetty-osgi-boot-jsp.jar] into your OSGi container.
|
||||
This jar can be obtained from maven central http://central.maven.org/maven2/org/eclipse/jetty/osgi/jetty-osgi-boot-jsp/[here].
|
||||
To be able to use JSPs you will need to also install the https://repo1.maven.org/maven2/org/eclipse/jetty/osgi/jetty-osgi-boot-jsp/[jetty-osgi-boot-jsp.jar] into your OSGi container.
|
||||
This jar can be obtained from maven central https://repo1.maven.org/maven2/org/eclipse/jetty/osgi/jetty-osgi-boot-jsp/[here].
|
||||
|
||||
This bundle acts as a fragment extension to the jetty-osgi-boot.jar and adds in support for using JSP.
|
||||
|
||||
|
@ -836,16 +836,16 @@ In order to use them with Jetty in OSGi, you will need to deploy some extra jars
|
|||
|Jar |Bundle Symbolic Name |Location
|
||||
|The link:#spifly[spifly jars] | |
|
||||
|org.ow2.asm:asm-5.0.1.jar |org.objectweb.asm
|
||||
|http://central.maven.org/maven2/org/ow2/asm/asm[Maven central]
|
||||
|https://repo1.maven.org/maven2/org/ow2/asm/asm[Maven central]
|
||||
|
||||
|org.ow2.asm:asm-commons-5.0.1.jar |org.objectweb.asm.commons
|
||||
|http://central.maven.org/maven2/org/ow2/asm/asm-commons[Maven central]
|
||||
|https://repo1.maven.org/maven2/org/ow2/asm/asm-commons[Maven central]
|
||||
|
||||
|org.ow2.asm:asm-tree-5.0.1.jar |org.objectweb.asm.tree
|
||||
|http://central.maven.org/maven2/org/ow2/asm/asm-tree[Maven central]
|
||||
|https://repo1.maven.org/maven2/org/ow2/asm/asm-tree[Maven central]
|
||||
|
||||
|javax.annotation:javax.annotation-api-1.2.jar |javax.annotation-api
|
||||
|http://central.maven.org/maven2/javax/annotation/javax.annotation-api/[Maven
|
||||
|https://repo1.maven.org/maven2/javax/annotation/javax.annotation-api/[Maven
|
||||
central]
|
||||
|
||||
|jta api version 1.1.1 (eg
|
||||
|
@ -1161,6 +1161,6 @@ In addition, as the feature group includes websocket, you will need to download
|
|||
|=======================================================================
|
||||
|Jar |Bundle Symbolic Name |Location
|
||||
|javax.websocket-api |javax.websocket-api
|
||||
|http://central.maven.org/maven2/javax/websocket/websocket-api[Maven
|
||||
|https://repo1.maven.org/maven2/javax/websocket/websocket-api[Maven
|
||||
central]
|
||||
|=======================================================================
|
||||
|
|
|
@ -113,7 +113,7 @@ Default value: the `org.apache.jasper.JspC` instance being configured.
|
|||
+
|
||||
The JspC class actually performs the pre-compilation.
|
||||
All setters on the JspC class are available.
|
||||
You can download the javadoc http://central.maven.org/maven2/org/glassfish/web/javax.servlet.jsp/2.3.2/javax.servlet.jsp-2.3.2-javadoc.jar[here].
|
||||
You can download the javadoc https://repo1.maven.org/maven2/org/glassfish/web/javax.servlet.jsp/2.3.2/javax.servlet.jsp-2.3.2-javadoc.jar[here].
|
||||
|
||||
Taking all the default settings, here's how to configure the war plugin to use the generated `web.xml` that includes all of the jsp servlet declarations:
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ Use an editor to create the file `pom.xml` in the `JettyMavenHelloWorld` directo
|
|||
|
||||
<properties>
|
||||
<!-- Adapt this to a version found on
|
||||
http://central.maven.org/maven2/org/eclipse/jetty/jetty-maven-plugin/
|
||||
https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-maven-plugin/
|
||||
-->
|
||||
<jettyVersion>9.3.9.v20160517</jettyVersion>
|
||||
</properties>
|
||||
|
|
|
@ -145,7 +145,7 @@ INFO : http2 initialized in ${jetty.base}/start.d/http2.ini
|
|||
INFO : https initialized in ${jetty.base}/start.d/https.ini
|
||||
INFO : ssl transitively enabled, ini template available with --add-to-start=ssl
|
||||
MKDIR : ${jetty.base}/lib/alpn
|
||||
DOWNLD: http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.8.v20160420/alpn-boot-8.1.8.v20160420.jar to ${jetty.base}/lib/alpn/alpn-boot-8.1.8.v20160420.jar
|
||||
DOWNLD: https://repo1.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.8.v20160420/alpn-boot-8.1.8.v20160420.jar to ${jetty.base}/lib/alpn/alpn-boot-8.1.8.v20160420.jar
|
||||
MKDIR : ${jetty.base}/etc
|
||||
COPY : ${jetty.home}/modules/ssl/keystore to ${jetty.base}/etc/keystore
|
||||
INFO : Base directory was modified
|
||||
|
|
|
@ -72,7 +72,7 @@ Jetty-Home can be downloaded from the Maven Central repository:
|
|||
|
||||
____
|
||||
*Jetty-Home*
|
||||
http://central.maven.org/maven2/org/eclipse/jetty/jetty-home/
|
||||
https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-home/
|
||||
____
|
||||
|
||||
Like the main Jetty distribution, Jetty-Home is available in both zip and gzip formats; download the one most appropriate for your system.
|
||||
|
|
|
@ -47,7 +47,7 @@ The top level Project Object Model (POM) for the Jetty project is located under
|
|||
The changes between versions of Jetty are tracked in a file called VERSIONS.txt, which is under source control and is generated on release.
|
||||
Those generated files are also uploaded into Maven Central during the release of the top level POM. You can find them as a classifier marked artifact.
|
||||
|
||||
http://central.maven.org/maven2/org/eclipse/jetty/jetty-project/
|
||||
https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-project/
|
||||
|
||||
[source, xml, subs="{sub-order}"]
|
||||
----
|
||||
|
|
|
@ -50,15 +50,17 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
*/
|
||||
public enum HttpCompliance // TODO in Jetty-10 convert this enum to a class so that extra custom modes can be defined dynamically
|
||||
{
|
||||
/** A Legacy compliance mode to match jetty's behavior prior to RFC2616 and RFC7230. It only
|
||||
* contains {@link HttpComplianceSection#METHOD_CASE_SENSITIVE}
|
||||
/** A Legacy compliance mode to match jetty's behavior prior to RFC2616 and RFC7230.
|
||||
*/
|
||||
LEGACY(sectionsBySpec("0,METHOD_CASE_SENSITIVE")),
|
||||
|
||||
/** The legacy RFC2616 support, which incorrectly excludes
|
||||
* {@link HttpComplianceSection#METHOD_CASE_SENSITIVE}, {@link HttpComplianceSection#FIELD_COLON}
|
||||
* {@link HttpComplianceSection#METHOD_CASE_SENSITIVE},
|
||||
* {@link HttpComplianceSection#FIELD_COLON},
|
||||
* {@link HttpComplianceSection#TRANSFER_ENCODING_WITH_CONTENT_LENGTH},
|
||||
* {@link HttpComplianceSection#MULTIPLE_CONTENT_LENGTHS},
|
||||
*/
|
||||
RFC2616_LEGACY(sectionsBySpec("RFC2616,-FIELD_COLON,-METHOD_CASE_SENSITIVE")),
|
||||
RFC2616_LEGACY(sectionsBySpec("RFC2616,-FIELD_COLON,-METHOD_CASE_SENSITIVE,-TRANSFER_ENCODING_WITH_CONTENT_LENGTH,-MULTIPLE_CONTENT_LENGTHS")),
|
||||
|
||||
/** The strict RFC2616 support mode */
|
||||
RFC2616(sectionsBySpec("RFC2616")),
|
||||
|
|
|
@ -28,7 +28,9 @@ public enum HttpComplianceSection
|
|||
FIELD_NAME_CASE_INSENSITIVE("https://tools.ietf.org/html/rfc7230#section-3.2","Field name is case-insensitive"),
|
||||
NO_WS_AFTER_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2.4","Whitespace not allowed after field name"),
|
||||
NO_FIELD_FOLDING("https://tools.ietf.org/html/rfc7230#section-3.2.4","No line Folding"),
|
||||
NO_HTTP_0_9("https://tools.ietf.org/html/rfc7230#appendix-A.2","No HTTP/0.9");
|
||||
NO_HTTP_0_9("https://tools.ietf.org/html/rfc7230#appendix-A.2","No HTTP/0.9"),
|
||||
TRANSFER_ENCODING_WITH_CONTENT_LENGTH("https://tools.ietf.org/html/rfc7230#section-3.3.1","Transfer-Encoding and Content-Length"),
|
||||
MULTIPLE_CONTENT_LENGTHS("https://tools.ietf.org/html/rfc7230#section-3.3.1","Multiple Content-Lengths");
|
||||
|
||||
final String url;
|
||||
final String description;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -18,21 +18,174 @@
|
|||
|
||||
package org.eclipse.jetty.http;
|
||||
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
|
||||
/**
|
||||
* HTTP constants
|
||||
*/
|
||||
public interface HttpTokens
|
||||
public class HttpTokens
|
||||
{
|
||||
// Terminal symbols.
|
||||
static final byte COLON= (byte)':';
|
||||
static final byte TAB= 0x09;
|
||||
static final byte LINE_FEED= 0x0A;
|
||||
static final byte CARRIAGE_RETURN= 0x0D;
|
||||
static final byte SPACE= 0x20;
|
||||
static final byte[] CRLF = {CARRIAGE_RETURN,LINE_FEED};
|
||||
static final byte SEMI_COLON= (byte)';';
|
||||
|
||||
public enum EndOfContent { UNKNOWN_CONTENT,NO_CONTENT,EOF_CONTENT,CONTENT_LENGTH,CHUNKED_CONTENT }
|
||||
|
||||
|
||||
public enum Type
|
||||
{
|
||||
CNTL, // Control characters excluding LF, CR
|
||||
HTAB, // Horizontal tab
|
||||
LF, // Line feed
|
||||
CR, // Carriage return
|
||||
SPACE, // Space
|
||||
COLON, // Colon character
|
||||
DIGIT, // Digit
|
||||
ALPHA, // Alpha
|
||||
TCHAR, // token characters excluding COLON,DIGIT,ALPHA, which is equivalent to VCHAR excluding delimiters
|
||||
VCHAR, // Visible characters excluding COLON,DIGIT,ALPHA
|
||||
OTEXT // Obsolete text
|
||||
}
|
||||
|
||||
public static class Token
|
||||
{
|
||||
private final Type _type;
|
||||
private final byte _b;
|
||||
private final char _c;
|
||||
private final int _x;
|
||||
|
||||
private Token(byte b, Type type)
|
||||
{
|
||||
_type = type;
|
||||
_b = b;
|
||||
_c = (char)(0xff&b);
|
||||
char lc = (_c>='A' & _c<='Z')?((char)(_c-'A'+'a')):_c;
|
||||
_x = (_type==Type.DIGIT || _type==Type.ALPHA && lc>='a' && lc<='f')?TypeUtil.convertHexDigit(b):-1;
|
||||
}
|
||||
|
||||
public Type getType()
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
public byte getByte()
|
||||
{
|
||||
return _b;
|
||||
}
|
||||
|
||||
public char getChar()
|
||||
{
|
||||
return _c;
|
||||
}
|
||||
|
||||
public boolean isHexDigit()
|
||||
{
|
||||
return _x>=0;
|
||||
}
|
||||
|
||||
public int getHexDigit()
|
||||
{
|
||||
return _x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
switch(_type)
|
||||
{
|
||||
case SPACE:
|
||||
case COLON:
|
||||
case ALPHA:
|
||||
case DIGIT:
|
||||
case TCHAR:
|
||||
case VCHAR:
|
||||
return _type+"='"+_c+"'";
|
||||
|
||||
case CR:
|
||||
return "CR=\\r";
|
||||
|
||||
case LF:
|
||||
return "LF=\\n";
|
||||
|
||||
default:
|
||||
return String.format("%s=0x%x",_type,_b);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final static Token[] TOKENS = new Token[256];
|
||||
|
||||
static
|
||||
{
|
||||
for (int b=0; b<256; b++)
|
||||
{
|
||||
// token = 1*tchar
|
||||
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
|
||||
// / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
|
||||
// / DIGIT / ALPHA
|
||||
// ; any VCHAR, except delimiters
|
||||
// quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
|
||||
// qdtext = HTAB / SP /%x21 / %x23-5B / %x5D-7E / obs-text
|
||||
// obs-text = %x80-FF
|
||||
// comment = "(" *( ctext / quoted-pair / comment ) ")"
|
||||
// ctext = HTAB / SP / %x21-27 / %x2A-5B / %x5D-7E / obs-text
|
||||
// quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
||||
|
||||
switch (b)
|
||||
{
|
||||
case LINE_FEED:
|
||||
TOKENS[b] = new Token((byte)b,Type.LF);
|
||||
break;
|
||||
case CARRIAGE_RETURN:
|
||||
TOKENS[b] = new Token((byte)b,Type.CR);
|
||||
break;
|
||||
case SPACE:
|
||||
TOKENS[b] = new Token((byte)b,Type.SPACE);
|
||||
break;
|
||||
case TAB:
|
||||
TOKENS[b] = new Token((byte)b,Type.HTAB);
|
||||
break;
|
||||
case COLON:
|
||||
TOKENS[b] = new Token((byte)b,Type.COLON);
|
||||
break;
|
||||
|
||||
case '!':
|
||||
case '#':
|
||||
case '$':
|
||||
case '%':
|
||||
case '&':
|
||||
case '\'':
|
||||
case '*':
|
||||
case '+':
|
||||
case '-':
|
||||
case '.':
|
||||
case '^':
|
||||
case '_':
|
||||
case '`':
|
||||
case '|':
|
||||
case '~':
|
||||
TOKENS[b] = new Token((byte)b,Type.TCHAR);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (b>=0x30 &&b<=0x39) // DIGIT
|
||||
TOKENS[b] = new Token((byte)b,Type.DIGIT);
|
||||
else if (b>=0x41 &&b<=0x5A) // ALPHA (uppercase)
|
||||
TOKENS[b] = new Token((byte)b,Type.ALPHA);
|
||||
else if (b>=0x61 &&b<=0x7A) // ALPHA (lowercase)
|
||||
TOKENS[b] = new Token((byte)b,Type.ALPHA);
|
||||
else if (b>=0x21 &&b<=0x7E) // Visible
|
||||
TOKENS[b] = new Token((byte)b,Type.VCHAR);
|
||||
else if (b>=0x80) // OBS
|
||||
TOKENS[b] = new Token((byte)b,Type.OTEXT);
|
||||
else
|
||||
TOKENS[b] = new Token((byte)b,Type.CNTL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,13 +40,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
public class MultiPartParser
|
||||
{
|
||||
public static final Logger LOG = Log.getLogger(MultiPartParser.class);
|
||||
|
||||
private static final byte COLON = (byte)':';
|
||||
private static final byte TAB = 0x09;
|
||||
private static final byte LINE_FEED = 0x0A;
|
||||
private static final byte CARRIAGE_RETURN = 0x0D;
|
||||
private static final byte SPACE = 0x20;
|
||||
|
||||
|
||||
// States
|
||||
public enum FieldState
|
||||
{
|
||||
|
@ -134,41 +128,49 @@ public class MultiPartParser
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
private byte getNextByte(ByteBuffer buffer)
|
||||
private HttpTokens.Token next(ByteBuffer buffer)
|
||||
{
|
||||
|
||||
byte ch = buffer.get();
|
||||
|
||||
HttpTokens.Token t = HttpTokens.TOKENS[0xff & ch];
|
||||
|
||||
HttpParser.CharState s = HttpParser.TOKEN_CHAR[0xff & ch];
|
||||
switch (s)
|
||||
if (DEBUG)
|
||||
LOG.debug("token={}",t);
|
||||
|
||||
switch(t.getType())
|
||||
{
|
||||
case CNTL:
|
||||
throw new IllegalCharacterException(_state,t,buffer);
|
||||
|
||||
case LF:
|
||||
_cr = false;
|
||||
return ch;
|
||||
|
||||
_cr=false;
|
||||
break;
|
||||
|
||||
case CR:
|
||||
if (_cr)
|
||||
throw new BadMessageException("Bad EOL");
|
||||
|
||||
_cr = true;
|
||||
if (buffer.hasRemaining())
|
||||
return getNextByte(buffer);
|
||||
|
||||
// Can return 0 here to indicate the need for more characters,
|
||||
// because a real 0 in the buffer would cause a BadMessage below
|
||||
return 0;
|
||||
|
||||
case LEGAL:
|
||||
|
||||
_cr=true;
|
||||
return null;
|
||||
|
||||
case ALPHA:
|
||||
case DIGIT:
|
||||
case TCHAR:
|
||||
case VCHAR:
|
||||
case HTAB:
|
||||
case SPACE:
|
||||
case OTEXT:
|
||||
case COLON:
|
||||
if (_cr)
|
||||
throw new BadMessageException("Bad EOL");
|
||||
break;
|
||||
|
||||
return ch;
|
||||
|
||||
case ILLEGAL:
|
||||
default:
|
||||
throw new IllegalCharacterException(_state, ch, buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
private void setString(String s)
|
||||
|
@ -307,11 +309,11 @@ public class MultiPartParser
|
|||
{
|
||||
while (__delimiterStates.contains(_state) && hasNextByte(buffer))
|
||||
{
|
||||
byte b = getNextByte(buffer);
|
||||
if (b == 0)
|
||||
HttpTokens.Token t = next(buffer);
|
||||
if (t == null)
|
||||
return;
|
||||
|
||||
if (b == '\n')
|
||||
if (t.getType()==HttpTokens.Type.LF)
|
||||
{
|
||||
setState(State.BODY_PART);
|
||||
|
||||
|
@ -325,14 +327,14 @@ public class MultiPartParser
|
|||
switch (_state)
|
||||
{
|
||||
case DELIMITER:
|
||||
if (b == '-')
|
||||
if (t.getChar() == '-')
|
||||
setState(State.DELIMITER_CLOSE);
|
||||
else
|
||||
setState(State.DELIMITER_PADDING);
|
||||
continue;
|
||||
|
||||
case DELIMITER_CLOSE:
|
||||
if (b == '-')
|
||||
if (t.getChar() == '-')
|
||||
{
|
||||
setState(State.EPILOGUE);
|
||||
return;
|
||||
|
@ -356,11 +358,11 @@ public class MultiPartParser
|
|||
while (_state == State.BODY_PART && hasNextByte(buffer))
|
||||
{
|
||||
// process each character
|
||||
byte b = getNextByte(buffer);
|
||||
if (b == 0)
|
||||
HttpTokens.Token t = next(buffer);
|
||||
if (t == null)
|
||||
break;
|
||||
|
||||
if (b != LINE_FEED)
|
||||
|
||||
if (t.getType() != HttpTokens.Type.LF)
|
||||
_totalHeaderLineLength++;
|
||||
|
||||
if (_totalHeaderLineLength > MAX_HEADER_LINE_LENGTH)
|
||||
|
@ -369,10 +371,10 @@ public class MultiPartParser
|
|||
switch (_fieldState)
|
||||
{
|
||||
case FIELD:
|
||||
switch (b)
|
||||
switch (t.getType())
|
||||
{
|
||||
case SPACE:
|
||||
case TAB:
|
||||
case HTAB:
|
||||
{
|
||||
// Folded field value!
|
||||
|
||||
|
@ -395,8 +397,7 @@ public class MultiPartParser
|
|||
break;
|
||||
}
|
||||
|
||||
case LINE_FEED:
|
||||
{
|
||||
case LF:
|
||||
handleField();
|
||||
setState(State.FIRST_OCTETS);
|
||||
_partialBoundary = 2; // CRLF is option for empty parts
|
||||
|
@ -407,24 +408,28 @@ public class MultiPartParser
|
|||
if (_handler.headerComplete())
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
|
||||
case ALPHA:
|
||||
case DIGIT:
|
||||
case TCHAR:
|
||||
// process previous header
|
||||
handleField();
|
||||
|
||||
// New header
|
||||
setState(FieldState.IN_NAME);
|
||||
_string.reset();
|
||||
_string.append(b);
|
||||
_string.append(t.getChar());
|
||||
_length = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalCharacterException(_state,t,buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
case IN_NAME:
|
||||
switch (b)
|
||||
switch(t.getType())
|
||||
{
|
||||
case COLON:
|
||||
_fieldName = takeString();
|
||||
|
@ -437,7 +442,7 @@ public class MultiPartParser
|
|||
setState(FieldState.AFTER_NAME);
|
||||
break;
|
||||
|
||||
case LINE_FEED:
|
||||
case LF:
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Line Feed in Name {}", this);
|
||||
|
@ -446,16 +451,21 @@ public class MultiPartParser
|
|||
setState(FieldState.FIELD);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
_string.append(b);
|
||||
|
||||
case ALPHA:
|
||||
case DIGIT:
|
||||
case TCHAR:
|
||||
_string.append(t.getChar());
|
||||
_length = _string.length();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalCharacterException(_state,t,buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
case AFTER_NAME:
|
||||
switch (b)
|
||||
switch(t.getType())
|
||||
{
|
||||
case COLON:
|
||||
_fieldName = takeString();
|
||||
|
@ -463,7 +473,7 @@ public class MultiPartParser
|
|||
setState(FieldState.VALUE);
|
||||
break;
|
||||
|
||||
case LINE_FEED:
|
||||
case LF:
|
||||
_fieldName = takeString();
|
||||
_string.reset();
|
||||
_fieldValue = "";
|
||||
|
@ -474,14 +484,14 @@ public class MultiPartParser
|
|||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalCharacterException(_state, b, buffer);
|
||||
throw new IllegalCharacterException(_state, t, buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
case VALUE:
|
||||
switch (b)
|
||||
switch(t.getType())
|
||||
{
|
||||
case LINE_FEED:
|
||||
case LF:
|
||||
_string.reset();
|
||||
_fieldValue = "";
|
||||
_length = -1;
|
||||
|
@ -490,25 +500,34 @@ public class MultiPartParser
|
|||
break;
|
||||
|
||||
case SPACE:
|
||||
case TAB:
|
||||
case HTAB:
|
||||
break;
|
||||
|
||||
default:
|
||||
_string.append(b);
|
||||
|
||||
case ALPHA:
|
||||
case DIGIT:
|
||||
case TCHAR:
|
||||
case VCHAR:
|
||||
case COLON:
|
||||
case OTEXT:
|
||||
_string.append(t.getByte());
|
||||
_length = _string.length();
|
||||
setState(FieldState.IN_VALUE);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalCharacterException(_state,t,buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
case IN_VALUE:
|
||||
switch (b)
|
||||
switch(t.getType())
|
||||
{
|
||||
case SPACE:
|
||||
_string.append(b);
|
||||
case HTAB:
|
||||
_string.append(' ');
|
||||
break;
|
||||
|
||||
case LINE_FEED:
|
||||
case LF:
|
||||
if (_length > 0)
|
||||
{
|
||||
_fieldValue = takeString();
|
||||
|
@ -517,12 +536,19 @@ public class MultiPartParser
|
|||
}
|
||||
setState(FieldState.FIELD);
|
||||
break;
|
||||
|
||||
default:
|
||||
_string.append(b);
|
||||
if (b > SPACE || b < 0)
|
||||
_length = _string.length();
|
||||
|
||||
case ALPHA:
|
||||
case DIGIT:
|
||||
case TCHAR:
|
||||
case VCHAR:
|
||||
case COLON:
|
||||
case OTEXT:
|
||||
_string.append(t.getByte());
|
||||
_length=_string.length();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalCharacterException(_state,t,buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -694,16 +720,16 @@ public class MultiPartParser
|
|||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
@SuppressWarnings("serial")
|
||||
private static class IllegalCharacterException extends IllegalArgumentException
|
||||
private static class IllegalCharacterException extends BadMessageException
|
||||
{
|
||||
private IllegalCharacterException(State state, byte ch, ByteBuffer buffer)
|
||||
private IllegalCharacterException(State state,HttpTokens.Token token,ByteBuffer buffer)
|
||||
{
|
||||
super(String.format("Illegal character 0x%X", ch));
|
||||
// Bug #460642 - don't reveal buffers to end user
|
||||
LOG.warn(String.format("Illegal character 0x%X in state=%s for buffer %s", ch, state, BufferUtil.toDetailString(buffer)));
|
||||
super(400,String.format("Illegal character %s",token));
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(String.format("Illegal character %s in state=%s for buffer %s",token,state,BufferUtil.toDetailString(buffer)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -216,6 +216,31 @@ public class HttpParserTest
|
|||
Assert.assertEquals(-1, _headers);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllowedLinePreamble() throws Exception
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer("\r\n\r\nGET / HTTP/1.0\r\n");
|
||||
|
||||
HttpParser.RequestHandler handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
Assert.assertEquals("GET", _methodOrVersion);
|
||||
Assert.assertEquals("/", _uriOrStatus);
|
||||
Assert.assertEquals("HTTP/1.0", _versionOrReason);
|
||||
Assert.assertEquals(-1, _headers);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisallowedLinePreamble() throws Exception
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer("\r\n \r\nGET / HTTP/1.0\r\n");
|
||||
|
||||
HttpParser.RequestHandler handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
Assert.assertEquals("Illegal character SPACE=' '", _bad);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnect() throws Exception
|
||||
{
|
||||
|
@ -446,7 +471,7 @@ public class HttpParserTest
|
|||
Assert.assertEquals("HTTP/1.1", _methodOrVersion);
|
||||
Assert.assertEquals("204", _uriOrStatus);
|
||||
Assert.assertEquals("No Content", _versionOrReason);
|
||||
Assert.assertThat(_bad, Matchers.containsString("Illegal character 0x20"));
|
||||
Assert.assertThat(_bad, Matchers.containsString("Illegal character "));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -723,6 +748,40 @@ public class HttpParserTest
|
|||
parseAll(parser, buffer);
|
||||
Assert.assertThat(_bad, Matchers.notNullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadHeaderNames() throws Exception
|
||||
{
|
||||
String[] bad = new String[]
|
||||
{
|
||||
"Foo\\Bar: value\r\n",
|
||||
"Foo@Bar: value\r\n",
|
||||
"Foo,Bar: value\r\n",
|
||||
"Foo}Bar: value\r\n",
|
||||
"Foo{Bar: value\r\n",
|
||||
"Foo=Bar: value\r\n",
|
||||
"Foo>Bar: value\r\n",
|
||||
"Foo<Bar: value\r\n",
|
||||
"Foo)Bar: value\r\n",
|
||||
"Foo(Bar: value\r\n",
|
||||
"Foo?Bar: value\r\n",
|
||||
"Foo\"Bar: value\r\n",
|
||||
"Foo/Bar: value\r\n",
|
||||
"Foo]Bar: value\r\n",
|
||||
"Foo[Bar: value\r\n",
|
||||
};
|
||||
|
||||
for (int i=0; i<bad.length; i++)
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer(
|
||||
"GET / HTTP/1.0\r\n" + bad[i]+ "\r\n");
|
||||
|
||||
HttpParser.RequestHandler handler = new Handler();
|
||||
HttpParser parser= new HttpParser(handler);
|
||||
parseAll(parser,buffer);
|
||||
Assert.assertThat(bad[i],_bad,Matchers.notNullValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHeaderTab() throws Exception
|
||||
|
@ -1741,7 +1800,7 @@ public class HttpParserTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateContentLengthWithLargerThenCorrectValue()
|
||||
public void testMultipleContentLengthWithLargerThenCorrectValue()
|
||||
{
|
||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||
"POST / HTTP/1.1\r\n"
|
||||
|
@ -1756,7 +1815,7 @@ public class HttpParserTest
|
|||
|
||||
parser.parseNext(buffer);
|
||||
Assert.assertEquals("POST", _methodOrVersion);
|
||||
Assert.assertEquals("Duplicate Content-Length", _bad);
|
||||
Assert.assertEquals("Multiple Content-Lengths", _bad);
|
||||
Assert.assertFalse(buffer.hasRemaining());
|
||||
Assert.assertEquals(HttpParser.State.CLOSE, parser.getState());
|
||||
parser.atEOF();
|
||||
|
@ -1765,7 +1824,7 @@ public class HttpParserTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateContentLengthWithCorrectThenLargerValue()
|
||||
public void testMultipleContentLengthWithCorrectThenLargerValue()
|
||||
{
|
||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||
"POST / HTTP/1.1\r\n"
|
||||
|
@ -1780,7 +1839,7 @@ public class HttpParserTest
|
|||
|
||||
parser.parseNext(buffer);
|
||||
Assert.assertEquals("POST", _methodOrVersion);
|
||||
Assert.assertEquals("Duplicate Content-Length", _bad);
|
||||
Assert.assertEquals("Multiple Content-Lengths", _bad);
|
||||
Assert.assertFalse(buffer.hasRemaining());
|
||||
Assert.assertEquals(HttpParser.State.CLOSE, parser.getState());
|
||||
parser.atEOF();
|
||||
|
@ -1803,7 +1862,7 @@ public class HttpParserTest
|
|||
+ "\r\n");
|
||||
|
||||
HttpParser.RequestHandler handler = new Handler();
|
||||
HttpParser parser = new HttpParser(handler);
|
||||
HttpParser parser = new HttpParser(handler, HttpCompliance.RFC2616_LEGACY);
|
||||
parseAll(parser, buffer);
|
||||
|
||||
Assert.assertEquals("POST", _methodOrVersion);
|
||||
|
@ -1813,6 +1872,8 @@ public class HttpParserTest
|
|||
|
||||
Assert.assertTrue(_headerCompleted);
|
||||
Assert.assertTrue(_messageCompleted);
|
||||
|
||||
Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.TRANSFER_ENCODING_WITH_CONTENT_LENGTH));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1830,7 +1891,7 @@ public class HttpParserTest
|
|||
+ "\r\n");
|
||||
|
||||
HttpParser.RequestHandler handler = new Handler();
|
||||
HttpParser parser = new HttpParser(handler);
|
||||
HttpParser parser = new HttpParser(handler, HttpCompliance.RFC2616_LEGACY);
|
||||
parseAll(parser, buffer);
|
||||
|
||||
Assert.assertEquals("POST", _methodOrVersion);
|
||||
|
@ -1840,6 +1901,8 @@ public class HttpParserTest
|
|||
|
||||
Assert.assertTrue(_headerCompleted);
|
||||
Assert.assertTrue(_messageCompleted);
|
||||
|
||||
Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.TRANSFER_ENCODING_WITH_CONTENT_LENGTH));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -482,6 +482,49 @@ public class MultiPartParserTest
|
|||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBadHeaderNames() throws Exception
|
||||
{
|
||||
String[] bad = new String[]
|
||||
{
|
||||
"Foo\\Bar: value\r\n",
|
||||
"Foo@Bar: value\r\n",
|
||||
"Foo,Bar: value\r\n",
|
||||
"Foo}Bar: value\r\n",
|
||||
"Foo{Bar: value\r\n",
|
||||
"Foo=Bar: value\r\n",
|
||||
"Foo>Bar: value\r\n",
|
||||
"Foo<Bar: value\r\n",
|
||||
"Foo)Bar: value\r\n",
|
||||
"Foo(Bar: value\r\n",
|
||||
"Foo?Bar: value\r\n",
|
||||
"Foo\"Bar: value\r\n",
|
||||
"Foo/Bar: value\r\n",
|
||||
"Foo]Bar: value\r\n",
|
||||
"Foo[Bar: value\r\n",
|
||||
"\u0192\u00f8\u00f8\u00df\u00e5\u00ae: value\r\n"
|
||||
};
|
||||
|
||||
for (int i=0; i<bad.length; i++)
|
||||
{
|
||||
ByteBuffer buffer= BufferUtil.toBuffer(
|
||||
"--AaB03x\r\n" + bad[i] + "\r\n--AaB03x--\r\n");
|
||||
|
||||
MultiPartParser.Handler handler = new TestHandler();
|
||||
MultiPartParser parser= new MultiPartParser(handler, "AaB03x");
|
||||
|
||||
try
|
||||
{
|
||||
parser.parse(buffer, true);
|
||||
}
|
||||
catch(BadMessageException e)
|
||||
{
|
||||
assertTrue(e.getMessage().contains("Illegal character"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void splitTest()
|
||||
{
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
#org.eclipse.jetty.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.server.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.http.LEVEL=DEBUG
|
||||
|
|
|
@ -17,8 +17,7 @@ Content-Transfer-Encoding: 8bit
|
|||
|
||||
Value 3
|
||||
--z5xWs05oeiE0TAdFlrrlAX5RSgHrHzVcgskrru
|
||||
Content-Disposition: form-data; name="other\";
|
||||
what=\"Something\""
|
||||
Content-Disposition: form-data; name="other\"; what=\"Something\""
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
package org.eclipse.jetty.http2.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
|
@ -107,7 +107,8 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
|
|||
{
|
||||
Map<Integer, Integer> settings = listener.onPreface(getSession());
|
||||
if (settings == null)
|
||||
settings = Collections.emptyMap();
|
||||
settings = new HashMap<>();
|
||||
settings.computeIfAbsent(SettingsFrame.INITIAL_WINDOW_SIZE, k -> client.getInitialStreamRecvWindow());
|
||||
|
||||
PrefaceFrame prefaceFrame = new PrefaceFrame();
|
||||
SettingsFrame settingsFrame = new SettingsFrame(settings, false);
|
||||
|
|
|
@ -103,7 +103,7 @@ public class AsyncServletTest extends AbstractTest
|
|||
{
|
||||
try
|
||||
{
|
||||
buffer.write(BufferUtil.toArray(frame.getData()));
|
||||
BufferUtil.writeTo(frame.getData(), buffer);
|
||||
callback.succeeded();
|
||||
if (frame.isEndStream())
|
||||
latch.countDown();
|
||||
|
|
|
@ -679,13 +679,7 @@ public abstract class FlowControlStrategyTest
|
|||
@Override
|
||||
public void onData(Stream stream, DataFrame frame, Callback callback)
|
||||
{
|
||||
// Since we echo back the data
|
||||
// asynchronously we must copy it.
|
||||
ByteBuffer data = frame.getData();
|
||||
ByteBuffer copy = ByteBuffer.allocateDirect(data.remaining());
|
||||
copy.put(data).flip();
|
||||
completable.thenRun(() ->
|
||||
stream.data(new DataFrame(stream.getId(), copy, frame.isEndStream()), callback));
|
||||
completable.thenRun(() -> stream.data(frame, callback));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 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;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.http.HostPortHttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpScheme;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http2.ISession;
|
||||
import org.eclipse.jetty.http2.IStream;
|
||||
import org.eclipse.jetty.http2.api.Session;
|
||||
import org.eclipse.jetty.http2.api.Stream;
|
||||
import org.eclipse.jetty.http2.api.server.ServerSessionListener;
|
||||
import org.eclipse.jetty.http2.frames.HeadersFrame;
|
||||
import org.eclipse.jetty.http2.server.RawHTTP2ServerConnectionFactory;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class FlowControlWindowsTest
|
||||
{
|
||||
private Server server;
|
||||
private ServerConnector connector;
|
||||
private HTTP2Client client;
|
||||
private int serverSessionRecvWindow = 3 * 1024 * 1024;
|
||||
private int serverStreamRecvWindow = 2 * 1024 * 1024;
|
||||
private int clientSessionRecvWindow = 5 * 1024 * 1024;
|
||||
private int clientStreamRecvWindow = 4 * 1024 * 1024;
|
||||
|
||||
private void start(ServerSessionListener listener) throws Exception
|
||||
{
|
||||
RawHTTP2ServerConnectionFactory connectionFactory = new RawHTTP2ServerConnectionFactory(new HttpConfiguration(), listener);
|
||||
connectionFactory.setInitialSessionRecvWindow(serverSessionRecvWindow);
|
||||
connectionFactory.setInitialStreamRecvWindow(serverStreamRecvWindow);
|
||||
QueuedThreadPool serverExecutor = new QueuedThreadPool();
|
||||
serverExecutor.setName("server");
|
||||
server = new Server(serverExecutor);
|
||||
connector = new ServerConnector(server, 1, 1, connectionFactory);
|
||||
server.addConnector(connector);
|
||||
server.start();
|
||||
|
||||
client = new HTTP2Client();
|
||||
QueuedThreadPool clientExecutor = new QueuedThreadPool();
|
||||
clientExecutor.setName("client");
|
||||
client.setExecutor(clientExecutor);
|
||||
client.setInitialSessionRecvWindow(clientSessionRecvWindow);
|
||||
client.setInitialStreamRecvWindow(clientStreamRecvWindow);
|
||||
client.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void dispose() throws Exception
|
||||
{
|
||||
if (client != null)
|
||||
client.stop();
|
||||
if (server != null)
|
||||
server.stop();
|
||||
}
|
||||
|
||||
protected ISession newClient(Session.Listener listener) throws Exception
|
||||
{
|
||||
String host = "localhost";
|
||||
int port = connector.getLocalPort();
|
||||
InetSocketAddress address = new InetSocketAddress(host, port);
|
||||
FuturePromise<Session> promise = new FuturePromise<>();
|
||||
client.connect(address, listener, promise);
|
||||
return (ISession)promise.get(5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientFlowControlWindows() throws Exception
|
||||
{
|
||||
start(new ServerSessionListener.Adapter());
|
||||
|
||||
ISession clientSession = newClient(new Session.Listener.Adapter());
|
||||
// Wait while client and server exchange SETTINGS and WINDOW_UPDATE frames.
|
||||
Thread.sleep(1000);
|
||||
|
||||
int sessionSendWindow = clientSession.updateSendWindow(0);
|
||||
Assert.assertEquals(serverSessionRecvWindow, sessionSendWindow);
|
||||
int sessionRecvWindow = clientSession.updateRecvWindow(0);
|
||||
Assert.assertEquals(clientSessionRecvWindow, sessionRecvWindow);
|
||||
|
||||
HostPortHttpField hostPort = new HostPortHttpField("localhost:" + connector.getLocalPort());
|
||||
MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), HttpScheme.HTTP, hostPort, "/", HttpVersion.HTTP_2, new HttpFields());
|
||||
HeadersFrame frame = new HeadersFrame(request, null, true);
|
||||
FuturePromise<Stream> promise = new FuturePromise<>();
|
||||
clientSession.newStream(frame, promise, new Stream.Listener.Adapter());
|
||||
IStream clientStream = (IStream)promise.get(5, TimeUnit.SECONDS);
|
||||
|
||||
int streamSendWindow = clientStream.updateSendWindow(0);
|
||||
Assert.assertEquals(serverStreamRecvWindow, streamSendWindow);
|
||||
int streamRecvWindow = clientStream.updateRecvWindow(0);
|
||||
Assert.assertEquals(clientStreamRecvWindow, streamRecvWindow);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerFlowControlWindows() throws Exception
|
||||
{
|
||||
AtomicReference<ISession> sessionRef = new AtomicReference<>();
|
||||
CountDownLatch sessionLatch = new CountDownLatch(1);
|
||||
AtomicReference<IStream> streamRef = new AtomicReference<>();
|
||||
CountDownLatch streamLatch = new CountDownLatch(1);
|
||||
start(new ServerSessionListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onAccept(Session session)
|
||||
{
|
||||
sessionRef.set((ISession)session);
|
||||
sessionLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
|
||||
{
|
||||
streamRef.set((IStream)stream);
|
||||
streamLatch.countDown();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
ISession clientSession = newClient(new Session.Listener.Adapter());
|
||||
|
||||
Assert.assertTrue(sessionLatch.await(5, TimeUnit.SECONDS));
|
||||
ISession serverSession = sessionRef.get();
|
||||
// Wait while client and server exchange SETTINGS and WINDOW_UPDATE frames.
|
||||
Thread.sleep(1000);
|
||||
|
||||
int sessionSendWindow = serverSession.updateSendWindow(0);
|
||||
Assert.assertEquals(clientSessionRecvWindow, sessionSendWindow);
|
||||
int sessionRecvWindow = serverSession.updateRecvWindow(0);
|
||||
Assert.assertEquals(serverSessionRecvWindow, sessionRecvWindow);
|
||||
|
||||
HostPortHttpField hostPort = new HostPortHttpField("localhost:" + connector.getLocalPort());
|
||||
MetaData.Request request = new MetaData.Request(HttpMethod.GET.asString(), HttpScheme.HTTP, hostPort, "/", HttpVersion.HTTP_2, new HttpFields());
|
||||
HeadersFrame frame = new HeadersFrame(request, null, true);
|
||||
clientSession.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter());
|
||||
|
||||
Assert.assertTrue(streamLatch.await(5, TimeUnit.SECONDS));
|
||||
IStream serverStream = streamRef.get();
|
||||
|
||||
int streamSendWindow = serverStream.updateSendWindow(0);
|
||||
Assert.assertEquals(clientStreamRecvWindow, streamSendWindow);
|
||||
int streamRecvWindow = serverStream.updateRecvWindow(0);
|
||||
Assert.assertEquals(serverStreamRecvWindow, streamRecvWindow);
|
||||
}
|
||||
}
|
|
@ -59,6 +59,7 @@ import org.eclipse.jetty.server.HttpConfiguration;
|
|||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.Jetty;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.junit.Assert;
|
||||
|
@ -196,6 +197,49 @@ public class HTTP2Test extends AbstractTest
|
|||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestContentResponseContent() throws Exception
|
||||
{
|
||||
start(new EmptyHttpServlet()
|
||||
{
|
||||
@Override
|
||||
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
IO.copy(request.getInputStream(), response.getOutputStream());
|
||||
}
|
||||
});
|
||||
|
||||
Session session = newClient(new Session.Listener.Adapter());
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
MetaData.Request metaData = newRequest("POST", new HttpFields());
|
||||
HeadersFrame frame = new HeadersFrame(metaData, null, false);
|
||||
Promise.Completable<Stream> streamCompletable = new Promise.Completable<>();
|
||||
session.newStream(frame, streamCompletable, new Stream.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onData(Stream stream, DataFrame frame, Callback callback)
|
||||
{
|
||||
callback.succeeded();
|
||||
if (frame.isEndStream())
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
streamCompletable.thenCompose(stream ->
|
||||
{
|
||||
DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(1024), false);
|
||||
Callback.Completable dataCompletable = new Callback.Completable();
|
||||
stream.data(dataFrame, dataCompletable);
|
||||
return dataCompletable.thenApply(y -> stream);
|
||||
}).thenAccept(stream ->
|
||||
{
|
||||
DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(1024), true);
|
||||
stream.data(dataFrame, Callback.NOOP);
|
||||
});
|
||||
|
||||
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleRequests() throws Exception
|
||||
{
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.eclipse.jetty.http2.frames.DataFrame;
|
|||
import org.eclipse.jetty.http2.frames.Frame;
|
||||
import org.eclipse.jetty.http2.frames.HeadersFrame;
|
||||
import org.eclipse.jetty.http2.frames.SettingsFrame;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -80,16 +81,13 @@ public class InterleavingTest extends AbstractTest
|
|||
}
|
||||
});
|
||||
|
||||
BlockingQueue<FrameBytesCallback> dataFrames = new LinkedBlockingDeque<>();
|
||||
BlockingQueue<DataFrameCallback> dataFrames = new LinkedBlockingDeque<>();
|
||||
Stream.Listener streamListener = new Stream.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onData(Stream stream, DataFrame frame, Callback callback)
|
||||
{
|
||||
ByteBuffer data = frame.getData();
|
||||
byte[] bytes = new byte[data.remaining()];
|
||||
data.get(bytes);
|
||||
dataFrames.offer(new FrameBytesCallback(frame, bytes, callback));
|
||||
dataFrames.offer(new DataFrameCallback(frame, callback));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -146,20 +144,20 @@ public class InterleavingTest extends AbstractTest
|
|||
int finished = 0;
|
||||
while (finished < 2)
|
||||
{
|
||||
FrameBytesCallback frameBytesCallback = dataFrames.poll(5, TimeUnit.SECONDS);
|
||||
if (frameBytesCallback == null)
|
||||
DataFrameCallback dataFrameCallback = dataFrames.poll(5, TimeUnit.SECONDS);
|
||||
if (dataFrameCallback == null)
|
||||
Assert.fail();
|
||||
|
||||
DataFrame dataFrame = frameBytesCallback.frame;
|
||||
DataFrame dataFrame = dataFrameCallback.frame;
|
||||
int streamId = dataFrame.getStreamId();
|
||||
int length = dataFrame.remaining();
|
||||
streamLengths.add(new StreamLength(streamId, length));
|
||||
if (dataFrame.isEndStream())
|
||||
++finished;
|
||||
|
||||
contents.get(streamId).write(frameBytesCallback.bytes);
|
||||
BufferUtil.writeTo(dataFrame.getData(), contents.get(streamId));
|
||||
|
||||
frameBytesCallback.callback.succeeded();
|
||||
dataFrameCallback.callback.succeeded();
|
||||
}
|
||||
|
||||
// Verify that the content has been sent properly.
|
||||
|
@ -197,16 +195,14 @@ public class InterleavingTest extends AbstractTest
|
|||
});
|
||||
}
|
||||
|
||||
private static class FrameBytesCallback
|
||||
private static class DataFrameCallback
|
||||
{
|
||||
private final DataFrame frame;
|
||||
private final byte[] bytes;
|
||||
private final Callback callback;
|
||||
|
||||
private FrameBytesCallback(DataFrame frame, byte[] bytes, Callback callback)
|
||||
private DataFrameCallback(DataFrame frame, Callback callback)
|
||||
{
|
||||
this.frame = frame;
|
||||
this.bytes = bytes;
|
||||
this.callback = callback;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,22 +54,24 @@ public class InvalidServerTest extends AbstractTest
|
|||
}
|
||||
}, promise);
|
||||
|
||||
Socket socket = server.accept();
|
||||
OutputStream output = socket.getOutputStream();
|
||||
output.write("enough_junk_bytes".getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
Session session = promise.get(5, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(session);
|
||||
|
||||
Assert.assertTrue(failureLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
// Verify that the client closed the socket.
|
||||
InputStream input = socket.getInputStream();
|
||||
while (true)
|
||||
try (Socket socket = server.accept())
|
||||
{
|
||||
int read = input.read();
|
||||
if (read < 0)
|
||||
break;
|
||||
OutputStream output = socket.getOutputStream();
|
||||
output.write("enough_junk_bytes".getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
Session session = promise.get(5, TimeUnit.SECONDS);
|
||||
Assert.assertNotNull(session);
|
||||
|
||||
Assert.assertTrue(failureLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
// Verify that the client closed the socket.
|
||||
InputStream input = socket.getInputStream();
|
||||
while (true)
|
||||
{
|
||||
int read = input.read();
|
||||
if (read < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.util.concurrent.CountDownLatch;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
|
@ -165,6 +166,7 @@ public class PrefaceTest extends AbstractTest
|
|||
settings.offer(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
ByteBuffer buffer = byteBufferPool.acquire(1024, true);
|
||||
while (true)
|
||||
|
@ -307,6 +309,7 @@ public class PrefaceTest extends AbstractTest
|
|||
responded.set(true);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
// HTTP/2 parsing.
|
||||
while (true)
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.eclipse.jetty.http2.api.Session;
|
|||
import org.eclipse.jetty.http2.api.Stream;
|
||||
import org.eclipse.jetty.http2.frames.HeadersFrame;
|
||||
import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.ProxyConnectionFactory;
|
||||
|
@ -49,6 +50,7 @@ import org.eclipse.jetty.server.handler.AbstractHandler;
|
|||
import org.eclipse.jetty.util.FuturePromise;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
@ -144,8 +146,12 @@ public class ProxyProtocolTest
|
|||
{
|
||||
Assert.assertEquals("10.0.0.4",request.getRemoteAddr());
|
||||
Assert.assertEquals(33824,request.getRemotePort());
|
||||
Assert.assertEquals("10.0.0.4",request.getLocalAddr());
|
||||
Assert.assertEquals("10.0.0.5",request.getLocalAddr());
|
||||
Assert.assertEquals(8888,request.getLocalPort());
|
||||
EndPoint endPoint = baseRequest.getHttpChannel().getEndPoint();
|
||||
Assert.assertThat(endPoint, Matchers.instanceOf(ProxyConnectionFactory.ProxyEndPoint.class));
|
||||
ProxyConnectionFactory.ProxyEndPoint proxyEndPoint = (ProxyConnectionFactory.ProxyEndPoint)endPoint;
|
||||
Assert.assertNotNull(proxyEndPoint.getAttribute(ProxyConnectionFactory.TLS_VERSION));
|
||||
}
|
||||
catch(Throwable th)
|
||||
{
|
||||
|
@ -156,7 +162,9 @@ public class ProxyProtocolTest
|
|||
}
|
||||
});
|
||||
|
||||
String request1 = "0D0A0D0A000D0A515549540A211100140A0000040A000004842022B82000050000000000";
|
||||
// String is: "MAGIC VER|CMD FAM|PROT LEN SRC_ADDR DST_ADDR SRC_PORT DST_PORT PP2_TYPE_SSL LEN CLIENT VERIFY PP2_SUBTYPE_SSL_VERSION LEN 1.2"
|
||||
String request1 = "0D0A0D0A000D0A515549540A 21 11 001A 0A000004 0A000005 8420 22B8 20 000B 01 00000000 21 0003 312E32";
|
||||
request1 = request1.replace(" ", "");
|
||||
SocketChannel channel = SocketChannel.open();
|
||||
channel.connect(new InetSocketAddress("localhost", connector.getLocalPort()));
|
||||
channel.write(ByteBuffer.wrap(TypeUtil.fromHexString(request1)));
|
||||
|
|
|
@ -263,14 +263,6 @@ public class RawHTTP2ProxyTest
|
|||
Assert.assertTrue(latch2.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
private static DataFrame copyDataFrame(DataFrame frame)
|
||||
{
|
||||
ByteBuffer data = frame.getData();
|
||||
ByteBuffer dataCopy = ByteBuffer.allocate(data.remaining());
|
||||
dataCopy.put(data).flip();
|
||||
return new DataFrame(frame.getStreamId(), dataCopy, frame.isEndStream(), frame.padding());
|
||||
}
|
||||
|
||||
private static class ClientToProxySessionListener extends ServerSessionListener.Adapter
|
||||
{
|
||||
private final Map<Integer, ClientToProxyToServer> forwarders = new ConcurrentHashMap<>();
|
||||
|
@ -505,8 +497,7 @@ public class RawHTTP2ProxyTest
|
|||
{
|
||||
if (LOGGER.isDebugEnabled())
|
||||
LOGGER.debug("CPS received {} on {}", frame, stream);
|
||||
// Must copy the bytes because they are not consumed here.
|
||||
offer(stream, copyDataFrame(frame), callback);
|
||||
offer(stream, frame, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -668,8 +659,7 @@ public class RawHTTP2ProxyTest
|
|||
{
|
||||
if (LOGGER.isDebugEnabled())
|
||||
LOGGER.debug("SPC received {} on {}", frame, stream);
|
||||
// Must copy the bytes because they are not consumed here.
|
||||
offer(stream, copyDataFrame(frame), callback);
|
||||
offer(stream, frame, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -132,23 +132,17 @@ public class StreamCloseTest extends AbstractTest
|
|||
{
|
||||
Assert.assertTrue(((HTTP2Stream)stream).isRemotelyClosed());
|
||||
|
||||
// We must copy the data that we send asynchronously.
|
||||
ByteBuffer data = frame.getData();
|
||||
ByteBuffer copy = ByteBuffer.allocate(data.remaining());
|
||||
copy.put(data).flip();
|
||||
|
||||
completable.thenRun(() ->
|
||||
stream.data(new DataFrame(stream.getId(), copy, frame.isEndStream()), new Callback()
|
||||
{
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
Assert.assertTrue(stream.isClosed());
|
||||
Assert.assertEquals(0, stream.getSession().getStreams().size());
|
||||
callback.succeeded();
|
||||
serverDataLatch.countDown();
|
||||
}
|
||||
}));
|
||||
completable.thenRun(() -> stream.data(frame, new Callback()
|
||||
{
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
Assert.assertTrue(stream.isClosed());
|
||||
Assert.assertEquals(0, stream.getSession().getStreams().size());
|
||||
callback.succeeded();
|
||||
serverDataLatch.countDown();
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -623,7 +623,7 @@ public class StreamResetTest extends AbstractTest
|
|||
}
|
||||
});
|
||||
|
||||
Deque<Object> dataQueue = new ArrayDeque<>();
|
||||
Deque<Callback> dataQueue = new ArrayDeque<>();
|
||||
AtomicLong received = new AtomicLong();
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
Session client = newClient(new Session.Listener.Adapter());
|
||||
|
@ -635,7 +635,6 @@ public class StreamResetTest extends AbstractTest
|
|||
@Override
|
||||
public void onData(Stream stream, DataFrame frame, Callback callback)
|
||||
{
|
||||
dataQueue.offer(frame);
|
||||
dataQueue.offer(callback);
|
||||
// Do not consume the data yet.
|
||||
if (received.addAndGet(frame.getData().remaining()) == windowSize)
|
||||
|
@ -647,10 +646,7 @@ public class StreamResetTest extends AbstractTest
|
|||
|
||||
// Reset and consume.
|
||||
stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
|
||||
dataQueue.stream()
|
||||
.filter(item -> item instanceof Callback)
|
||||
.map(item -> (Callback)item)
|
||||
.forEach(Callback::succeeded);
|
||||
dataQueue.forEach(Callback::succeeded);
|
||||
|
||||
Assert.assertTrue(writeLatch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
|
|
@ -92,6 +92,8 @@ public abstract class AbstractFlowControlStrategy implements FlowControlStrategy
|
|||
this.initialStreamSendWindow = initialStreamWindow;
|
||||
}
|
||||
int delta = initialStreamWindow - previousInitialStreamWindow;
|
||||
if (delta == 0)
|
||||
return;
|
||||
|
||||
// SPEC: updates of the initial window size only affect stream windows, not session's.
|
||||
for (Stream stream : session.getStreams())
|
||||
|
|
|
@ -23,8 +23,18 @@ import java.nio.ByteBuffer;
|
|||
import java.util.ArrayDeque;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.eclipse.jetty.http2.frames.DataFrame;
|
||||
import org.eclipse.jetty.http2.frames.GoAwayFrame;
|
||||
import org.eclipse.jetty.http2.frames.HeadersFrame;
|
||||
import org.eclipse.jetty.http2.frames.PingFrame;
|
||||
import org.eclipse.jetty.http2.frames.PriorityFrame;
|
||||
import org.eclipse.jetty.http2.frames.PushPromiseFrame;
|
||||
import org.eclipse.jetty.http2.frames.ResetFrame;
|
||||
import org.eclipse.jetty.http2.frames.SettingsFrame;
|
||||
import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
|
||||
import org.eclipse.jetty.http2.parser.Parser;
|
||||
import org.eclipse.jetty.io.AbstractConnection;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
|
@ -32,6 +42,7 @@ import org.eclipse.jetty.io.EndPoint;
|
|||
import org.eclipse.jetty.io.WriteFlusher;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.Retainable;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -66,6 +77,7 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher.
|
|||
executor = new TryExecutor.NoTryExecutor(executor);
|
||||
this.strategy = new EatWhatYouKill(producer, executor);
|
||||
LifeCycle.start(strategy);
|
||||
parser.init(ParserListener::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -92,7 +104,8 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher.
|
|||
|
||||
protected void setInputBuffer(ByteBuffer buffer)
|
||||
{
|
||||
producer.buffer = buffer;
|
||||
if (buffer != null)
|
||||
producer.setInputBuffer(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -205,9 +218,16 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher.
|
|||
protected class HTTP2Producer implements ExecutionStrategy.Producer
|
||||
{
|
||||
private final Callback fillableCallback = new FillableCallback();
|
||||
private ByteBuffer buffer;
|
||||
private NetworkBuffer buffer;
|
||||
private boolean shutdown;
|
||||
|
||||
private void setInputBuffer(ByteBuffer byteBuffer)
|
||||
{
|
||||
if (buffer == null)
|
||||
buffer = acquireNetworkBuffer();
|
||||
buffer.put(byteBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Runnable produce()
|
||||
{
|
||||
|
@ -221,38 +241,50 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher.
|
|||
return null;
|
||||
|
||||
if (buffer == null)
|
||||
buffer = byteBufferPool.acquire(bufferSize, false); // TODO: make directness customizable
|
||||
boolean looping = BufferUtil.hasContent(buffer);
|
||||
buffer = acquireNetworkBuffer();
|
||||
boolean parse = buffer.hasRemaining();
|
||||
while (true)
|
||||
{
|
||||
if (looping)
|
||||
if (parse)
|
||||
{
|
||||
buffer.retain();
|
||||
|
||||
while (buffer.hasRemaining())
|
||||
parser.parse(buffer);
|
||||
parser.parse(buffer.buffer);
|
||||
|
||||
boolean released = buffer.tryRelease();
|
||||
|
||||
task = pollTask();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Dequeued new task {}", task);
|
||||
if (task != null)
|
||||
{
|
||||
release();
|
||||
if (released)
|
||||
releaseNetworkBuffer();
|
||||
else
|
||||
buffer = null;
|
||||
return task;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!released)
|
||||
buffer = acquireNetworkBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
int filled = fill(getEndPoint(), buffer);
|
||||
int filled = fill(getEndPoint(), buffer.buffer);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Filled {} bytes", filled);
|
||||
LOG.debug("Filled {} bytes in {}", filled, buffer);
|
||||
|
||||
if (filled == 0)
|
||||
{
|
||||
release();
|
||||
releaseNetworkBuffer();
|
||||
getEndPoint().fillInterested(fillableCallback);
|
||||
return null;
|
||||
}
|
||||
else if (filled < 0)
|
||||
{
|
||||
release();
|
||||
releaseNetworkBuffer();
|
||||
shutdown = true;
|
||||
session.onShutdown();
|
||||
return null;
|
||||
|
@ -260,17 +292,27 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher.
|
|||
else
|
||||
{
|
||||
bytesIn.addAndGet(filled);
|
||||
parse = true;
|
||||
}
|
||||
|
||||
looping = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void release()
|
||||
private NetworkBuffer acquireNetworkBuffer()
|
||||
{
|
||||
if (buffer != null && !buffer.hasRemaining())
|
||||
NetworkBuffer networkBuffer = new NetworkBuffer();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Acquired {}", networkBuffer);
|
||||
return networkBuffer;
|
||||
}
|
||||
|
||||
private void releaseNetworkBuffer()
|
||||
{
|
||||
if (!buffer.hasRemaining())
|
||||
{
|
||||
byteBufferPool.release(buffer);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Released {}", buffer);
|
||||
buffer.release();
|
||||
byteBufferPool.release(buffer.buffer);
|
||||
buffer = null;
|
||||
}
|
||||
}
|
||||
|
@ -302,4 +344,143 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher.
|
|||
return InvocationType.EITHER;
|
||||
}
|
||||
}
|
||||
|
||||
private class ParserListener implements Parser.Listener
|
||||
{
|
||||
private final Parser.Listener listener;
|
||||
|
||||
private ParserListener(Parser.Listener listener)
|
||||
{
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onData(DataFrame frame)
|
||||
{
|
||||
NetworkBuffer buffer = producer.buffer;
|
||||
buffer.retain();
|
||||
Callback callback = buffer;
|
||||
session.onData(frame, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHeaders(HeadersFrame frame)
|
||||
{
|
||||
listener.onHeaders(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPriority(PriorityFrame frame)
|
||||
{
|
||||
listener.onPriority(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReset(ResetFrame frame)
|
||||
{
|
||||
listener.onReset(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSettings(SettingsFrame frame)
|
||||
{
|
||||
listener.onSettings(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPushPromise(PushPromiseFrame frame)
|
||||
{
|
||||
listener.onPushPromise(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPing(PingFrame frame)
|
||||
{
|
||||
listener.onPing(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGoAway(GoAwayFrame frame)
|
||||
{
|
||||
listener.onGoAway(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowUpdate(WindowUpdateFrame frame)
|
||||
{
|
||||
listener.onWindowUpdate(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionFailure(int error, String reason)
|
||||
{
|
||||
listener.onConnectionFailure(error, reason);
|
||||
}
|
||||
}
|
||||
|
||||
private class NetworkBuffer implements Callback, Retainable
|
||||
{
|
||||
private final AtomicInteger refCount = new AtomicInteger();
|
||||
private final ByteBuffer buffer;
|
||||
|
||||
private NetworkBuffer()
|
||||
{
|
||||
buffer = byteBufferPool.acquire(bufferSize, false); // TODO: make directness customizable
|
||||
}
|
||||
|
||||
private void put(ByteBuffer source)
|
||||
{
|
||||
BufferUtil.append(buffer, source);
|
||||
}
|
||||
|
||||
private boolean hasRemaining()
|
||||
{
|
||||
return buffer.hasRemaining();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void retain()
|
||||
{
|
||||
refCount.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InvocationType getInvocationType()
|
||||
{
|
||||
return InvocationType.NON_BLOCKING;
|
||||
}
|
||||
|
||||
private void release()
|
||||
{
|
||||
if (tryRelease())
|
||||
{
|
||||
byteBufferPool.release(buffer);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Released retained {}", this);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tryRelease()
|
||||
{
|
||||
return refCount.decrementAndGet() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x[%s]", getClass().getSimpleName(), hashCode(), buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ import org.eclipse.jetty.util.Atomics;
|
|||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.CountingCallback;
|
||||
import org.eclipse.jetty.util.Promise;
|
||||
import org.eclipse.jetty.util.Retainable;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
|
@ -216,7 +217,13 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onData(final DataFrame frame)
|
||||
public void onData(DataFrame frame)
|
||||
{
|
||||
onData(frame, Callback.NOOP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onData(final DataFrame frame, Callback callback)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Received {}", frame);
|
||||
|
@ -233,39 +240,11 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
{
|
||||
if (getRecvWindow() < 0)
|
||||
{
|
||||
close(ErrorCode.FLOW_CONTROL_ERROR.code, "session_window_exceeded", Callback.NOOP);
|
||||
close(ErrorCode.FLOW_CONTROL_ERROR.code, "session_window_exceeded", callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.process(frame, new Callback()
|
||||
{
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
// Consume also in case of failures, to free the
|
||||
// session flow control window for other streams.
|
||||
complete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InvocationType getInvocationType()
|
||||
{
|
||||
return InvocationType.NON_BLOCKING;
|
||||
}
|
||||
|
||||
private void complete()
|
||||
{
|
||||
notIdle();
|
||||
stream.notIdle();
|
||||
flowControl.onDataConsumed(HTTP2Session.this, stream, flowControlLength);
|
||||
}
|
||||
});
|
||||
stream.process(frame, new DataCallback(callback, stream, flowControlLength));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -275,6 +254,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
// We must enlarge the session flow control window,
|
||||
// otherwise other requests will be stalled.
|
||||
flowControl.onDataConsumed(this, null, flowControlLength);
|
||||
callback.succeeded();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -492,31 +472,36 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
@Override
|
||||
public void newStream(HeadersFrame frame, Promise<Stream> promise, Stream.Listener listener)
|
||||
{
|
||||
// Synchronization is necessary to atomically create
|
||||
// the stream id and enqueue the frame to be sent.
|
||||
boolean queued;
|
||||
synchronized (this)
|
||||
try
|
||||
{
|
||||
int streamId = frame.getStreamId();
|
||||
if (streamId <= 0)
|
||||
// Synchronization is necessary to atomically create
|
||||
// the stream id and enqueue the frame to be sent.
|
||||
boolean queued;
|
||||
synchronized (this)
|
||||
{
|
||||
streamId = streamIds.getAndAdd(2);
|
||||
PriorityFrame priority = frame.getPriority();
|
||||
priority = priority == null ? null : new PriorityFrame(streamId, priority.getParentStreamId(),
|
||||
priority.getWeight(), priority.isExclusive());
|
||||
frame = new HeadersFrame(streamId, frame.getMetaData(), priority, frame.isEndStream());
|
||||
}
|
||||
final IStream stream = createLocalStream(streamId, promise);
|
||||
if (stream == null)
|
||||
return;
|
||||
stream.setListener(listener);
|
||||
int streamId = frame.getStreamId();
|
||||
if (streamId <= 0)
|
||||
{
|
||||
streamId = streamIds.getAndAdd(2);
|
||||
PriorityFrame priority = frame.getPriority();
|
||||
priority = priority == null ? null : new PriorityFrame(streamId, priority.getParentStreamId(),
|
||||
priority.getWeight(), priority.isExclusive());
|
||||
frame = new HeadersFrame(streamId, frame.getMetaData(), priority, frame.isEndStream());
|
||||
}
|
||||
IStream stream = createLocalStream(streamId);
|
||||
stream.setListener(listener);
|
||||
|
||||
ControlEntry entry = new ControlEntry(frame, stream, new PromiseCallback<>(promise, stream));
|
||||
queued = flusher.append(entry);
|
||||
ControlEntry entry = new ControlEntry(frame, stream, new PromiseCallback<>(promise, stream));
|
||||
queued = flusher.append(entry);
|
||||
}
|
||||
// Iterate outside the synchronized block.
|
||||
if (queued)
|
||||
flusher.iterate();
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
promise.failed(x);
|
||||
}
|
||||
// Iterate outside the synchronized block.
|
||||
if (queued)
|
||||
flusher.iterate();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -537,25 +522,30 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
@Override
|
||||
public void push(IStream stream, Promise<Stream> promise, PushPromiseFrame frame, Stream.Listener listener)
|
||||
{
|
||||
// Synchronization is necessary to atomically create
|
||||
// the stream id and enqueue the frame to be sent.
|
||||
boolean queued;
|
||||
synchronized (this)
|
||||
try
|
||||
{
|
||||
int streamId = streamIds.getAndAdd(2);
|
||||
frame = new PushPromiseFrame(frame.getStreamId(), streamId, frame.getMetaData());
|
||||
// Synchronization is necessary to atomically create
|
||||
// the stream id and enqueue the frame to be sent.
|
||||
boolean queued;
|
||||
synchronized (this)
|
||||
{
|
||||
int streamId = streamIds.getAndAdd(2);
|
||||
frame = new PushPromiseFrame(frame.getStreamId(), streamId, frame.getMetaData());
|
||||
|
||||
final IStream pushStream = createLocalStream(streamId, promise);
|
||||
if (pushStream == null)
|
||||
return;
|
||||
pushStream.setListener(listener);
|
||||
IStream pushStream = createLocalStream(streamId);
|
||||
pushStream.setListener(listener);
|
||||
|
||||
ControlEntry entry = new ControlEntry(frame, pushStream, new PromiseCallback<>(promise, pushStream));
|
||||
queued = flusher.append(entry);
|
||||
ControlEntry entry = new ControlEntry(frame, pushStream, new PromiseCallback<>(promise, pushStream));
|
||||
queued = flusher.append(entry);
|
||||
}
|
||||
// Iterate outside the synchronized block.
|
||||
if (queued)
|
||||
flusher.iterate();
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
promise.failed(x);
|
||||
}
|
||||
// Iterate outside the synchronized block.
|
||||
if (queued)
|
||||
flusher.iterate();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -696,17 +686,14 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
}
|
||||
}
|
||||
|
||||
protected IStream createLocalStream(int streamId, Promise<Stream> promise)
|
||||
protected IStream createLocalStream(int streamId)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
int localCount = localStreamCount.get();
|
||||
int maxCount = getMaxLocalStreams();
|
||||
if (maxCount >= 0 && localCount >= maxCount)
|
||||
{
|
||||
promise.failed(new IllegalStateException("Max local stream count " + maxCount + " exceeded"));
|
||||
return null;
|
||||
}
|
||||
throw new IllegalStateException("Max local stream count " + maxCount + " exceeded");
|
||||
if (localStreamCount.compareAndSet(localCount, localCount + 1))
|
||||
break;
|
||||
}
|
||||
|
@ -722,8 +709,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
}
|
||||
else
|
||||
{
|
||||
promise.failed(new IllegalStateException("Duplicate stream " + streamId));
|
||||
return null;
|
||||
throw new IllegalStateException("Duplicate stream " + streamId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1415,6 +1401,50 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
}
|
||||
}
|
||||
|
||||
private class DataCallback extends Callback.Nested implements Retainable
|
||||
{
|
||||
private final IStream stream;
|
||||
private final int flowControlLength;
|
||||
|
||||
public DataCallback(Callback callback, IStream stream, int flowControlLength)
|
||||
{
|
||||
super(callback);
|
||||
this.stream = stream;
|
||||
this.flowControlLength = flowControlLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void retain()
|
||||
{
|
||||
Callback callback = getCallback();
|
||||
if (callback instanceof Retainable)
|
||||
((Retainable)callback).retain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
complete();
|
||||
super.succeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
// Consume also in case of failures, to free the
|
||||
// session flow control window for other streams.
|
||||
complete();
|
||||
super.failed(x);
|
||||
}
|
||||
|
||||
private void complete()
|
||||
{
|
||||
notIdle();
|
||||
stream.notIdle();
|
||||
flowControl.onDataConsumed(HTTP2Session.this, stream, flowControlLength);
|
||||
}
|
||||
}
|
||||
|
||||
private class ResetCallback implements Callback
|
||||
{
|
||||
@Override
|
||||
|
|
|
@ -119,7 +119,7 @@ public interface ISession extends Session
|
|||
*
|
||||
* @see #onShutdown()
|
||||
* @see #close(int, String, Callback)
|
||||
* @return <code>true</code> if the session has expired
|
||||
* @return {@code true} if the session has expired
|
||||
*/
|
||||
public boolean onIdleTimeout();
|
||||
|
||||
|
@ -143,4 +143,12 @@ public interface ISession extends Session
|
|||
* @return the number of bytes written by this session
|
||||
*/
|
||||
public long getBytesWritten();
|
||||
|
||||
/**
|
||||
* <p>Callback method invoked when a DATA frame is received.</p>
|
||||
*
|
||||
* @param frame the DATA frame received
|
||||
* @param callback the callback to notify when the frame has been processed
|
||||
*/
|
||||
public void onData(DataFrame frame, Callback callback);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.http2.parser;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.eclipse.jetty.http2.ErrorCode;
|
||||
import org.eclipse.jetty.http2.Flags;
|
||||
|
@ -49,6 +50,7 @@ public class Parser
|
|||
|
||||
private final Listener listener;
|
||||
private final HeaderParser headerParser;
|
||||
private final HeaderBlockParser headerBlockParser;
|
||||
private final BodyParser[] bodyParsers;
|
||||
private boolean continuation;
|
||||
private State state = State.HEADER;
|
||||
|
@ -57,11 +59,14 @@ public class Parser
|
|||
{
|
||||
this.listener = listener;
|
||||
this.headerParser = new HeaderParser();
|
||||
this.headerBlockParser = new HeaderBlockParser(byteBufferPool, new HpackDecoder(maxDynamicTableSize, maxHeaderSize));
|
||||
this.bodyParsers = new BodyParser[FrameType.values().length];
|
||||
}
|
||||
|
||||
HeaderBlockParser headerBlockParser = new HeaderBlockParser(byteBufferPool, new HpackDecoder(maxDynamicTableSize, maxHeaderSize));
|
||||
public void init(UnaryOperator<Listener> wrapper)
|
||||
{
|
||||
Listener listener = wrapper.apply(this.listener);
|
||||
HeaderBlockFragments headerBlockFragments = new HeaderBlockFragments();
|
||||
|
||||
bodyParsers[FrameType.DATA.getType()] = new DataBodyParser(headerParser, listener);
|
||||
bodyParsers[FrameType.HEADERS.getType()] = new HeadersBodyParser(headerParser, listener, headerBlockParser, headerBlockFragments);
|
||||
bodyParsers[FrameType.PRIORITY.getType()] = new PriorityBodyParser(headerParser, listener);
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.frames;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.eclipse.jetty.http.HostPortHttpField;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
|
@ -61,6 +62,7 @@ public class ContinuationParseTest
|
|||
frames.add(new HeadersFrame(null, null, false));
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
// Iterate a few times to be sure the parser is properly reset.
|
||||
for (int i = 0; i < 2; ++i)
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.eclipse.jetty.http2.generator.DataGenerator;
|
||||
import org.eclipse.jetty.http2.generator.HeaderGenerator;
|
||||
|
@ -98,6 +99,7 @@ public class DataGenerateParseTest
|
|||
frames.add(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
// Iterate a few times to be sure generator and parser are properly reset.
|
||||
for (int i = 0; i < 2; ++i)
|
||||
|
@ -137,6 +139,7 @@ public class DataGenerateParseTest
|
|||
frames.add(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
// Iterate a few times to be sure generator and parser are properly reset.
|
||||
for (int i = 0; i < 2; ++i)
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.eclipse.jetty.http2.generator.GoAwayGenerator;
|
||||
import org.eclipse.jetty.http2.generator.HeaderGenerator;
|
||||
|
@ -49,6 +50,7 @@ public class GoAwayGenerateParseTest
|
|||
frames.add(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
int lastStreamId = 13;
|
||||
int error = 17;
|
||||
|
@ -90,6 +92,7 @@ public class GoAwayGenerateParseTest
|
|||
frames.add(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
int lastStreamId = 13;
|
||||
int error = 17;
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.frames;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.eclipse.jetty.http.HostPortHttpField;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
|
@ -61,6 +62,7 @@ public class HeadersGenerateParseTest
|
|||
frames.add(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
// Iterate a few times to be sure generator and parser are properly reset.
|
||||
for (int i = 0; i < 2; ++i)
|
||||
|
@ -113,6 +115,7 @@ public class HeadersGenerateParseTest
|
|||
frames.add(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
// Iterate a few times to be sure generator and parser are properly reset.
|
||||
for (int i = 0; i < 2; ++i)
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.eclipse.jetty.http2.generator.HeaderGenerator;
|
||||
import org.eclipse.jetty.http2.generator.PingGenerator;
|
||||
|
@ -49,6 +50,7 @@ public class PingGenerateParseTest
|
|||
frames.add(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
byte[] payload = new byte[8];
|
||||
new Random().nextBytes(payload);
|
||||
|
@ -89,6 +91,7 @@ public class PingGenerateParseTest
|
|||
frames.add(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
byte[] payload = new byte[8];
|
||||
new Random().nextBytes(payload);
|
||||
|
@ -129,6 +132,7 @@ public class PingGenerateParseTest
|
|||
frames.add(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
|
||||
PingFrame ping = new PingFrame(System.nanoTime(), true);
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.frames;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.eclipse.jetty.http2.generator.HeaderGenerator;
|
||||
import org.eclipse.jetty.http2.generator.PriorityGenerator;
|
||||
|
@ -48,6 +49,7 @@ public class PriorityGenerateParseTest
|
|||
frames.add(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
int streamId = 13;
|
||||
int parentStreamId = 17;
|
||||
|
@ -92,6 +94,7 @@ public class PriorityGenerateParseTest
|
|||
frames.add(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
int streamId = 13;
|
||||
int parentStreamId = 17;
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.frames;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.eclipse.jetty.http.HostPortHttpField;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
|
@ -55,6 +56,7 @@ public class PushPromiseGenerateParseTest
|
|||
frames.add(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
int streamId = 13;
|
||||
int promisedStreamId = 17;
|
||||
|
@ -107,6 +109,7 @@ public class PushPromiseGenerateParseTest
|
|||
frames.add(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
int streamId = 13;
|
||||
int promisedStreamId = 17;
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.frames;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.eclipse.jetty.http2.generator.HeaderGenerator;
|
||||
import org.eclipse.jetty.http2.generator.ResetGenerator;
|
||||
|
@ -48,6 +49,7 @@ public class ResetGenerateParseTest
|
|||
frames.add(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
int streamId = 13;
|
||||
int error = 17;
|
||||
|
@ -88,6 +90,7 @@ public class ResetGenerateParseTest
|
|||
frames.add(frame);
|
||||
}
|
||||
}, 4096, 8192);
|
||||
parser.init(UnaryOperator.identity());
|
||||
|
||||
int streamId = 13;
|
||||
int error = 17;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue