diff --git a/Jenkinsfile b/Jenkinsfile index d33ebf87c96..5685afe6fad 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -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" } } } diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_101.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_101.mod index d940468a7ff..98e9460dd1a 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_101.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_101.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_102.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_102.mod index d940468a7ff..98e9460dd1a 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_102.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_102.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_111.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_111.mod index d940468a7ff..98e9460dd1a 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_111.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_111.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_112.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_112.mod index e244e3bed3d..8d4ac37b4f4 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_112.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_112.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_121.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_121.mod index 6afa18151a4..7a3a9192362 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_121.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_121.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_131.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_131.mod index 6afa18151a4..7a3a9192362 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_131.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_131.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_141.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_141.mod index 6afa18151a4..7a3a9192362 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_141.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_141.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_144.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_144.mod index 6afa18151a4..7a3a9192362 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_144.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_144.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_151.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_151.mod index 6afa18151a4..7a3a9192362 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_151.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_151.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_152.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_152.mod index 6afa18151a4..7a3a9192362 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_152.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_152.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_161.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_161.mod index e2e91808cd3..00366a87b3d 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_161.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_161.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_162.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_162.mod index e2e91808cd3..00366a87b3d 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_162.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_162.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_171.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_171.mod index e2e91808cd3..00366a87b3d 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_171.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_171.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_172.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_172.mod index e2e91808cd3..00366a87b3d 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_172.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_172.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_40.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_40.mod index 3d5c1aeb044..9ffca1a9699 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_40.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_40.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_45.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_45.mod index 3d5c1aeb044..9ffca1a9699 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_45.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_45.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_51.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_51.mod index 51a8dbb518d..bd6891a07e4 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_51.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_51.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_60.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_60.mod index 4f639da61a1..004663c5e7a 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_60.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_60.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_65.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_65.mod index 80d1541775d..532c440dd42 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_65.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_65.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_66.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_66.mod index 80d1541775d..532c440dd42 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_66.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_66.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_71.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_71.mod index bf0de731394..48de22c2231 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_71.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_71.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_72.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_72.mod index bf0de731394..48de22c2231 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_72.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_72.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_73.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_73.mod index bf0de731394..48de22c2231 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_73.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_73.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_74.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_74.mod index bf0de731394..48de22c2231 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_74.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_74.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_77.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_77.mod index bf0de731394..48de22c2231 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_77.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_77.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_91.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_91.mod index bf0de731394..48de22c2231 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_91.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_91.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_92.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_92.mod index 267aa41ea37..a3677be88e3 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_92.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-1.8.0_92.mod @@ -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 diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-8.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-8.mod index 84454089e27..252d27466af 100644 --- a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-8.mod +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-8.mod @@ -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} diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java index 3d4f9de19aa..16825e704a2 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ContinueProtocolHandler.java @@ -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 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 listeners = exchange.getResponseListeners(); + HttpContentResponse contentResponse = new HttpContentResponse(response, getContent(), getMediaType(), getEncoding()); + notifier.forwardSuccess(listeners, contentResponse); + exchange.proceed(new HttpRequestException("Expectation failed", request)); } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java index 5b431422b3a..813672fb72c 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpReceiver.java @@ -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 = new AtomicReference<>(ResponseState.IDLE); private final HttpChannel channel; + private List 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 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 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 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; } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java b/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java index b3d29143ff6..9bddc6f585d 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/ResponseNotifier.java @@ -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 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 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 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) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java index 3e69c185f75..a73a88ca5a1 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java @@ -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)); } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionPoolTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionPoolTest.java index 80e4dfa0751..56b4bc61bd3 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionPoolTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionPoolTest.java @@ -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; diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java index cf2e355d50e..220b81b5daa 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientTLSTest.java @@ -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)); } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ServerConnectionCloseTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ServerConnectionCloseTest.java index 62536f246a8..5712d0cc6d2 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ServerConnectionCloseTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ServerConnectionCloseTest.java @@ -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 diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/Socks4ProxyTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/Socks4ProxyTest.java index b3f6deddf8b..754bd6aa97e 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/Socks4ProxyTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/Socks4ProxyTest.java @@ -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)); + } } } diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/TLSServerConnectionCloseTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/TLSServerConnectionCloseTest.java index a5d87cb3c14..c6678d1c75f 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/TLSServerConnectionCloseTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/TLSServerConnectionCloseTest.java @@ -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 diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesClientTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesClientTest.java index 83684dd8397..64610fbfb7a 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesClientTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesClientTest.java @@ -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 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 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 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 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 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 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 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 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); + } } } diff --git a/jetty-documentation/pom.xml b/jetty-documentation/pom.xml index 1eafcc6db7a..158664228e1 100644 --- a/jetty-documentation/pom.xml +++ b/jetty-documentation/pom.xml @@ -63,7 +63,7 @@ http://download.eclipse.org/jetty/stable-9/xref ${basedir}/.. https://github.com/eclipse/jetty.project/tree/jetty-9.4.x - http://central.maven.org/maven2 + https://repo1.maven.org/maven2 ${project.version} diff --git a/jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc b/jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc index 0078bfba417..aa8414f5592 100644 --- a/jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/alpn/alpn.adoc @@ -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] diff --git a/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations-embedded.adoc b/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations-embedded.adoc index 6a166b3c88e..a296e879f82 100644 --- a/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations-embedded.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/annotations/using-annotations-embedded.adoc @@ -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 diff --git a/jetty-documentation/src/main/asciidoc/administration/extras/cross-origin-filter.adoc b/jetty-documentation/src/main/asciidoc/administration/extras/cross-origin-filter.adoc index 703a3d72032..bbc4ad75286 100644 --- a/jetty-documentation/src/main/asciidoc/administration/extras/cross-origin-filter.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/extras/cross-origin-filter.adoc @@ -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]] diff --git a/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-datasources.adoc b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-datasources.adoc index 569930f7e36..2eda57495ec 100644 --- a/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-datasources.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-datasources.adoc @@ -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}"] ---- diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/configuring-logging-modules.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-logging-modules.adoc index 4179ef67205..ee4fd3e0d3a 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/configuring-logging-modules.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/configuring-logging-modules.adoc @@ -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 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc index 04c5f6e7ed5..3a943e7d7df 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-apache-log4j.adoc @@ -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 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc index 82ac20a6a8e..124b12dae79 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-java-util-logging.adoc @@ -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 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-centralized-logging.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-centralized-logging.adoc index d0aa9aed14b..4d8382fa24f 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-centralized-logging.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback-centralized-logging.adoc @@ -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 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc index f31c129c7df..b0060639fc8 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-logback.adoc @@ -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 diff --git a/jetty-documentation/src/main/asciidoc/administration/logging/example-slf4j-multiple-loggers.adoc b/jetty-documentation/src/main/asciidoc/administration/logging/example-slf4j-multiple-loggers.adoc index d6556b24ee6..422ec9e7948 100644 --- a/jetty-documentation/src/main/asciidoc/administration/logging/example-slf4j-multiple-loggers.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/logging/example-slf4j-multiple-loggers.adoc @@ -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 diff --git a/jetty-documentation/src/main/asciidoc/administration/runner/jetty-runner.adoc b/jetty-documentation/src/main/asciidoc/administration/runner/jetty-runner.adoc index 4f71f91c496..b019e8c6256 100644 --- a/jetty-documentation/src/main/asciidoc/administration/runner/jetty-runner.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/runner/jetty-runner.adoc @@ -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 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-gcloud.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-gcloud.adoc index 619093b80a2..7360d96082f 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-gcloud.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-gcloud.adoc @@ -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 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-hazelcast.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-hazelcast.adoc index 2eb619ef572..193e7a6d9ae 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-hazelcast.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-hazelcast.adoc @@ -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 diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc index 4787a69bba9..07528662522 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc @@ -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 ---- diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-mongodb.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-mongodb.adoc index f486b0ac941..35c2525cfb2 100644 --- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-mongodb.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-mongodb.adoc @@ -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 ---- diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/custom-modules.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/custom-modules.adoc index 0985657c1a3..e070669d1be 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/custom-modules.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/custom-modules.adoc @@ -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 ---- diff --git a/jetty-documentation/src/main/asciidoc/administration/startup/start-jar.adoc b/jetty-documentation/src/main/asciidoc/administration/startup/start-jar.adoc index 1ec9b20c8a5..2a713497958 100644 --- a/jetty-documentation/src/main/asciidoc/administration/startup/start-jar.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/startup/start-jar.adoc @@ -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/. diff --git a/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl-distribution.adoc b/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl-distribution.adoc index 971cb823f6c..2f482785b0b 100644 --- a/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl-distribution.adoc +++ b/jetty-documentation/src/main/asciidoc/configuring/connectors/configuring-ssl-distribution.adoc @@ -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 diff --git a/jetty-documentation/src/main/asciidoc/development/ant/jetty-ant.adoc b/jetty-documentation/src/main/asciidoc/development/ant/jetty-ant.adoc index ce8ad8f2c2f..5d00fd04109 100644 --- a/jetty-documentation/src/main/asciidoc/development/ant/jetty-ant.adoc +++ b/jetty-documentation/src/main/asciidoc/development/ant/jetty-ant.adoc @@ -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. diff --git a/jetty-documentation/src/main/asciidoc/development/embedding/jetty-helloworld.adoc b/jetty-documentation/src/main/asciidoc/development/embedding/jetty-helloworld.adoc index f5088057bb4..66f9983b52c 100644 --- a/jetty-documentation/src/main/asciidoc/development/embedding/jetty-helloworld.adoc +++ b/jetty-documentation/src/main/asciidoc/development/embedding/jetty-helloworld.adoc @@ -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]] diff --git a/jetty-documentation/src/main/asciidoc/development/frameworks/osgi.adoc b/jetty-documentation/src/main/asciidoc/development/frameworks/osgi.adoc index df45a5fbefb..da23e5dc9e2 100644 --- a/jetty-documentation/src/main/asciidoc/development/frameworks/osgi.adoc +++ b/jetty-documentation/src/main/asciidoc/development/frameworks/osgi.adoc @@ -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] |======================================================================= diff --git a/jetty-documentation/src/main/asciidoc/development/maven/jetty-jspc-maven-plugin.adoc b/jetty-documentation/src/main/asciidoc/development/maven/jetty-jspc-maven-plugin.adoc index 9e1a3134bfb..c387792349d 100644 --- a/jetty-documentation/src/main/asciidoc/development/maven/jetty-jspc-maven-plugin.adoc +++ b/jetty-documentation/src/main/asciidoc/development/maven/jetty-jspc-maven-plugin.adoc @@ -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: diff --git a/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-helloworld.adoc b/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-helloworld.adoc index 7430704d3e5..c700cf1a3e2 100644 --- a/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-helloworld.adoc +++ b/jetty-documentation/src/main/asciidoc/development/maven/jetty-maven-helloworld.adoc @@ -115,7 +115,7 @@ Use an editor to create the file `pom.xml` in the `JettyMavenHelloWorld` directo 9.3.9.v20160517 diff --git a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-common-configuration.adoc b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-common-configuration.adoc index 258ac14e972..607d452694c 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-common-configuration.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-common-configuration.adoc @@ -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 diff --git a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-installing.adoc b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-installing.adoc index 399c7c9e1c2..9ce7f41ffab 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-installing.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/getting-started/jetty-installing.adoc @@ -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. diff --git a/jetty-documentation/src/main/asciidoc/quick-start/introduction/jetty-coordinates.adoc b/jetty-documentation/src/main/asciidoc/quick-start/introduction/jetty-coordinates.adoc index a1fd059b4c8..d64ca85d5bd 100644 --- a/jetty-documentation/src/main/asciidoc/quick-start/introduction/jetty-coordinates.adoc +++ b/jetty-documentation/src/main/asciidoc/quick-start/introduction/jetty-coordinates.adoc @@ -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}"] ---- diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java index 9e7022b35e4..1c5d92c8ebe 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java @@ -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")), diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpComplianceSection.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpComplianceSection.java index d068179cbf1..190a4dea7aa 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpComplianceSection.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpComplianceSection.java @@ -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; diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index 55f4c1ef37a..b8a11df0ab0 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -20,7 +20,6 @@ package org.eclipse.jetty.http; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.util.Arrays; import java.util.EnumSet; import java.util.List; import java.util.Locale; @@ -30,16 +29,12 @@ import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Trie; -import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.Utf8StringBuilder; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import static org.eclipse.jetty.http.HttpTokens.CARRIAGE_RETURN; -import static org.eclipse.jetty.http.HttpTokens.COLON; -import static org.eclipse.jetty.http.HttpTokens.LINE_FEED; -import static org.eclipse.jetty.http.HttpTokens.SPACE; -import static org.eclipse.jetty.http.HttpTokens.TAB; +import static org.eclipse.jetty.http.HttpComplianceSection.MULTIPLE_CONTENT_LENGTHS; +import static org.eclipse.jetty.http.HttpComplianceSection.TRANSFER_ENCODING_WITH_CONTENT_LENGTH; /* ------------------------------------------------------------ */ @@ -92,6 +87,7 @@ public class HttpParser @Deprecated public final static String __STRICT="org.eclipse.jetty.http.HttpParser.STRICT"; public final static int INITIAL_URI_LENGTH=256; + private final static int MAX_CHUNK_LENGTH=Integer.MAX_VALUE/16-16; /** * Cache of common {@link HttpField}s including:
    @@ -172,6 +168,7 @@ public class HttpParser private HttpVersion _version; private Utf8StringBuilder _uri=new Utf8StringBuilder(INITIAL_URI_LENGTH); // Tune? private EndOfContent _endOfContent; + private boolean _hasContentLength; private long _contentLength = -1; private long _contentPosition; private int _chunkLength; @@ -323,6 +320,16 @@ public class HttpParser { return _handler; } + + /* ------------------------------------------------------------------------------- */ + /** Check RFC compliance violation + * @param violation The compliance section violation + * @return True if the current compliance level is set so as to Not allow this violation + */ + protected boolean complianceViolation(HttpComplianceSection violation) + { + return complianceViolation(violation,null); + } /* ------------------------------------------------------------------------------- */ /** Check RFC compliance violation @@ -334,7 +341,8 @@ public class HttpParser { if (_compliances.contains(violation)) return true; - + if (reason==null) + reason=violation.description; if (_complianceHandler!=null) _complianceHandler.onComplianceViolation(_compliance,violation,reason); @@ -446,67 +454,16 @@ public class HttpParser } /* ------------------------------------------------------------------------------- */ - enum CharState { ILLEGAL, CR, LF, LEGAL } - public final static CharState[] TOKEN_CHAR; - static - { - // 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 ) - - TOKEN_CHAR =new CharState[256]; - Arrays.fill(TOKEN_CHAR,CharState.ILLEGAL); - TOKEN_CHAR[LINE_FEED]=CharState.LF; - TOKEN_CHAR[CARRIAGE_RETURN]=CharState.CR; - TOKEN_CHAR[TAB]=CharState.LEGAL; - TOKEN_CHAR[SPACE]=CharState.LEGAL; - - TOKEN_CHAR['!']=CharState.LEGAL; - TOKEN_CHAR['#']=CharState.LEGAL; - TOKEN_CHAR['$']=CharState.LEGAL; - TOKEN_CHAR['%']=CharState.LEGAL; - TOKEN_CHAR['&']=CharState.LEGAL; - TOKEN_CHAR['\'']=CharState.LEGAL; - TOKEN_CHAR['*']=CharState.LEGAL; - TOKEN_CHAR['+']=CharState.LEGAL; - TOKEN_CHAR['-']=CharState.LEGAL; - TOKEN_CHAR['.']=CharState.LEGAL; - TOKEN_CHAR['^']=CharState.LEGAL; - TOKEN_CHAR['_']=CharState.LEGAL; - TOKEN_CHAR['`']=CharState.LEGAL; - TOKEN_CHAR['|']=CharState.LEGAL; - TOKEN_CHAR['~']=CharState.LEGAL; - - TOKEN_CHAR['"']=CharState.LEGAL; - - TOKEN_CHAR['\\']=CharState.LEGAL; - TOKEN_CHAR['(']=CharState.LEGAL; - TOKEN_CHAR[')']=CharState.LEGAL; - Arrays.fill(TOKEN_CHAR,0x21,0x27+1,CharState.LEGAL); - Arrays.fill(TOKEN_CHAR,0x2A,0x5B+1,CharState.LEGAL); - Arrays.fill(TOKEN_CHAR,0x5D,0x7E+1,CharState.LEGAL); - Arrays.fill(TOKEN_CHAR,0x80,0xFF+1,CharState.LEGAL); - - } - - /* ------------------------------------------------------------------------------- */ - private byte next(ByteBuffer buffer) + private HttpTokens.Token next(ByteBuffer buffer) { byte ch = buffer.get(); - CharState s = TOKEN_CHAR[0xff & ch]; - switch(s) + HttpTokens.Token t = HttpTokens.TOKENS[0xff & ch]; + + switch(t.getType()) { - case ILLEGAL: - throw new IllegalCharacterException(_state,ch,buffer); + case CNTL: + throw new IllegalCharacterException(_state,t,buffer); case LF: _cr=false; @@ -525,16 +482,25 @@ public class HttpParser return next(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; + return null; - case LEGAL: + case ALPHA: + case DIGIT: + case TCHAR: + case VCHAR: + case HTAB: + case SPACE: + case OTEXT: + case COLON: if (_cr) throw new BadMessageException("Bad EOL"); + break; + + default: + break; } - return ch; + return t; } /* ------------------------------------------------------------------------------- */ @@ -569,19 +535,30 @@ public class HttpParser // Quick start look while (_state==State.START && buffer.hasRemaining()) { - int ch=next(buffer); - - if (ch > SPACE) - { - _string.setLength(0); - _string.append((char)ch); - setState(_requestHandler!=null?State.METHOD:State.RESPONSE_VERSION); - return false; - } - else if (ch==0) + HttpTokens.Token t = next(buffer); + if (t==null) break; - else if (ch<0) - throw new BadMessageException(); + + switch(t.getType()) + { + case ALPHA: + case DIGIT: + case TCHAR: + case VCHAR: + { + _string.setLength(0); + _string.append(t.getChar()); + setState(_requestHandler!=null?State.METHOD:State.RESPONSE_VERSION); + return false; + } + case OTEXT: + case SPACE: + case HTAB: + throw new IllegalCharacterException(_state,t,buffer); + + default: + break; + } // count this white space as a header byte to avoid DOS if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes) @@ -640,8 +617,8 @@ public class HttpParser while (_state.ordinal()0 && ++_headerBytes>_maxHeaderBytes) @@ -664,255 +641,319 @@ public class HttpParser switch (_state) { case METHOD: - if (b == SPACE) + switch(t.getType()) { - _length=_string.length(); - _methodString=takeString(); + case SPACE: + _length=_string.length(); + _methodString=takeString(); - if (_compliances.contains(HttpComplianceSection.METHOD_CASE_SENSITIVE)) - { - HttpMethod method=HttpMethod.CACHE.get(_methodString); - if (method!=null) - _methodString = method.asString(); - } - else - { - HttpMethod method=HttpMethod.INSENSITIVE_CACHE.get(_methodString); - - if (method!=null) + if (_compliances.contains(HttpComplianceSection.METHOD_CASE_SENSITIVE)) { - if (!method.asString().equals(_methodString)) - handleViolation(HttpComplianceSection.METHOD_CASE_SENSITIVE,_methodString); - _methodString = method.asString(); + HttpMethod method=HttpMethod.CACHE.get(_methodString); + if (method!=null) + _methodString = method.asString(); } - } + else + { + HttpMethod method=HttpMethod.INSENSITIVE_CACHE.get(_methodString); + + if (method!=null) + { + if (!method.asString().equals(_methodString)) + handleViolation(HttpComplianceSection.METHOD_CASE_SENSITIVE,_methodString); + _methodString = method.asString(); + } + } + + setState(State.SPACE1); + break; - setState(State.SPACE1); - } - else if (b < SPACE) - { - if (b==LINE_FEED) + case LF: throw new BadMessageException("No URI"); - else - throw new IllegalCharacterException(_state,b,buffer); + + case ALPHA: + case DIGIT: + case TCHAR: + _string.append(t.getChar()); + break; + + default: + throw new IllegalCharacterException(_state,t,buffer); } - else - _string.append((char)b); break; case RESPONSE_VERSION: - if (b == HttpTokens.SPACE) + switch(t.getType()) { - _length=_string.length(); - String version=takeString(); - _version=HttpVersion.CACHE.get(version); - if (_version==null) - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Unknown Version"); - setState(State.SPACE1); + case SPACE: + _length=_string.length(); + String version=takeString(); + _version=HttpVersion.CACHE.get(version); + checkVersion(); + setState(State.SPACE1); + break; + + case ALPHA: + case DIGIT: + case TCHAR: + case VCHAR: + case COLON: + _string.append(t.getChar()); + break; + default: + throw new IllegalCharacterException(_state,t,buffer); } - else if (b < HttpTokens.SPACE) - throw new IllegalCharacterException(_state,b,buffer); - else - _string.append((char)b); break; case SPACE1: - if (b > HttpTokens.SPACE || b<0) + switch(t.getType()) { - if (_responseHandler!=null) - { - setState(State.STATUS); - setResponseStatus(b-'0'); - } - else - { - _uri.reset(); - setState(State.URI); - // quick scan for space or EoBuffer - if (buffer.hasArray()) + case SPACE: + break; + + case ALPHA: + case DIGIT: + case TCHAR: + case VCHAR: + case COLON: + if (_responseHandler!=null) { - byte[] array=buffer.array(); - int p=buffer.arrayOffset()+buffer.position(); - int l=buffer.arrayOffset()+buffer.limit(); - int i=p; - while (iHttpTokens.SPACE) - i++; - - int len=i-p; - _headerBytes+=len; - - if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes) - { - LOG.warn("URI is too large >"+_maxHeaderBytes); - throw new BadMessageException(HttpStatus.URI_TOO_LONG_414); - } - _uri.append(array,p-1,len+1); - buffer.position(i-buffer.arrayOffset()); + if (t.getType()!=HttpTokens.Type.DIGIT) + throw new IllegalCharacterException(_state,t,buffer); + setState(State.STATUS); + setResponseStatus(t.getByte()-'0'); } else - _uri.append(b); - } - } - else if (b < HttpTokens.SPACE) - { - throw new BadMessageException(HttpStatus.BAD_REQUEST_400,_requestHandler!=null?"No URI":"No Status"); + { + _uri.reset(); + setState(State.URI); + // quick scan for space or EoBuffer + if (buffer.hasArray()) + { + byte[] array=buffer.array(); + int p=buffer.arrayOffset()+buffer.position(); + int l=buffer.arrayOffset()+buffer.limit(); + int i=p; + while (iHttpTokens.SPACE) + i++; + + int len=i-p; + _headerBytes+=len; + + if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes) + { + LOG.warn("URI is too large >"+_maxHeaderBytes); + throw new BadMessageException(HttpStatus.URI_TOO_LONG_414); + } + _uri.append(array,p-1,len+1); + buffer.position(i-buffer.arrayOffset()); + } + else + _uri.append(t.getByte()); + } + break; + + default: + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,_requestHandler!=null?"No URI":"No Status"); } break; case STATUS: - if (b == HttpTokens.SPACE) + switch(t.getType()) { - setState(State.SPACE2); - } - else if (b>='0' && b<='9') - { - _responseStatus=_responseStatus*10+(b-'0'); - } - else if (b < HttpTokens.SPACE && b>=0) - { - setState(State.HEADER); - handle=_responseHandler.startResponse(_version, _responseStatus, null)||handle; - } - else - { - throw new BadMessageException(); + case SPACE: + setState(State.SPACE2); + break; + + case DIGIT: + _responseStatus=_responseStatus*10+(t.getByte()-'0'); + if (_responseStatus>=1000) + throw new BadMessageException("Bad status"); + break; + + case LF: + setState(State.HEADER); + handle=_responseHandler.startResponse(_version, _responseStatus, null)||handle; + break; + + default: + throw new IllegalCharacterException(_state,t,buffer); } break; case URI: - if (b == HttpTokens.SPACE) + switch(t.getType()) { - setState(State.SPACE2); - } - else if (b < HttpTokens.SPACE && b>=0) - { - // HTTP/0.9 - if (complianceViolation(HttpComplianceSection.NO_HTTP_0_9,"No request version")) - throw new BadMessageException("HTTP/0.9 not supported"); - handle=_requestHandler.startRequest(_methodString,_uri.toString(), HttpVersion.HTTP_0_9); - setState(State.END); - BufferUtil.clear(buffer); - handle= handleHeaderContentMessage() || handle; - } - else - { - _uri.append(b); - } - break; - - case SPACE2: - if (b > HttpTokens.SPACE) - { - _string.setLength(0); - _string.append((char)b); - if (_responseHandler!=null) - { - _length=1; - setState(State.REASON); - } - else - { - setState(State.REQUEST_VERSION); - - // try quick look ahead for HTTP Version - HttpVersion version; - if (buffer.position()>0 && buffer.hasArray()) - version=HttpVersion.lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.arrayOffset()+buffer.limit()); - else - version=HttpVersion.CACHE.getBest(buffer,0,buffer.remaining()); - - if (version!=null) - { - int pos = buffer.position()+version.asString().length()-1; - if (pos0 && buffer.hasArray()) + version=HttpVersion.lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.arrayOffset()+buffer.limit()); + else + version=HttpVersion.CACHE.getBest(buffer,0,buffer.remaining()); + + if (version!=null) + { + int pos = buffer.position()+version.asString().length()-1; + if (pos=HttpVersion.HTTP_1_1.getVersion() && _handler.getHeaderCacheSize()>0) - { - int header_cache = _handler.getHeaderCacheSize(); - _fieldCache=new ArrayTernaryTrie<>(header_cache); - } + // Should we try to cache header fields? + if (_fieldCache==null && _version.getVersion()>=HttpVersion.HTTP_1_1.getVersion() && _handler.getHeaderCacheSize()>0) + { + int header_cache = _handler.getHeaderCacheSize(); + _fieldCache=new ArrayTernaryTrie<>(header_cache); + } - setState(State.HEADER); + setState(State.HEADER); - handle=_requestHandler.startRequest(_methodString,_uri.toString(), _version)||handle; - continue; + handle=_requestHandler.startRequest(_methodString,_uri.toString(), _version)||handle; + continue; + + case ALPHA: + case DIGIT: + case TCHAR: + case VCHAR: + case COLON: + _string.append(t.getChar()); + break; + + default: + throw new IllegalCharacterException(_state,t,buffer); } - else if (b>=HttpTokens.SPACE) - _string.append((char)b); - else - throw new BadMessageException(); - break; case REASON: - if (b == HttpTokens.LINE_FEED) + switch(t.getType()) { - String reason=takeString(); - setState(State.HEADER); - handle=_responseHandler.startResponse(_version, _responseStatus, reason)||handle; - continue; - } - else if (b>=HttpTokens.SPACE || ((b<0) && (b>=-96))) - { - _string.append((char)(0xff&b)); - if (b!=' '&&b!='\t') + case LF: + String reason=takeString(); + setState(State.HEADER); + handle=_responseHandler.startResponse(_version, _responseStatus, reason)||handle; + continue; + + case ALPHA: + case DIGIT: + case TCHAR: + case VCHAR: + case COLON: + case OTEXT: // TODO should this be UTF8 + _string.append(t.getChar()); _length=_string.length(); + break; + + case SPACE: + case HTAB: + _string.append(t.getChar()); + break; + + default: + throw new IllegalCharacterException(_state,t,buffer); } - else - throw new BadMessageException(); break; default: @@ -923,6 +964,15 @@ public class HttpParser return handle; } + private void checkVersion() + { + if (_version==null) + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Unknown Version"); + + if (_version.getVersion()<10 || _version.getVersion()>20) + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad Version"); + } + private void parsedHeader() { // handler last header if any. Delayed to here just in case there was a continuation line (above) @@ -935,11 +985,19 @@ public class HttpParser switch (_header) { case CONTENT_LENGTH: - if (_endOfContent == EndOfContent.CONTENT_LENGTH) + if (_hasContentLength) { - throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Duplicate Content-Length"); + if(complianceViolation(MULTIPLE_CONTENT_LENGTHS)) + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,MULTIPLE_CONTENT_LENGTHS.description); + if (convertContentLength(_valueString)!=_contentLength) + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,MULTIPLE_CONTENT_LENGTHS.description); } - else if (_endOfContent != EndOfContent.CHUNKED_CONTENT) + _hasContentLength = true; + + if (_endOfContent == EndOfContent.CHUNKED_CONTENT && complianceViolation(TRANSFER_ENCODING_WITH_CONTENT_LENGTH)) + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad Content-Length"); + + if (_endOfContent != EndOfContent.CHUNKED_CONTENT) { _contentLength=convertContentLength(_valueString); if (_contentLength <= 0) @@ -950,6 +1008,9 @@ public class HttpParser break; case TRANSFER_ENCODING: + if (_hasContentLength && complianceViolation(TRANSFER_ENCODING_WITH_CONTENT_LENGTH)) + throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Transfer-Encoding and Content-Length"); + if (HttpHeaderValue.CHUNKED.is(_valueString)) { _endOfContent=EndOfContent.CHUNKED_CONTENT; @@ -966,6 +1027,8 @@ public class HttpParser else if (values.stream().anyMatch(HttpHeaderValue.CHUNKED::is)) throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Bad chunking"); } + + break; case HOST: @@ -1041,7 +1104,7 @@ public class HttpParser /* ------------------------------------------------------------------------------- */ /* - * Parse the message headers and return true if the handler has signaled for a return + * Parse the message headers and return true if the handler has signalled for a return */ protected boolean parseFields(ByteBuffer buffer) { @@ -1049,8 +1112,8 @@ public class HttpParser while ((_state==State.HEADER || _state==State.TRAILER) && buffer.hasRemaining()) { // process each character - byte b=next(buffer); - if (b==0) + HttpTokens.Token t = next(buffer); + if (t==null) break; if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes) @@ -1065,11 +1128,11 @@ public class HttpParser switch (_fieldState) { case FIELD: - switch(b) + switch(t.getType()) { - case HttpTokens.COLON: - case HttpTokens.SPACE: - case HttpTokens.TAB: + case COLON: + case SPACE: + case HTAB: { if (complianceViolation(HttpComplianceSection.NO_FIELD_FOLDING,_headerString)) throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Header Folding"); @@ -1091,7 +1154,7 @@ public class HttpParser break; } - case HttpTokens.LINE_FEED: + case LF: { // process previous header if (_state==State.HEADER) @@ -1165,7 +1228,9 @@ public class HttpParser } } - default: + case ALPHA: + case DIGIT: + case TCHAR: { // process previous header if (_state==State.HEADER) @@ -1221,52 +1286,50 @@ public class HttpParser buffer.position(buffer.position()+n.length()+1); break; } - else + + // Header and value + int pos=buffer.position()+n.length()+v.length()+1; + byte peek=buffer.get(pos); + if (peek==HttpTokens.CARRIAGE_RETURN || peek==HttpTokens.LINE_FEED) { - // Header and value - int pos=buffer.position()+n.length()+v.length()+1; - byte peek=buffer.get(pos); + _field=cached_field; + _valueString=v; + setState(FieldState.IN_VALUE); - if (peek==HttpTokens.CARRIAGE_RETURN || peek==HttpTokens.LINE_FEED) + if (peek==HttpTokens.CARRIAGE_RETURN) { - _field=cached_field; - _valueString=v; - setState(FieldState.IN_VALUE); - - if (peek==HttpTokens.CARRIAGE_RETURN) - { - _cr=true; - buffer.position(pos+1); - } - else - buffer.position(pos); - break; + _cr=true; + buffer.position(pos+1); } else - { - setState(FieldState.IN_VALUE); - setString(v); buffer.position(pos); - break; - } + break; } + setState(FieldState.IN_VALUE); + setString(v); + buffer.position(pos); + break; } } // New header setState(FieldState.IN_NAME); _string.setLength(0); - _string.append((char)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 SPACE: - case TAB: + case HTAB: //Ignore trailing whitespaces ? if (!complianceViolation(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME,null)) { @@ -1276,7 +1339,7 @@ public class HttpParser setState(FieldState.WS_AFTER_NAME); break; } - throw new IllegalCharacterException(_state,b,buffer); + throw new IllegalCharacterException(_state,t,buffer); case COLON: _headerString=takeString(); @@ -1285,7 +1348,7 @@ public class HttpParser setState(FieldState.VALUE); break; - case LINE_FEED: + case LF: _headerString=takeString(); _header=HttpHeader.CACHE.get(_headerString); _string.setLength(0); @@ -1297,47 +1360,49 @@ public class HttpParser setState(FieldState.FIELD); break; } - throw new IllegalCharacterException(_state,b,buffer); - - default: - if (b<0) - throw new IllegalCharacterException(_state,b,buffer); + throw new IllegalCharacterException(_state,t,buffer); - _string.append((char)b); + case ALPHA: + case DIGIT: + case TCHAR: + _string.append(t.getChar()); _length=_string.length(); break; + + default: + throw new IllegalCharacterException(_state,t,buffer); } break; case WS_AFTER_NAME: - switch(b) + switch(t.getType()) { case SPACE: - case TAB: + case HTAB: break; case COLON: setState(FieldState.VALUE); break; - case LINE_FEED: + case LF: if (!complianceViolation(HttpComplianceSection.FIELD_COLON,_headerString)) { setState(FieldState.FIELD); break; - } - throw new IllegalCharacterException(_state,b,buffer); + } + throw new IllegalCharacterException(_state,t,buffer); 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.setLength(0); _valueString=""; _length=-1; @@ -1346,21 +1411,29 @@ public class HttpParser break; case SPACE: - case TAB: + case HTAB: break; - default: - _string.append((char)(0xff&b)); + case ALPHA: + case DIGIT: + case TCHAR: + case VCHAR: + case COLON: + case OTEXT: // TODO review? should this be a utf8 string? + _string.append(t.getChar()); _length=_string.length(); setState(FieldState.IN_VALUE); - break; + break; + + default: + throw new IllegalCharacterException(_state,t,buffer); } break; case IN_VALUE: - switch(b) + switch(t.getType()) { - case LINE_FEED: + case LF: if (_length > 0) { _valueString=takeString(); @@ -1370,14 +1443,22 @@ public class HttpParser break; case SPACE: - case TAB: - _string.append((char)(0xff&b)); + case HTAB: + _string.append(t.getChar()); break; - - default: - _string.append((char)(0xff&b)); + + case ALPHA: + case DIGIT: + case TCHAR: + case VCHAR: + case COLON: + case OTEXT: // TODO review? should this be a utf8 string? + _string.append(t.getChar()); _length=_string.length(); break; + + default: + throw new IllegalCharacterException(_state,t,buffer); } break; @@ -1599,53 +1680,94 @@ public class HttpParser case CHUNKED_CONTENT: { - ch=next(buffer); - if (ch>HttpTokens.SPACE) + HttpTokens.Token t = next(buffer); + if (t==null) + break; + switch(t.getType()) { - _chunkLength=TypeUtil.convertHexDigit(ch); - _chunkPosition=0; - setState(State.CHUNK_SIZE); + case LF: + break; + + case DIGIT: + _chunkLength=t.getHexDigit(); + _chunkPosition=0; + setState(State.CHUNK_SIZE); + break; + + case ALPHA: + if (t.isHexDigit()) + { + _chunkLength=t.getHexDigit(); + _chunkPosition=0; + setState(State.CHUNK_SIZE); + break; + } + throw new IllegalCharacterException(_state,t,buffer); + + default: + throw new IllegalCharacterException(_state,t,buffer); } - break; } case CHUNK_SIZE: { - ch=next(buffer); - if (ch==0) + HttpTokens.Token t = next(buffer); + if (t==null) break; - if (ch == HttpTokens.LINE_FEED) + + switch(t.getType()) { - if (_chunkLength == 0) - { - setState(State.TRAILER); - if (_handler.contentComplete()) - return true; - } - else - setState(State.CHUNK); + case LF: + if (_chunkLength == 0) + { + setState(State.TRAILER); + if (_handler.contentComplete()) + return true; + } + else + setState(State.CHUNK); + break; + + case SPACE: + setState(State.CHUNK_PARAMS); + break; + + default: + if (t.isHexDigit()) + { + if (_chunkLength>MAX_CHUNK_LENGTH) + throw new BadMessageException(HttpStatus.PAYLOAD_TOO_LARGE_413); + _chunkLength=_chunkLength * 16 + t.getHexDigit(); + } + else + { + setState(State.CHUNK_PARAMS); + } } - else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON) - setState(State.CHUNK_PARAMS); - else - _chunkLength=_chunkLength * 16 + TypeUtil.convertHexDigit(ch); break; } case CHUNK_PARAMS: { - ch=next(buffer); - if (ch == HttpTokens.LINE_FEED) + HttpTokens.Token t = next(buffer); + if (t==null) + break; + + switch(t.getType()) { - if (_chunkLength == 0) - { - setState(State.TRAILER); - if (_handler.contentComplete()) - return true; - } - else - setState(State.CHUNK); + case LF: + if (_chunkLength == 0) + { + setState(State.TRAILER); + if (_handler.contentComplete()) + return true; + } + else + setState(State.CHUNK); + break; + default: + break; // TODO review } break; } @@ -1730,6 +1852,7 @@ public class HttpParser setState(State.START); _endOfContent=EndOfContent.UNKNOWN_CONTENT; _contentLength=-1; + _hasContentLength=false; _contentPosition=0; _responseStatus=0; _contentChunk=null; @@ -1750,7 +1873,7 @@ public class HttpParser protected void setState(FieldState state) { if (DEBUG) - LOG.debug("{}:{} --> {}",_state,_field,state); + LOG.debug("{}:{} --> {}",_state,_field!=null?_field:_headerString!=null?_headerString:_string,state); _fieldState=state; } @@ -1881,11 +2004,11 @@ public class HttpParser @SuppressWarnings("serial") private static class IllegalCharacterException extends BadMessageException { - private IllegalCharacterException(State state,byte ch,ByteBuffer buffer) + private IllegalCharacterException(State state,HttpTokens.Token token,ByteBuffer buffer) { - super(400,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))); } } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java index b65c94d1906..818eb1f3426 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpTokens.java @@ -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); + } + } + } } diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 92ece5b07b5..3b1fb97b1ca 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -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))); } } } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java index 1df966dfbba..1e9de93f45a 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java @@ -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", + "FooBar: value\r\n", + "Foo 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); diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AsyncServletTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AsyncServletTest.java index f2c55ab85d9..92e8f7e2f20 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AsyncServletTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/AsyncServletTest.java @@ -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(); diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStrategyTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStrategyTest.java index 9fc4155f0ab..28862a21795 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStrategyTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlStrategyTest.java @@ -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)); } }; } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlWindowsTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlWindowsTest.java new file mode 100644 index 00000000000..d28e2fb4331 --- /dev/null +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/FlowControlWindowsTest.java @@ -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 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 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 sessionRef = new AtomicReference<>(); + CountDownLatch sessionLatch = new CountDownLatch(1); + AtomicReference 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); + } +} diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java index e977672afeb..9961e799e80 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java @@ -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 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 { diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InterleavingTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InterleavingTest.java index 450647abb88..489cc161870 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InterleavingTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InterleavingTest.java @@ -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 dataFrames = new LinkedBlockingDeque<>(); + BlockingQueue 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; } } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InvalidServerTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InvalidServerTest.java index 7be8f698943..a56cb15c924 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InvalidServerTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/InvalidServerTest.java @@ -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; + } } } } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PrefaceTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PrefaceTest.java index ff2e8b18aec..ba140b6de86 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PrefaceTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/PrefaceTest.java @@ -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) diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyProtocolTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyProtocolTest.java index 765c6ffc877..a5715f1ccc7 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyProtocolTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/ProxyProtocolTest.java @@ -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))); diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/RawHTTP2ProxyTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/RawHTTP2ProxyTest.java index 99b9f198879..26e38bc09cf 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/RawHTTP2ProxyTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/RawHTTP2ProxyTest.java @@ -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 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 diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCloseTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCloseTest.java index 35832f8a3cc..4265d5a422a 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCloseTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamCloseTest.java @@ -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(); + } + })); } }; } diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java index 77d9d9c32f0..c67b71805b6 100644 --- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java +++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/StreamResetTest.java @@ -623,7 +623,7 @@ public class StreamResetTest extends AbstractTest } }); - Deque dataQueue = new ArrayDeque<>(); + Deque 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)); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/AbstractFlowControlStrategy.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/AbstractFlowControlStrategy.java index 52f10e44529..16a0068a8e6 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/AbstractFlowControlStrategy.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/AbstractFlowControlStrategy.java @@ -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()) diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java index db65721cb20..534359990f8 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java @@ -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); + } + } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 6ee22959696..86d4077c3bd 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -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 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 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 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 diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java index 70d8885b7c5..3d74301e125 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/ISession.java @@ -119,7 +119,7 @@ public interface ISession extends Session * * @see #onShutdown() * @see #close(int, String, Callback) - * @return true 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(); + + /** + *

    Callback method invoked when a DATA frame is received.

    + * + * @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); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java index 7ed3827b618..41872115124 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/parser/Parser.java @@ -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 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); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java index 3e72c43ccd3..3f272efefd0 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ContinuationParseTest.java @@ -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) diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java index 784540eab3f..17e26e9c0cd 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/DataGenerateParseTest.java @@ -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) diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java index 23d51c56a09..d9b2e386e79 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/GoAwayGenerateParseTest.java @@ -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; diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java index 5c681dd1ecb..7365c526bca 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/HeadersGenerateParseTest.java @@ -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) diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java index 8a60844dedb..aac8e696ce9 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PingGenerateParseTest.java @@ -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); diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java index 97af2a2813d..5a9b9bffc4c 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PriorityGenerateParseTest.java @@ -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; diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java index cb743a25d96..1e1c214a52f 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/PushPromiseGenerateParseTest.java @@ -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; diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java index 9ecdfa0289e..c61c4638b17 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/ResetGenerateParseTest.java @@ -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; diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java index afeb26f8987..dc652545860 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/SettingsGenerateParseTest.java @@ -25,6 +25,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.UnaryOperator; import org.eclipse.jetty.http2.ErrorCode; import org.eclipse.jetty.http2.generator.HeaderGenerator; @@ -81,6 +82,7 @@ public class SettingsGenerateParseTest 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) @@ -115,6 +117,7 @@ public class SettingsGenerateParseTest errorRef.set(error); } }, 4096, 8192); + parser.init(UnaryOperator.identity()); Map settings1 = new HashMap<>(); settings1.put(13, 17); @@ -149,6 +152,7 @@ public class SettingsGenerateParseTest frames.add(frame); } }, 4096, 8192); + parser.init(UnaryOperator.identity()); Map settings1 = new HashMap<>(); int key = 13; diff --git a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java index 68069d1af8d..ed707e150d2 100644 --- a/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java +++ b/jetty-http2/http2-common/src/test/java/org/eclipse/jetty/http2/frames/WindowUpdateGenerateParseTest.java @@ -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.WindowUpdateGenerator; @@ -48,6 +49,7 @@ public class WindowUpdateGenerateParseTest frames.add(frame); } }, 4096, 8192); + parser.init(UnaryOperator.identity()); int streamId = 13; int windowUpdate = 17; @@ -88,6 +90,7 @@ public class WindowUpdateGenerateParseTest frames.add(frame); } }, 4096, 8192); + parser.init(UnaryOperator.identity()); int streamId = 13; int windowUpdate = 17; diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java index f024d8974ef..90906b3ef74 100644 --- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java +++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2.java @@ -20,7 +20,6 @@ package org.eclipse.jetty.http2.client.http; import java.io.IOException; import java.net.InetSocketAddress; -import java.util.HashMap; import java.util.Map; import org.eclipse.jetty.alpn.client.ALPNClientConnectionFactory; @@ -197,14 +196,6 @@ public class HttpClientTransportOverHTTP2 extends AbstractHttpClientTransport return (Promise)context.get(HTTP_CONNECTION_PROMISE_CONTEXT_KEY); } - @Override - public Map onPreface(Session session) - { - Map settings = new HashMap<>(); - settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, client.getInitialStreamRecvWindow()); - return settings; - } - @Override public void onSettings(Session session, SettingsFrame frame) { diff --git a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java index 627072d0463..8c61824af08 100644 --- a/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java +++ b/jetty-http2/http2-http-client-transport/src/main/java/org/eclipse/jetty/http2/client/http/HttpReceiverOverHTTP2.java @@ -19,7 +19,6 @@ package org.eclipse.jetty.http2.client.http; import java.io.IOException; -import java.nio.ByteBuffer; import java.util.ArrayDeque; import java.util.Collections; import java.util.List; @@ -44,10 +43,9 @@ import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PushPromiseFrame; import org.eclipse.jetty.http2.frames.ResetFrame; -import org.eclipse.jetty.io.ByteBufferPool; -import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.IteratingCallback; +import org.eclipse.jetty.util.Retainable; public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listener { @@ -152,23 +150,12 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen if (exchange == null) { callback.failed(new IOException("terminated")); - return; } - - // We must copy the data since we do not know when the - // application will consume the bytes and the parsing - // will continue as soon as this method returns, eventually - // leading to reusing the underlying buffer for more reads. - ByteBufferPool byteBufferPool = getHttpDestination().getHttpClient().getByteBufferPool(); - ByteBuffer original = frame.getData(); - int length = original.remaining(); - final ByteBuffer copy = byteBufferPool.acquire(length, original.isDirect()); - BufferUtil.clearToFill(copy); - copy.put(original); - BufferUtil.flipToFlush(copy, 0); - - contentNotifier.offer(new DataInfo(exchange, copy, callback, frame.isEndStream())); - contentNotifier.iterate(); + else + { + contentNotifier.offer(new DataInfo(exchange, frame, callback)); + contentNotifier.iterate(); + } } @Override @@ -190,7 +177,7 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen return true; } - private class ContentNotifier extends IteratingCallback + private class ContentNotifier extends IteratingCallback implements Retainable { private final Queue queue = new ArrayDeque<>(); private DataInfo dataInfo; @@ -215,21 +202,27 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen if (dataInfo == null) { DataInfo prevDataInfo = this.dataInfo; - if (prevDataInfo != null && prevDataInfo.last) + if (prevDataInfo != null && prevDataInfo.frame.isEndStream()) return Action.SUCCEEDED; return Action.IDLE; } this.dataInfo = dataInfo; - responseContent(dataInfo.exchange, dataInfo.buffer, this); + responseContent(dataInfo.exchange, dataInfo.frame.getData(), this); return Action.SCHEDULED; } + @Override + public void retain() + { + Callback callback = dataInfo.callback; + if (callback instanceof Retainable) + ((Retainable)callback).retain(); + } + @Override public void succeeded() { - ByteBufferPool byteBufferPool = getHttpDestination().getHttpClient().getByteBufferPool(); - byteBufferPool.release(dataInfo.buffer); dataInfo.callback.succeeded(); super.succeeded(); } @@ -243,8 +236,6 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen @Override protected void onCompleteFailure(Throwable failure) { - ByteBufferPool byteBufferPool = getHttpDestination().getHttpClient().getByteBufferPool(); - byteBufferPool.release(dataInfo.buffer); dataInfo.callback.failed(failure); responseFailure(failure); } @@ -253,16 +244,14 @@ public class HttpReceiverOverHTTP2 extends HttpReceiver implements Stream.Listen private static class DataInfo { private final HttpExchange exchange; - private final ByteBuffer buffer; + private final DataFrame frame; private final Callback callback; - private final boolean last; - private DataInfo(HttpExchange exchange, ByteBuffer buffer, Callback callback, boolean last) + private DataInfo(HttpExchange exchange, DataFrame frame, Callback callback) { this.exchange = exchange; - this.buffer = buffer; + this.frame = frame; this.callback = callback; - this.last = last; } } } diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java index e08ee60b539..c5f6890654f 100644 --- a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java +++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/HttpClientTransportOverHTTP2Test.java @@ -37,6 +37,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.UnaryOperator; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -499,6 +500,7 @@ public class HttpClientTransportOverHTTP2Test extends AbstractTest } } }, 4096, 8192); + parser.init(UnaryOperator.identity()); byte[] bytes = new byte[1024]; while (true) diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java index 2fdb5b9279e..b2cc1ad504e 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/AbstractHTTP2ServerConnectionFactory.java @@ -18,6 +18,8 @@ package org.eclipse.jetty.http2.server; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import org.eclipse.jetty.http2.BufferingFlowControlStrategy; @@ -25,6 +27,7 @@ import org.eclipse.jetty.http2.FlowControlStrategy; import org.eclipse.jetty.http2.HTTP2Connection; import org.eclipse.jetty.http2.api.server.ServerSessionListener; import org.eclipse.jetty.http2.frames.Frame; +import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.http2.generator.Generator; import org.eclipse.jetty.http2.parser.ServerParser; import org.eclipse.jetty.io.Connection; @@ -168,6 +171,18 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne return httpConfiguration; } + protected Map newSettings() + { + Map settings = new HashMap<>(); + settings.put(SettingsFrame.HEADER_TABLE_SIZE, getMaxDynamicTableSize()); + settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, getInitialStreamRecvWindow()); + int maxConcurrentStreams = getMaxConcurrentStreams(); + if (maxConcurrentStreams >= 0) + settings.put(SettingsFrame.MAX_CONCURRENT_STREAMS, maxConcurrentStreams); + settings.put(SettingsFrame.MAX_HEADER_LIST_SIZE, getHttpConfiguration().getRequestHeaderSize()); + return settings; + } + @Override public Connection newConnection(Connector connector, EndPoint endPoint) { diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java index 5a95fb91c5e..eee89bd9b48 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HTTP2ServerConnectionFactory.java @@ -18,7 +18,6 @@ package org.eclipse.jetty.http2.server; -import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; @@ -33,7 +32,6 @@ import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; 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.io.EndPoint; import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.server.Connector; @@ -93,14 +91,7 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF @Override public Map onPreface(Session session) { - Map settings = new HashMap<>(); - settings.put(SettingsFrame.HEADER_TABLE_SIZE, getMaxDynamicTableSize()); - settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, getInitialStreamRecvWindow()); - int maxConcurrentStreams = getMaxConcurrentStreams(); - if (maxConcurrentStreams >= 0) - settings.put(SettingsFrame.MAX_CONCURRENT_STREAMS, maxConcurrentStreams); - settings.put(SettingsFrame.MAX_HEADER_LIST_SIZE, getHttpConfiguration().getRequestHeaderSize()); - return settings; + return newSettings(); } @Override diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java index bfbe7c56195..3e76a2c703f 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpChannelOverHTTP2.java @@ -36,7 +36,6 @@ import org.eclipse.jetty.http2.IStream; import org.eclipse.jetty.http2.api.Stream; import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; -import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.WriteFlusher; import org.eclipse.jetty.server.Connector; @@ -44,7 +43,6 @@ import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpInput; import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -228,40 +226,27 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable, Writ return null; } - // We must copy the data since we do not know when the - // application will consume the bytes (we queue them by - // calling onContent()), and the parsing will continue - // as soon as this method returns, eventually leading - // to reusing the underlying buffer for more reads. - final ByteBufferPool byteBufferPool = getByteBufferPool(); - ByteBuffer original = frame.getData(); - int length = original.remaining(); - final ByteBuffer copy = byteBufferPool.acquire(length, original.isDirect()); - BufferUtil.clearToFill(copy); - copy.put(original); - BufferUtil.flipToFlush(copy, 0); - - boolean handle = onContent(new HttpInput.Content(copy) + ByteBuffer buffer = frame.getData(); + int length = buffer.remaining(); + boolean handle = onContent(new HttpInput.Content(buffer) { - @Override - public InvocationType getInvocationType() - { - return callback.getInvocationType(); - } - @Override public void succeeded() { - byteBufferPool.release(copy); callback.succeeded(); } @Override public void failed(Throwable x) { - byteBufferPool.release(copy); callback.failed(x); } + + @Override + public InvocationType getInvocationType() + { + return callback.getInvocationType(); + } }); boolean endStream = frame.isEndStream(); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java index db0302f440f..7a1c65293b3 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/RawHTTP2ServerConnectionFactory.java @@ -18,7 +18,17 @@ package org.eclipse.jetty.http2.server; +import java.util.Map; +import java.util.Objects; + +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.GoAwayFrame; +import org.eclipse.jetty.http2.frames.HeadersFrame; +import org.eclipse.jetty.http2.frames.PingFrame; +import org.eclipse.jetty.http2.frames.ResetFrame; +import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; @@ -27,15 +37,15 @@ public class RawHTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnecti { private final ServerSessionListener listener; - public RawHTTP2ServerConnectionFactory(HttpConfiguration httpConfiguration,ServerSessionListener listener) + public RawHTTP2ServerConnectionFactory(HttpConfiguration httpConfiguration, ServerSessionListener listener) { super(httpConfiguration); - this.listener = listener; + this.listener = new RawServerSessionListener(Objects.requireNonNull(listener)); } public RawHTTP2ServerConnectionFactory(HttpConfiguration httpConfiguration, ServerSessionListener listener, String... protocols) { - super(httpConfiguration,protocols); + super(httpConfiguration, protocols); this.listener = listener; } @@ -44,4 +54,72 @@ public class RawHTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnecti { return listener; } + + private class RawServerSessionListener implements ServerSessionListener + { + private final ServerSessionListener delegate; + + private RawServerSessionListener(ServerSessionListener delegate) + { + this.delegate = delegate; + } + + @Override + public void onAccept(Session session) + { + delegate.onAccept(session); + } + + @Override + public Map onPreface(Session session) + { + Map settings = newSettings(); + Map moreSettings = delegate.onPreface(session); + if (moreSettings != null) + settings.putAll(moreSettings); + return settings; + } + + @Override + public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) + { + return delegate.onNewStream(stream, frame); + } + + @Override + public void onSettings(Session session, SettingsFrame frame) + { + delegate.onSettings(session, frame); + } + + @Override + public void onPing(Session session, PingFrame frame) + { + delegate.onPing(session, frame); + } + + @Override + public void onReset(Session session, ResetFrame frame) + { + delegate.onReset(session, frame); + } + + @Override + public void onClose(Session session, GoAwayFrame frame) + { + delegate.onClose(session, frame); + } + + @Override + public boolean onIdleTimeout(Session session) + { + return delegate.onIdleTimeout(session); + } + + @Override + public void onFailure(Session session, Throwable failure) + { + delegate.onFailure(session, failure); + } + } } diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java index 5076979259d..f7e50a3aa98 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/CloseTest.java @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.UnaryOperator; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpVersion; @@ -107,6 +108,7 @@ public class CloseTest extends AbstractServerTest } } }, 4096, 8192); + parser.init(UnaryOperator.identity()); parseResponse(client, parser); @@ -163,6 +165,7 @@ public class CloseTest extends AbstractServerTest responseLatch.countDown(); } }, 4096, 8192); + parser.init(UnaryOperator.identity()); parseResponse(client, parser); @@ -231,6 +234,7 @@ public class CloseTest extends AbstractServerTest closeLatch.countDown(); } }, 4096, 8192); + parser.init(UnaryOperator.identity()); parseResponse(client, parser); diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java index c8abb21b002..3a6e8f3d3ac 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2CServerTest.java @@ -30,6 +30,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.UnaryOperator; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpFields; @@ -166,6 +167,7 @@ public class HTTP2CServerTest extends AbstractServerTest latchRef.get().countDown(); } }, 4096, 8192); + parser.init(UnaryOperator.identity()); parseResponse(client, parser); @@ -263,6 +265,7 @@ public class HTTP2CServerTest extends AbstractServerTest latch.countDown(); } }, 4096, 8192); + parser.init(UnaryOperator.identity()); parseResponse(client, parser); diff --git a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java index c39211640c5..5029d396059 100644 --- a/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java +++ b/jetty-http2/http2-server/src/test/java/org/eclipse/jetty/http2/server/HTTP2ServerTest.java @@ -33,6 +33,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 javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -59,7 +60,6 @@ import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ChannelEndPoint; import org.eclipse.jetty.io.ManagedSelector; -import org.eclipse.jetty.io.SelectChannelEndPoint; import org.eclipse.jetty.io.SocketChannelEndPoint; import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.HttpConfiguration; @@ -99,6 +99,7 @@ public class HTTP2ServerTest extends AbstractServerTest latch.countDown(); } }, 4096, 8192); + parser.init(UnaryOperator.identity()); parseResponse(client, parser); @@ -149,6 +150,7 @@ public class HTTP2ServerTest extends AbstractServerTest latch.countDown(); } }, 4096, 8192); + parser.init(UnaryOperator.identity()); parseResponse(client, parser); @@ -214,6 +216,7 @@ public class HTTP2ServerTest extends AbstractServerTest latch.countDown(); } }, 4096, 8192); + parser.init(UnaryOperator.identity()); parseResponse(client, parser); @@ -260,6 +263,7 @@ public class HTTP2ServerTest extends AbstractServerTest latch.countDown(); } }, 4096, 8192); + parser.init(UnaryOperator.identity()); parseResponse(client, parser); @@ -297,6 +301,7 @@ public class HTTP2ServerTest extends AbstractServerTest latch.countDown(); } }, 4096, 8192); + parser.init(UnaryOperator.identity()); parseResponse(client, parser); @@ -363,6 +368,7 @@ public class HTTP2ServerTest extends AbstractServerTest // The server will close the connection abruptly since it // cannot write and therefore cannot even send the GO_AWAY. Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter(), 4096, 8192); + parser.init(UnaryOperator.identity()); boolean closed = parseResponse(client, parser, 2 * delay); Assert.assertTrue(closed); } @@ -397,6 +403,7 @@ public class HTTP2ServerTest extends AbstractServerTest output.flush(); Parser parser = new Parser(byteBufferPool, new Parser.Listener.Adapter(), 4096, 8192); + parser.init(UnaryOperator.identity()); boolean closed = parseResponse(client, parser); Assert.assertTrue(closed); @@ -575,6 +582,7 @@ public class HTTP2ServerTest extends AbstractServerTest clientLatch.countDown(); } }, 4096, 8192); + parser.init(UnaryOperator.identity()); boolean closed = parseResponse(client, parser); Assert.assertTrue(clientLatch.await(5, TimeUnit.SECONDS)); diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java index 9c3381d4f55..ccc70dd6eea 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslClientConnectionFactory.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.io.ssl; import java.io.IOException; import java.util.Map; +import java.util.Objects; import java.util.concurrent.Executor; import javax.net.ssl.SSLEngine; @@ -46,7 +47,7 @@ public class SslClientConnectionFactory implements ClientConnectionFactory public SslClientConnectionFactory(SslContextFactory sslContextFactory, ByteBufferPool byteBufferPool, Executor executor, ClientConnectionFactory connectionFactory) { - this.sslContextFactory = sslContextFactory; + this.sslContextFactory = Objects.requireNonNull(sslContextFactory, "Missing SslContextFactory"); this.byteBufferPool = byteBufferPool; this.executor = executor; this.connectionFactory = connectionFactory; diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java index 21e96e4d3aa..9e055097d91 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/IOTest.java @@ -18,14 +18,6 @@ package org.eclipse.jetty.io; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -52,10 +44,17 @@ import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.OS; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.IO; -import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + public class IOTest { @Test @@ -73,325 +72,312 @@ public class IOTest @Test public void testHalfClose() throws Exception { - ServerSocket connector = new ServerSocket(0); - - Socket client = new Socket("localhost", connector.getLocalPort()); - Socket server = connector.accept(); - - // we can write both ways - client.getOutputStream().write(1); - assertEquals(1, server.getInputStream().read()); - server.getOutputStream().write(1); - assertEquals(1, client.getInputStream().read()); - - // shutdown output results in read -1 - client.shutdownOutput(); - assertEquals(-1, server.getInputStream().read()); - - // Even though EOF has been read, the server input is not seen as shutdown - assertFalse(server.isInputShutdown()); - - // and we can read -1 again - assertEquals(-1, server.getInputStream().read()); - - // but cannot write - try + try (ServerSocket connector = new ServerSocket(0); + Socket client = new Socket("localhost", connector.getLocalPort()); + Socket server = connector.accept()) { + // we can write both ways client.getOutputStream().write(1); - fail("exception expected"); - } - catch (SocketException e) - { - } - - // but can still write in opposite direction. - server.getOutputStream().write(1); - assertEquals(1, client.getInputStream().read()); - - // server can shutdown input to match the shutdown out of client - server.shutdownInput(); - - // now we EOF instead of reading -1 - try - { - server.getInputStream().read(); - fail("exception expected"); - } - catch (SocketException e) - { - } - - // but can still write in opposite direction. - server.getOutputStream().write(1); - assertEquals(1, client.getInputStream().read()); - - // client can shutdown input - client.shutdownInput(); - - // now we EOF instead of reading -1 - try - { - client.getInputStream().read(); - fail("exception expected"); - } - catch (SocketException e) - { - } - - // But we can still write at the server (data which will never be read) - server.getOutputStream().write(1); - - // and the server output is not shutdown - assertFalse(server.isOutputShutdown()); - - // until we explictly shut it down - server.shutdownOutput(); - - // and now we can't write - try - { + assertEquals(1, server.getInputStream().read()); server.getOutputStream().write(1); - fail("exception expected"); + assertEquals(1, client.getInputStream().read()); + + // shutdown output results in read -1 + client.shutdownOutput(); + assertEquals(-1, server.getInputStream().read()); + + // Even though EOF has been read, the server input is not seen as shutdown + assertFalse(server.isInputShutdown()); + + // and we can read -1 again + assertEquals(-1, server.getInputStream().read()); + + // but cannot write + try + { + client.getOutputStream().write(1); + fail("exception expected"); + } + catch (SocketException expected) + { + } + + // but can still write in opposite direction. + server.getOutputStream().write(1); + assertEquals(1, client.getInputStream().read()); + + // server can shutdown input to match the shutdown out of client + server.shutdownInput(); + + // now we EOF instead of reading -1 + try + { + server.getInputStream().read(); + fail("exception expected"); + } + catch (SocketException expected) + { + } + + // but can still write in opposite direction. + server.getOutputStream().write(1); + assertEquals(1, client.getInputStream().read()); + + // client can shutdown input + client.shutdownInput(); + + // now we EOF instead of reading -1 + try + { + client.getInputStream().read(); + fail("exception expected"); + } + catch (SocketException expected) + { + } + + // But we can still write at the server (data which will never be read) + server.getOutputStream().write(1); + + // and the server output is not shutdown + assertFalse(server.isOutputShutdown()); + + // until we explictly shut it down + server.shutdownOutput(); + + // and now we can't write + try + { + server.getOutputStream().write(1); + fail("exception expected"); + } + catch (SocketException expected) + { + } + + // but the sockets are still open + assertFalse(client.isClosed()); + assertFalse(server.isClosed()); + + // but if we close one end + client.close(); + + // it is seen as closed. + assertTrue(client.isClosed()); + + // but not the other end + assertFalse(server.isClosed()); + + // which has to be closed explictly + server.close(); + assertTrue(server.isClosed()); } - catch (SocketException e) - { - } - - // but the sockets are still open - assertFalse(client.isClosed()); - assertFalse(server.isClosed()); - - // but if we close one end - client.close(); - - // it is seen as closed. - assertTrue(client.isClosed()); - - // but not the other end - assertFalse(server.isClosed()); - - // which has to be closed explictly - server.close(); - assertTrue(server.isClosed()); } @Test public void testHalfCloseClientServer() throws Exception { - ServerSocketChannel connector = ServerSocketChannel.open(); - connector.socket().bind(null); - - Socket client = SocketChannel.open(connector.socket().getLocalSocketAddress()).socket(); - client.setSoTimeout(1000); - client.setSoLinger(false, -1); - Socket server = connector.accept().socket(); - server.setSoTimeout(1000); - server.setSoLinger(false, -1); - - // Write from client to server - client.getOutputStream().write(1); - - // Server reads - assertEquals(1, server.getInputStream().read()); - - // Write from server to client with oshut - server.getOutputStream().write(1); - // System.err.println("OSHUT "+server); - server.shutdownOutput(); - - // Client reads response - assertEquals(1, client.getInputStream().read()); - - try + try (ServerSocketChannel connector = ServerSocketChannel.open()) { - // Client reads -1 and does ishut - assertEquals(-1, client.getInputStream().read()); - assertFalse(client.isInputShutdown()); - //System.err.println("ISHUT "+client); - client.shutdownInput(); - - // Client ??? - //System.err.println("OSHUT "+client); - client.shutdownOutput(); - //System.err.println("CLOSE "+client); - client.close(); - - // Server reads -1, does ishut and then close - assertEquals(-1, server.getInputStream().read()); - assertFalse(server.isInputShutdown()); - //System.err.println("ISHUT "+server); - - try + connector.socket().bind(null); + try (Socket client = SocketChannel.open(connector.socket().getLocalSocketAddress()).socket()) { - server.shutdownInput(); - } - catch (SocketException e) - { - // System.err.println(e); - } - //System.err.println("CLOSE "+server); - server.close(); + client.setSoTimeout(1000); + client.setSoLinger(false, -1); + try (Socket server = connector.accept().socket()) + { + server.setSoTimeout(1000); + server.setSoLinger(false, -1); - } - catch (Exception e) - { - System.err.println(e); - assertTrue(OS.IS_OSX); + // Write from client to server + client.getOutputStream().write(1); + + // Server reads + assertEquals(1, server.getInputStream().read()); + + // Write from server to client with oshut + server.getOutputStream().write(1); + // System.err.println("OSHUT "+server); + server.shutdownOutput(); + + // Client reads response + assertEquals(1, client.getInputStream().read()); + + try + { + // Client reads -1 and does ishut + assertEquals(-1, client.getInputStream().read()); + assertFalse(client.isInputShutdown()); + //System.err.println("ISHUT "+client); + client.shutdownInput(); + + // Client ??? + //System.err.println("OSHUT "+client); + client.shutdownOutput(); + //System.err.println("CLOSE "+client); + client.close(); + + // Server reads -1, does ishut and then close + assertEquals(-1, server.getInputStream().read()); + assertFalse(server.isInputShutdown()); + //System.err.println("ISHUT "+server); + + server.shutdownInput(); + server.close(); + } + catch (Exception e) + { + e.printStackTrace(); + assertTrue(OS.IS_OSX); + } + } + } } } @Test public void testHalfCloseBadClient() throws Exception { - ServerSocketChannel connector = ServerSocketChannel.open(); - connector.socket().bind(null); - - Socket client = SocketChannel.open(connector.socket().getLocalSocketAddress()).socket(); - client.setSoTimeout(1000); - client.setSoLinger(false, -1); - Socket server = connector.accept().socket(); - server.setSoTimeout(1000); - server.setSoLinger(false, -1); - - // Write from client to server - client.getOutputStream().write(1); - - // Server reads - assertEquals(1, server.getInputStream().read()); - - // Write from server to client with oshut - server.getOutputStream().write(1); - //System.err.println("OSHUT "+server); - server.shutdownOutput(); - - try + try (ServerSocketChannel connector = ServerSocketChannel.open()) { - // Client reads response - assertEquals(1, client.getInputStream().read()); + connector.socket().bind(null); - // Client reads -1 - assertEquals(-1, client.getInputStream().read()); - assertFalse(client.isInputShutdown()); - - // Client can still write as we are half closed - client.getOutputStream().write(1); - - // Server can still read - assertEquals(1, server.getInputStream().read()); - - // Server now closes - server.close(); - - // Client still reads -1 (not broken pipe !!) - assertEquals(-1, client.getInputStream().read()); - assertFalse(client.isInputShutdown()); - - Thread.sleep(100); - - // Client still reads -1 (not broken pipe !!) - assertEquals(-1, client.getInputStream().read()); - assertFalse(client.isInputShutdown()); - - // Client can still write data even though server is closed??? - client.getOutputStream().write(1); - - // Client eventually sees Broken Pipe - int i = 0; - try + try (Socket client = SocketChannel.open(connector.socket().getLocalSocketAddress()).socket()) { - for (i = 0; i < 100000; i++) + client.setSoTimeout(1000); + client.setSoLinger(false, -1); + try (Socket server = connector.accept().socket()) + { + server.setSoTimeout(1000); + server.setSoLinger(false, -1); + + // Write from client to server client.getOutputStream().write(1); - Assert.fail(); - } - catch (IOException e) - { - } - client.close(); + // Server reads + assertEquals(1, server.getInputStream().read()); - } - catch (Exception e) - { - System.err.println("PLEASE INVESTIGATE:"); - e.printStackTrace(); + // Write from server to client with oshut + server.getOutputStream().write(1); + //System.err.println("OSHUT "+server); + server.shutdownOutput(); + + // Client reads response + assertEquals(1, client.getInputStream().read()); + + // Client reads -1 + assertEquals(-1, client.getInputStream().read()); + assertFalse(client.isInputShutdown()); + + // Client can still write as we are half closed + client.getOutputStream().write(1); + + // Server can still read + assertEquals(1, server.getInputStream().read()); + + // Server now closes + server.close(); + + // Client still reads -1 (not broken pipe !!) + assertEquals(-1, client.getInputStream().read()); + assertFalse(client.isInputShutdown()); + + Thread.sleep(100); + + // Client still reads -1 (not broken pipe !!) + assertEquals(-1, client.getInputStream().read()); + assertFalse(client.isInputShutdown()); + + // Client can still write data even though server is closed??? + client.getOutputStream().write(1); + + // Client eventually sees Broken Pipe + try + { + for (int i = 0; i < 100000; i++) + client.getOutputStream().write(1); + Assert.fail(); + } + catch (IOException expected) + { + } + } + } } } @Test public void testServerChannelInterrupt() throws Exception { - final ServerSocketChannel connector = ServerSocketChannel.open(); - connector.configureBlocking(true); - connector.socket().bind(null); - - Socket client = SocketChannel.open(connector.socket().getLocalSocketAddress()).socket(); - client.setSoTimeout(2000); - client.setSoLinger(false, -1); - Socket server = connector.accept().socket(); - server.setSoTimeout(2000); - server.setSoLinger(false, -1); - - // Write from client to server - client.getOutputStream().write(1); - // Server reads - assertEquals(1, server.getInputStream().read()); - - // Write from server to client - server.getOutputStream().write(1); - // Client reads - assertEquals(1, client.getInputStream().read()); - - - // block a thread in accept - final CountDownLatch alatch=new CountDownLatch(2); - Thread acceptor = new Thread() + try (ServerSocketChannel connector = ServerSocketChannel.open()) { - @Override - public void run() + connector.configureBlocking(true); + connector.socket().bind(null); + try (Socket client = SocketChannel.open(connector.socket().getLocalSocketAddress()).socket()) { - try + client.setSoTimeout(2000); + client.setSoLinger(false, -1); + try (Socket server = connector.accept().socket()) { - alatch.countDown(); - connector.accept(); - } - catch (Throwable e) - { - } - finally - { - alatch.countDown(); + server.setSoTimeout(2000); + server.setSoLinger(false, -1); + + // Write from client to server + client.getOutputStream().write(1); + // Server reads + assertEquals(1, server.getInputStream().read()); + + // Write from server to client + server.getOutputStream().write(1); + // Client reads + assertEquals(1, client.getInputStream().read()); + + // block a thread in accept + final CountDownLatch latch = new CountDownLatch(2); + Thread acceptor = new Thread(() -> + { + try + { + latch.countDown(); + connector.accept(); + } + catch (Throwable ignored) + { + } + finally + { + latch.countDown(); + } + }); + acceptor.start(); + while (latch.getCount() == 2) + Thread.sleep(10); + + // interrupt the acceptor + acceptor.interrupt(); + + // wait for acceptor to exit + assertTrue(latch.await(10, TimeUnit.SECONDS)); + + // connector is closed + assertFalse(connector.isOpen()); + + // but connection is still open + assertFalse(client.isClosed()); + assertFalse(server.isClosed()); + + // Write from client to server + client.getOutputStream().write(42); + // Server reads + assertEquals(42, server.getInputStream().read()); + + // Write from server to client + server.getOutputStream().write(43); + // Client reads + assertEquals(43, client.getInputStream().read()); } } - }; - acceptor.start(); - while (alatch.getCount()==2) - Thread.sleep(10); - - // interrupt the acceptor - acceptor.interrupt(); - - // wait for acceptor to exit - assertTrue(alatch.await(10,TimeUnit.SECONDS)); - - // connector is closed - assertFalse(connector.isOpen()); - - // but connection is still open - assertFalse(client.isClosed()); - assertFalse(server.isClosed()); - - // Write from client to server - client.getOutputStream().write(42); - // Server reads - assertEquals(42, server.getInputStream().read()); - - // Write from server to client - server.getOutputStream().write(43); - // Client reads - assertEquals(43, client.getInputStream().read()); - - client.close(); - + } } @@ -401,7 +387,7 @@ public class IOTest { try (ServerSocket connector = new ServerSocket(0); Socket client = new Socket("127.0.0.1", connector.getLocalPort()); - Socket server = connector.accept();) + Socket server = connector.accept()) { client.setTcpNoDelay(true); client.setSoLinger(true, 0); @@ -430,8 +416,8 @@ public class IOTest assertEquals(-1, server.getInputStream().read()); server.shutdownInput(); - // Since output was already shutdown, server closes - server.close(); + // Since output was already shutdown, server + // closes in the try-with-resources block end. } } @@ -490,52 +476,48 @@ public class IOTest assertEquals(expected,wrote); - for (int i=0;i { - Thread.sleep(100); - selector.wakeup(); - } - catch(Exception e) - { - e.printStackTrace(); - } + try + { + Thread.sleep(100); + selector.wakeup(); + } + catch (Exception e) + { + e.printStackTrace(); + } + }).start(); + assertThat(selector.select(), is(0)); } - - }.start(); - assertThat(selector.select(), is(0)); + } } } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/NIOTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/NIOTest.java index 11ac5f4a018..41fa75b364f 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/NIOTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/NIOTest.java @@ -18,10 +18,6 @@ package org.eclipse.jetty.io; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - import java.net.ServerSocket; import java.net.Socket; import java.nio.ByteBuffer; @@ -31,106 +27,105 @@ import java.nio.channels.SocketChannel; import org.junit.Test; -/** - * - */ +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + public class NIOTest { @Test public void testSelector() throws Exception { - ServerSocket acceptor = new ServerSocket(0); + try (ServerSocket acceptor = new ServerSocket(0); + Selector selector = Selector.open(); + SocketChannel client = SocketChannel.open(acceptor.getLocalSocketAddress()); + Socket server = acceptor.accept()) + { + server.setTcpNoDelay(true); - Selector selector = Selector.open(); + // Make the client non blocking and register it with selector for reads + client.configureBlocking(false); + SelectionKey key = client.register(selector, SelectionKey.OP_READ); - // Create client server socket pair - SocketChannel client = SocketChannel.open(acceptor.getLocalSocketAddress()); - Socket server = acceptor.accept(); - server.setTcpNoDelay(true); + // assert it is not selected + assertTrue(key.isValid()); + assertFalse(key.isReadable()); + assertEquals(0, key.readyOps()); - // Make the client non blocking and register it with selector for reads - client.configureBlocking(false); - SelectionKey key = client.register(selector,SelectionKey.OP_READ); + // try selecting and assert nothing selected + int selected = selector.selectNow(); + assertEquals(0, selected); + assertEquals(0, selector.selectedKeys().size()); + assertTrue(key.isValid()); + assertFalse(key.isReadable()); + assertEquals(0, key.readyOps()); - // assert it is not selected - assertTrue(key.isValid()); - assertFalse(key.isReadable()); - assertEquals(0,key.readyOps()); + // Write a byte from server to client + server.getOutputStream().write(42); + server.getOutputStream().flush(); - // try selecting and assert nothing selected - int selected = selector.selectNow(); - assertEquals(0,selected); - assertEquals(0,selector.selectedKeys().size()); - assertTrue(key.isValid()); - assertFalse(key.isReadable()); - assertEquals(0,key.readyOps()); + // select again and assert selection found for read + selected = selector.select(1000); + assertEquals(1, selected); + assertEquals(1, selector.selectedKeys().size()); + assertTrue(key.isValid()); + assertTrue(key.isReadable()); + assertEquals(1, key.readyOps()); - // Write a byte from server to client - server.getOutputStream().write(42); - server.getOutputStream().flush(); + // select again and see that it is not reselect, but stays selected + selected = selector.select(100); + assertEquals(0, selected); + assertEquals(1, selector.selectedKeys().size()); + assertTrue(key.isValid()); + assertTrue(key.isReadable()); + assertEquals(1, key.readyOps()); - // select again and assert selection found for read - selected = selector.select(1000); - assertEquals(1,selected); - assertEquals(1,selector.selectedKeys().size()); - assertTrue(key.isValid()); - assertTrue(key.isReadable()); - assertEquals(1,key.readyOps()); + // read the byte + ByteBuffer buf = ByteBuffer.allocate(1024); + int len = client.read(buf); + assertEquals(1, len); + buf.flip(); + assertEquals(42, buf.get()); + buf.clear(); - // select again and see that it is not reselect, but stays selected - selected = selector.select(100); - assertEquals(0,selected); - assertEquals(1,selector.selectedKeys().size()); - assertTrue(key.isValid()); - assertTrue(key.isReadable()); - assertEquals(1,key.readyOps()); + // But this does not change the key + assertTrue(key.isValid()); + assertTrue(key.isReadable()); + assertEquals(1, key.readyOps()); - // read the byte - ByteBuffer buf = ByteBuffer.allocate(1024); - int len=client.read(buf); - assertEquals(1,len); - buf.flip(); - assertEquals(42,buf.get()); - buf.clear(); + // Even if we select again ? + selected = selector.select(100); + assertEquals(0, selected); + assertEquals(1, selector.selectedKeys().size()); + assertTrue(key.isValid()); + assertTrue(key.isReadable()); + assertEquals(1, key.readyOps()); - // But this does not change the key - assertTrue(key.isValid()); - assertTrue(key.isReadable()); - assertEquals(1,key.readyOps()); + // Unless we remove the key from the select set + // and then it is still flagged as isReadable() + selector.selectedKeys().clear(); + assertEquals(0, selector.selectedKeys().size()); + assertTrue(key.isValid()); + assertTrue(key.isReadable()); + assertEquals(1, key.readyOps()); - // Even if we select again ? - selected = selector.select(100); - assertEquals(0,selected); - assertEquals(1,selector.selectedKeys().size()); - assertTrue(key.isValid()); - assertTrue(key.isReadable()); - assertEquals(1,key.readyOps()); + // Now if we select again - it is still flagged as readable!!! + selected = selector.select(100); + assertEquals(0, selected); + assertEquals(0, selector.selectedKeys().size()); + assertTrue(key.isValid()); + assertTrue(key.isReadable()); + assertEquals(1, key.readyOps()); - // Unless we remove the key from the select set - // and then it is still flagged as isReadable() - selector.selectedKeys().clear(); - assertEquals(0,selector.selectedKeys().size()); - assertTrue(key.isValid()); - assertTrue(key.isReadable()); - assertEquals(1,key.readyOps()); - - // Now if we select again - it is still flagged as readable!!! - selected = selector.select(100); - assertEquals(0,selected); - assertEquals(0,selector.selectedKeys().size()); - assertTrue(key.isValid()); - assertTrue(key.isReadable()); - assertEquals(1,key.readyOps()); - - // Only when it is selected for something else does that state change. - key.interestOps(SelectionKey.OP_READ|SelectionKey.OP_WRITE); - selected = selector.select(1000); - assertEquals(1,selected); - assertEquals(1,selector.selectedKeys().size()); - assertTrue(key.isValid()); - assertTrue(key.isWritable()); - assertFalse(key.isReadable()); - assertEquals(SelectionKey.OP_WRITE,key.readyOps()); + // Only when it is selected for something else does that state change. + key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); + selected = selector.select(1000); + assertEquals(1, selected); + assertEquals(1, selector.selectedKeys().size()); + assertTrue(key.isValid()); + assertTrue(key.isWritable()); + assertFalse(key.isReadable()); + assertEquals(SelectionKey.OP_WRITE, key.readyOps()); + } } - } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointInterestsTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointInterestsTest.java index 04e17c9e4a0..f6503d559e4 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointInterestsTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointInterestsTest.java @@ -65,7 +65,7 @@ public class SocketChannelEndPointInterestsTest { @Override - protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey key) throws IOException + protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey key) { SocketChannelEndPoint endp = new SocketChannelEndPoint(channel, selector, key, getScheduler()) { @@ -176,36 +176,37 @@ public class SocketChannelEndPointInterestsTest } }); - Socket client = new Socket(); - client.connect(connector.getLocalAddress()); - client.setSoTimeout(5000); + try (Socket client = new Socket()) + { + client.connect(connector.getLocalAddress()); + client.setSoTimeout(5000); + try (SocketChannel server = connector.accept()) + { + server.configureBlocking(false); + selectorManager.accept(server); - SocketChannel server = connector.accept(); - server.configureBlocking(false); - selectorManager.accept(server); + OutputStream clientOutput = client.getOutputStream(); + clientOutput.write(1); + clientOutput.flush(); + Assert.assertTrue(latch1.await(5, TimeUnit.SECONDS)); - OutputStream clientOutput = client.getOutputStream(); - clientOutput.write(1); - clientOutput.flush(); - Assert.assertTrue(latch1.await(5, TimeUnit.SECONDS)); + // We do not read to keep the socket write blocked - // We do not read to keep the socket write blocked + clientOutput.write(2); + clientOutput.flush(); + Assert.assertTrue(latch2.await(5, TimeUnit.SECONDS)); - clientOutput.write(2); - clientOutput.flush(); - Assert.assertTrue(latch2.await(5, TimeUnit.SECONDS)); + // Sleep before reading to allow waking up the server only for read + Thread.sleep(1000); - // Sleep before reading to allow waking up the server only for read - Thread.sleep(1000); + // Now read what was written, waking up the server for write + InputStream clientInput = client.getInputStream(); + while (size.getAndDecrement() > 0) + clientInput.read(); - // Now read what was written, waking up the server for write - InputStream clientInput = client.getInputStream(); - while (size.getAndDecrement() > 0) - clientInput.read(); - - client.close(); - - Assert.assertNull(failure.get()); + Assert.assertNull(failure.get()); + } + } } private interface Interested @@ -214,5 +215,4 @@ public class SocketChannelEndPointInterestsTest void onIncompleteFlush(); } - } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointTest.java index 017104b7954..0645430f1a4 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SocketChannelEndPointTest.java @@ -18,13 +18,6 @@ package org.eclipse.jetty.io; -import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; - import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; @@ -73,6 +66,13 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + @SuppressWarnings("Duplicates") @RunWith(Parameterized.class) public class SocketChannelEndPointTest @@ -143,60 +143,61 @@ public class SocketChannelEndPointTest @Test public void testEcho() throws Exception { - Socket client = _scenario.newClient(_connector); - - client.setSoTimeout(60000); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - - _manager.accept(server); - - // Write client to server - client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); - - // Verify echo server to client - for (char c : "HelloWorld".toCharArray()) + try (Socket client = _scenario.newClient(_connector)) { - int b = client.getInputStream().read(); - assertTrue(b > 0); - assertEquals(c, (char) b); - } + client.setSoTimeout(60000); + try (SocketChannel server = _connector.accept()) + { + server.configureBlocking(false); + _manager.accept(server); - // wait for read timeout - client.setSoTimeout(500); - long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - try - { - client.getInputStream().read(); - Assert.fail(); - } - catch (SocketTimeoutException e) - { - long duration = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start; - Assert.assertThat("timeout duration", duration, greaterThanOrEqualTo(400L)); - } + // Write client to server + client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); - // write then shutdown - client.getOutputStream().write("Goodbye Cruel TLS".getBytes(StandardCharsets.UTF_8)); + // Verify echo server to client + for (char c : "HelloWorld".toCharArray()) + { + int b = client.getInputStream().read(); + assertTrue(b > 0); + assertEquals(c, (char)b); + } - // Verify echo server to client - for (char c : "Goodbye Cruel TLS".toCharArray()) - { - int b = client.getInputStream().read(); - Assert.assertThat("expect valid char integer", b, greaterThan(0)); - assertEquals("expect characters to be same", c, (char) b); - } - client.close(); + // wait for read timeout + client.setSoTimeout(500); + long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + try + { + client.getInputStream().read(); + Assert.fail(); + } + catch (SocketTimeoutException e) + { + long duration = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start; + Assert.assertThat("timeout duration", duration, greaterThanOrEqualTo(400L)); + } - for (int i = 0; i < 10; ++i) - { - if (server.isOpen()) - Thread.sleep(10); - else - break; + // write then shutdown + client.getOutputStream().write("Goodbye Cruel TLS".getBytes(StandardCharsets.UTF_8)); + + // Verify echo server to client + for (char c : "Goodbye Cruel TLS".toCharArray()) + { + int b = client.getInputStream().read(); + Assert.assertThat("expect valid char integer", b, greaterThan(0)); + assertEquals("expect characters to be same", c, (char)b); + } + client.close(); + + for (int i = 0; i < 10; ++i) + { + if (server.isOpen()) + Thread.sleep(10); + else + break; + } + assertFalse(server.isOpen()); + } } - assertFalse(server.isOpen()); } @Test @@ -204,265 +205,265 @@ public class SocketChannelEndPointTest { assumeTrue("Scenario supports half-close", _scenario.supportsHalfCloses()); - Socket client = _scenario.newClient(_connector); - - client.setSoTimeout(500); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - - _manager.accept(server); - - // Write client to server - client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); - - // Verify echo server to client - for (char c : "HelloWorld".toCharArray()) + try (Socket client = _scenario.newClient(_connector)) { - int b = client.getInputStream().read(); - assertTrue(b > 0); - assertEquals(c, (char) b); - } + client.setSoTimeout(500); + try (SocketChannel server = _connector.accept()) + { + server.configureBlocking(false); + _manager.accept(server); - // wait for read timeout - long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - try - { - client.getInputStream().read(); - Assert.fail(); - } - catch (SocketTimeoutException e) - { - assertTrue(TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start >= 400); - } + // Write client to server + client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); - // write then shutdown - client.getOutputStream().write("Goodbye Cruel TLS".getBytes(StandardCharsets.UTF_8)); - client.shutdownOutput(); + // Verify echo server to client + for (char c : "HelloWorld".toCharArray()) + { + int b = client.getInputStream().read(); + assertTrue(b > 0); + assertEquals(c, (char)b); + } - // Verify echo server to client - for (char c : "Goodbye Cruel TLS".toCharArray()) - { - int b = client.getInputStream().read(); - assertTrue(b > 0); - assertEquals(c, (char) b); + // wait for read timeout + long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + try + { + client.getInputStream().read(); + Assert.fail(); + } + catch (SocketTimeoutException e) + { + assertTrue(TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start >= 400); + } + + // write then shutdown + client.getOutputStream().write("Goodbye Cruel TLS".getBytes(StandardCharsets.UTF_8)); + client.shutdownOutput(); + + // Verify echo server to client + for (char c : "Goodbye Cruel TLS".toCharArray()) + { + int b = client.getInputStream().read(); + assertTrue(b > 0); + assertEquals(c, (char)b); + } + + // Read close + assertEquals(-1, client.getInputStream().read()); + } } - - // Read close - assertEquals(-1, client.getInputStream().read()); } @Test public void testReadBlocked() throws Exception { - Socket client = _scenario.newClient(_connector); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - - _manager.accept(server); - - OutputStream clientOutputStream = client.getOutputStream(); - InputStream clientInputStream = client.getInputStream(); - - int specifiedTimeout = 1000; - client.setSoTimeout(specifiedTimeout); - - // Write 8 and cause block waiting for 10 - _blockAt.set(10); - clientOutputStream.write("12345678".getBytes(StandardCharsets.UTF_8)); - clientOutputStream.flush(); - - Assert.assertTrue(_lastEndPointLatch.await(1, TimeUnit.SECONDS)); - _lastEndPoint.setIdleTimeout(10 * specifiedTimeout); - Thread.sleep((11 * specifiedTimeout) / 10); - - long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - try + try (Socket client = _scenario.newClient(_connector); + SocketChannel server = _connector.accept()) { - int b = clientInputStream.read(); - Assert.fail("Should have timed out waiting for a response, but read " + b); - } - catch (SocketTimeoutException e) - { - int elapsed = Long.valueOf(TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start).intValue(); - Assert.assertThat("Expected timeout", elapsed, greaterThanOrEqualTo(3 * specifiedTimeout / 4)); - } + server.configureBlocking(false); + _manager.accept(server); - // write remaining characters - clientOutputStream.write("90ABCDEF".getBytes(StandardCharsets.UTF_8)); - clientOutputStream.flush(); + OutputStream clientOutputStream = client.getOutputStream(); + InputStream clientInputStream = client.getInputStream(); - // Verify echo server to client - for (char c : "1234567890ABCDEF".toCharArray()) - { - int b = clientInputStream.read(); - assertTrue(b > 0); - assertEquals(c, (char) b); + int specifiedTimeout = 1000; + client.setSoTimeout(specifiedTimeout); + + // Write 8 and cause block waiting for 10 + _blockAt.set(10); + clientOutputStream.write("12345678".getBytes(StandardCharsets.UTF_8)); + clientOutputStream.flush(); + + Assert.assertTrue(_lastEndPointLatch.await(1, TimeUnit.SECONDS)); + _lastEndPoint.setIdleTimeout(10 * specifiedTimeout); + Thread.sleep((11 * specifiedTimeout) / 10); + + long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + try + { + int b = clientInputStream.read(); + Assert.fail("Should have timed out waiting for a response, but read " + b); + } + catch (SocketTimeoutException e) + { + int elapsed = Long.valueOf(TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) - start).intValue(); + Assert.assertThat("Expected timeout", elapsed, greaterThanOrEqualTo(3 * specifiedTimeout / 4)); + } + + // write remaining characters + clientOutputStream.write("90ABCDEF".getBytes(StandardCharsets.UTF_8)); + clientOutputStream.flush(); + + // Verify echo server to client + for (char c : "1234567890ABCDEF".toCharArray()) + { + int b = clientInputStream.read(); + assertTrue(b > 0); + assertEquals(c, (char)b); + } } } @Test public void testStress() throws Exception { - Socket client = _scenario.newClient(_connector); - client.setSoTimeout(30000); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - - _manager.accept(server); - final int writes = 200000; - - final byte[] bytes = "HelloWorld-".getBytes(StandardCharsets.UTF_8); - byte[] count = "0\n".getBytes(StandardCharsets.UTF_8); - BufferedOutputStream out = new BufferedOutputStream(client.getOutputStream()); - final CountDownLatch latch = new CountDownLatch(writes); - final InputStream in = new BufferedInputStream(client.getInputStream()); - final long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - out.write(bytes); - out.write(count); - out.flush(); - - Assert.assertTrue(_lastEndPointLatch.await(1, TimeUnit.SECONDS)); - _lastEndPoint.setIdleTimeout(5000); - - new Thread() + try (Socket client = _scenario.newClient(_connector)) { - @Override - public void run() + client.setSoTimeout(30000); + try (SocketChannel server = _connector.accept()) { - Thread.currentThread().setPriority(MAX_PRIORITY); - long last = -1; - int count = -1; - try - { - while (latch.getCount() > 0) - { - // Verify echo server to client - for (byte b0 : bytes) - { - int b = in.read(); - Assert.assertThat(b, greaterThan(0)); - assertEquals(0xff & b0, b); - } + server.configureBlocking(false); + _manager.accept(server); + final int writes = 200000; - count = 0; - int b = in.read(); - while (b > 0 && b != '\n') - { - count = count * 10 + (b - '0'); - b = in.read(); - } - last = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - - //if (latch.getCount()%1000==0) - // System.out.println(writes-latch.getCount()); - - latch.countDown(); - } - } - catch (Throwable e) - { - - long now = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); - System.err.println("count=" + count); - System.err.println("latch=" + latch.getCount()); - System.err.println("time=" + (now - start)); - System.err.println("last=" + (now - last)); - System.err.println("endp=" + _lastEndPoint); - System.err.println("conn=" + _lastEndPoint.getConnection()); - - e.printStackTrace(); - } - } - }.start(); - - // Write client to server - for (int i = 1; i < writes; i++) - { - out.write(bytes); - out.write(Integer.toString(i).getBytes(StandardCharsets.ISO_8859_1)); - out.write('\n'); - if (i % 1000 == 0) - { - //System.err.println(i+"/"+writes); + final byte[] bytes = "HelloWorld-".getBytes(StandardCharsets.UTF_8); + byte[] count = "0\n".getBytes(StandardCharsets.UTF_8); + BufferedOutputStream out = new BufferedOutputStream(client.getOutputStream()); + final CountDownLatch latch = new CountDownLatch(writes); + final InputStream in = new BufferedInputStream(client.getInputStream()); + final long start = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + out.write(bytes); + out.write(count); out.flush(); + + Assert.assertTrue(_lastEndPointLatch.await(1, TimeUnit.SECONDS)); + _lastEndPoint.setIdleTimeout(5000); + + new Thread(() -> + { + Thread.currentThread().setPriority(Thread.MAX_PRIORITY); + long last = -1; + int count1 = -1; + try + { + while (latch.getCount() > 0) + { + // Verify echo server to client + for (byte b0 : bytes) + { + int b = in.read(); + Assert.assertThat(b, greaterThan(0)); + assertEquals(0xff & b0, b); + } + + count1 = 0; + int b = in.read(); + while (b > 0 && b != '\n') + { + count1 = count1 * 10 + (b - '0'); + b = in.read(); + } + last = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + + //if (latch.getCount()%1000==0) + // System.out.println(writes-latch.getCount()); + + latch.countDown(); + } + } + catch (Throwable e) + { + + long now = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); + System.err.println("count=" + count1); + System.err.println("latch=" + latch.getCount()); + System.err.println("time=" + (now - start)); + System.err.println("last=" + (now - last)); + System.err.println("endp=" + _lastEndPoint); + System.err.println("conn=" + _lastEndPoint.getConnection()); + + e.printStackTrace(); + } + }).start(); + + // Write client to server + for (int i = 1; i < writes; i++) + { + out.write(bytes); + out.write(Integer.toString(i).getBytes(StandardCharsets.ISO_8859_1)); + out.write('\n'); + if (i % 1000 == 0) + { + //System.err.println(i+"/"+writes); + out.flush(); + } + Thread.yield(); + } + out.flush(); + + long last = latch.getCount(); + while (!latch.await(5, TimeUnit.SECONDS)) + { + //System.err.println(latch.getCount()); + if (latch.getCount() == last) + Assert.fail(); + last = latch.getCount(); + } + + assertEquals(0, latch.getCount()); } - Thread.yield(); } - out.flush(); - - long last = latch.getCount(); - while (!latch.await(5, TimeUnit.SECONDS)) - { - //System.err.println(latch.getCount()); - if (latch.getCount() == last) - Assert.fail(); - last = latch.getCount(); - } - - assertEquals(0, latch.getCount()); } @Test public void testWriteBlocked() throws Exception { - Socket client = _scenario.newClient(_connector); - - client.setSoTimeout(10000); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - - _manager.accept(server); - - // Write client to server - _writeCount.set(10000); - String data = "Now is the time for all good men to come to the aid of the party"; - client.getOutputStream().write(data.getBytes(StandardCharsets.UTF_8)); - BufferedInputStream in = new BufferedInputStream(client.getInputStream()); - - int byteNum = 0; - try + try (Socket client = _scenario.newClient(_connector)) { - for (int i = 0; i < _writeCount.get(); i++) + client.setSoTimeout(10000); + try (SocketChannel server = _connector.accept()) { - if (i % 1000 == 0) - TimeUnit.MILLISECONDS.sleep(200); + server.configureBlocking(false); + _manager.accept(server); - // Verify echo server to client - for (int j = 0; j < data.length(); j++) + // Write client to server + _writeCount.set(10000); + String data = "Now is the time for all good men to come to the aid of the party"; + client.getOutputStream().write(data.getBytes(StandardCharsets.UTF_8)); + BufferedInputStream in = new BufferedInputStream(client.getInputStream()); + + int byteNum = 0; + try { - char c = data.charAt(j); - int b = in.read(); - byteNum++; - assertTrue(b > 0); - assertEquals("test-" + i + "/" + j, c, (char) b); + for (int i = 0; i < _writeCount.get(); i++) + { + if (i % 1000 == 0) + TimeUnit.MILLISECONDS.sleep(200); + + // Verify echo server to client + for (int j = 0; j < data.length(); j++) + { + char c = data.charAt(j); + int b = in.read(); + byteNum++; + assertTrue(b > 0); + assertEquals("test-" + i + "/" + j, c, (char)b); + } + + if (i == 0) + _lastEndPoint.setIdleTimeout(60000); + } + } + catch (SocketTimeoutException e) + { + System.err.println("SelectorManager.dump() = " + _manager.dump()); + LOG.warn("Server: " + server); + LOG.warn("Error reading byte #" + byteNum, e); + throw e; } - if (i == 0) - _lastEndPoint.setIdleTimeout(60000); + client.close(); + + for (int i = 0; i < 10; ++i) + { + if (server.isOpen()) + Thread.sleep(10); + else + break; + } + assertFalse(server.isOpen()); } } - catch (SocketTimeoutException e) - { - System.err.println("SelectorManager.dump() = " + _manager.dump()); - LOG.warn("Server: " + server); - LOG.warn("Error reading byte #" + byteNum, e); - throw e; - } - - client.close(); - - for (int i = 0; i < 10; ++i) - { - if (server.isOpen()) - Thread.sleep(10); - else - break; - } - assertFalse(server.isOpen()); } @@ -482,7 +483,7 @@ public class SocketChannelEndPointTest { @Override - protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey selectionKey) throws IOException + protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey selectionKey) { SocketChannelEndPoint endp = new SocketChannelEndPoint(channel, selector, selectionKey, getScheduler()); _lastEndPoint = endp; @@ -491,7 +492,7 @@ public class SocketChannelEndPointTest } @Override - public Connection newConnection(SelectableChannel channel, EndPoint endpoint, Object attachment) throws IOException + public Connection newConnection(SelectableChannel channel, EndPoint endpoint, Object attachment) { return new TestConnection(endpoint, latch, getExecutor(), _blockAt, _writeCount); } @@ -507,18 +508,14 @@ public class SocketChannelEndPointTest CountDownLatch closed = new CountDownLatch(20); for (int i = 0; i < 20; i++) { - new Thread() + new Thread(() -> { - @Override - public void run() + try (Socket client = _scenario.newClient(_connector)) { - try (Socket client = _scenario.newClient(_connector);) + client.setSoTimeout(5000); + try (SocketChannel server = _connector.accept()) { - client.setSoTimeout(5000); - - SocketChannel server = _connector.accept(); server.configureBlocking(false); - _manager.accept(server); // Write client to server @@ -531,26 +528,26 @@ public class SocketChannelEndPointTest { int b = client.getInputStream().read(); assertTrue(b > 0); - assertEquals(c, (char) b); + assertEquals(c, (char)b); } assertEquals(-1, client.getInputStream().read()); echoed.incrementAndGet(); } - catch (SocketTimeoutException x) - { - x.printStackTrace(); - timeout.incrementAndGet(); - } - catch (Throwable x) - { - rejections.incrementAndGet(); - } - finally - { - closed.countDown(); - } } - }.start(); + catch (SocketTimeoutException x) + { + x.printStackTrace(); + timeout.incrementAndGet(); + } + catch (Throwable x) + { + rejections.incrementAndGet(); + } + finally + { + closed.countDown(); + } + }).start(); } // unblock the handling @@ -572,25 +569,25 @@ public class SocketChannelEndPointTest try (Socket client = _scenario.newClient(_connector)) { client.setSoTimeout(5000); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - - _manager.accept(server); - - // Write client to server - client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); - client.getOutputStream().flush(); - client.shutdownOutput(); - - // Verify echo server to client - for (char c : "HelloWorld".toCharArray()) + try (SocketChannel server = _connector.accept()) { - int b = client.getInputStream().read(); - assertTrue(b > 0); - assertEquals(c, (char) b); + server.configureBlocking(false); + _manager.accept(server); + + // Write client to server + client.getOutputStream().write("HelloWorld".getBytes(StandardCharsets.UTF_8)); + client.getOutputStream().flush(); + client.shutdownOutput(); + + // Verify echo server to client + for (char c : "HelloWorld".toCharArray()) + { + int b = client.getInputStream().read(); + assertTrue(b > 0); + assertEquals(c, (char)b); + } + assertEquals(-1, client.getInputStream().read()); } - assertEquals(-1, client.getInputStream().read()); } } @@ -601,7 +598,7 @@ public class SocketChannelEndPointTest super(executor, scheduler); } - protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey key) throws IOException + protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey key) { SocketChannelEndPoint endp = new SocketChannelEndPoint(channel, selector, key, getScheduler()); endp.setIdleTimeout(60000); @@ -611,7 +608,7 @@ public class SocketChannelEndPointTest } @Override - public Connection newConnection(SelectableChannel channel, EndPoint endpoint, Object attachment) throws IOException + public Connection newConnection(SelectableChannel channel, EndPoint endpoint, Object attachment) { return _scenario.newConnection(channel, endpoint, getExecutor(), _blockAt, _writeCount); } diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java index 72d90192b34..23c60aeadc4 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SslConnectionTest.java @@ -91,7 +91,7 @@ public class SslConnectionTest @Override - protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey selectionKey) throws IOException + protected EndPoint newEndPoint(SelectableChannel channel, ManagedSelector selector, SelectionKey selectionKey) { SocketChannelEndPoint endp = new TestEP(channel, selector, selectionKey, getScheduler()); endp.setIdleTimeout(60000); @@ -126,8 +126,7 @@ public class SslConnectionTest return false; } } - boolean flushed=super.flush(buffers); - return flushed; + return super.flush(buffers); } } @@ -186,15 +185,7 @@ public class SslConnectionTest fillInterested(); else { - getExecutor().execute(new Runnable() - { - - @Override - public void run() - { - getEndPoint().write(_writeCallback,BufferUtil.toBuffer("Hello Client")); - } - }); + getExecutor().execute(() -> getEndPoint().write(_writeCallback,BufferUtil.toBuffer("Hello Client"))); } } @@ -264,52 +255,54 @@ public class SslConnectionTest @Test public void testHelloWorld() throws Exception { - Socket client = newClient(); - client.setSoTimeout(60000); + try (Socket client = newClient()) + { + client.setSoTimeout(60000); + try (SocketChannel server = _connector.accept()) + { + server.configureBlocking(false); + _manager.accept(server); - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - _manager.accept(server); + client.getOutputStream().write("Hello".getBytes(StandardCharsets.UTF_8)); + byte[] buffer = new byte[1024]; + int len = client.getInputStream().read(buffer); + Assert.assertEquals(5, len); + Assert.assertEquals("Hello", new String(buffer, 0, len, StandardCharsets.UTF_8)); - client.getOutputStream().write("Hello".getBytes(StandardCharsets.UTF_8)); - byte[] buffer = new byte[1024]; - int len=client.getInputStream().read(buffer); - Assert.assertEquals(5, len); - Assert.assertEquals("Hello",new String(buffer,0,len,StandardCharsets.UTF_8)); - - _dispatches.set(0); - client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8)); - len=5; - while(len>0) - len-=client.getInputStream().read(buffer); - - client.close(); + _dispatches.set(0); + client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8)); + len = 5; + while (len > 0) + len -= client.getInputStream().read(buffer); + } + } } @Test public void testRenegotiate() throws Exception { - SSLSocket client = newClient(); - client.setSoTimeout(60000); + try (SSLSocket client = newClient()) + { + client.setSoTimeout(60000); + try (SocketChannel server = _connector.accept()) + { + server.configureBlocking(false); + _manager.accept(server); - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - _manager.accept(server); + client.getOutputStream().write("Hello".getBytes(StandardCharsets.UTF_8)); + byte[] buffer = new byte[1024]; + int len = client.getInputStream().read(buffer); + Assert.assertEquals(5, len); + Assert.assertEquals("Hello", new String(buffer, 0, len, StandardCharsets.UTF_8)); - client.getOutputStream().write("Hello".getBytes(StandardCharsets.UTF_8)); - byte[] buffer = new byte[1024]; - int len=client.getInputStream().read(buffer); - Assert.assertEquals(5, len); - Assert.assertEquals("Hello",new String(buffer,0,len,StandardCharsets.UTF_8)); + client.startHandshake(); - client.startHandshake(); - - client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8)); - len=client.getInputStream().read(buffer); - Assert.assertEquals(5, len); - Assert.assertEquals("World",new String(buffer,0,len,StandardCharsets.UTF_8)); - - client.close(); + client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8)); + len = client.getInputStream().read(buffer); + Assert.assertEquals(5, len); + Assert.assertEquals("World", new String(buffer, 0, len, StandardCharsets.UTF_8)); + } + } } @Test @@ -317,30 +310,33 @@ public class SslConnectionTest { __sslCtxFactory.setRenegotiationAllowed(false); - SSLSocket client = newClient(); - client.setSoTimeout(60000); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - _manager.accept(server); - - client.getOutputStream().write("Hello".getBytes(StandardCharsets.UTF_8)); - byte[] buffer = new byte[1024]; - int len=client.getInputStream().read(buffer); - Assert.assertEquals(5, len); - Assert.assertEquals("Hello",new String(buffer,0,len,StandardCharsets.UTF_8)); - - client.startHandshake(); - - client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8)); - try + try (SSLSocket client = newClient()) { - client.getInputStream().read(buffer); - Assert.fail(); - } - catch(SSLException e) - { - // expected + client.setSoTimeout(60000); + try (SocketChannel server = _connector.accept()) + { + server.configureBlocking(false); + _manager.accept(server); + + client.getOutputStream().write("Hello".getBytes(StandardCharsets.UTF_8)); + byte[] buffer = new byte[1024]; + int len = client.getInputStream().read(buffer); + Assert.assertEquals(5, len); + Assert.assertEquals("Hello", new String(buffer, 0, len, StandardCharsets.UTF_8)); + + client.startHandshake(); + + client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8)); + try + { + client.getInputStream().read(buffer); + Assert.fail(); + } + catch (SSLException e) + { + // expected + } + } } } @@ -350,152 +346,149 @@ public class SslConnectionTest __sslCtxFactory.setRenegotiationAllowed(true); __sslCtxFactory.setRenegotiationLimit(2); - SSLSocket client = newClient(); - client.setSoTimeout(60000); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - _manager.accept(server); - - client.getOutputStream().write("Good".getBytes(StandardCharsets.UTF_8)); - byte[] buffer = new byte[1024]; - int len=client.getInputStream().read(buffer); - Assert.assertEquals(4, len); - Assert.assertEquals("Good",new String(buffer,0,len,StandardCharsets.UTF_8)); - - client.startHandshake(); - - client.getOutputStream().write("Bye".getBytes(StandardCharsets.UTF_8)); - len=client.getInputStream().read(buffer); - Assert.assertEquals(3, len); - Assert.assertEquals("Bye",new String(buffer,0,len,StandardCharsets.UTF_8)); - - client.startHandshake(); - - client.getOutputStream().write("Cruel".getBytes(StandardCharsets.UTF_8)); - len=client.getInputStream().read(buffer); - Assert.assertEquals(5, len); - Assert.assertEquals("Cruel",new String(buffer,0,len,StandardCharsets.UTF_8)); - - client.startHandshake(); - - client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8)); - try + try (SSLSocket client = newClient()) { - client.getInputStream().read(buffer); - Assert.fail(); - } - catch(SSLException e) - { - // expected + client.setSoTimeout(60000); + try (SocketChannel server = _connector.accept()) + { + server.configureBlocking(false); + _manager.accept(server); + + client.getOutputStream().write("Good".getBytes(StandardCharsets.UTF_8)); + byte[] buffer = new byte[1024]; + int len = client.getInputStream().read(buffer); + Assert.assertEquals(4, len); + Assert.assertEquals("Good", new String(buffer, 0, len, StandardCharsets.UTF_8)); + + client.startHandshake(); + + client.getOutputStream().write("Bye".getBytes(StandardCharsets.UTF_8)); + len = client.getInputStream().read(buffer); + Assert.assertEquals(3, len); + Assert.assertEquals("Bye", new String(buffer, 0, len, StandardCharsets.UTF_8)); + + client.startHandshake(); + + client.getOutputStream().write("Cruel".getBytes(StandardCharsets.UTF_8)); + len = client.getInputStream().read(buffer); + Assert.assertEquals(5, len); + Assert.assertEquals("Cruel", new String(buffer, 0, len, StandardCharsets.UTF_8)); + + client.startHandshake(); + + client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8)); + try + { + client.getInputStream().read(buffer); + Assert.fail(); + } + catch (SSLException e) + { + // expected + } + } } } - - @Test public void testWriteOnConnect() throws Exception { _testFill=false; - _writeCallback = new FutureCallback(); - Socket client = newClient(); - client.setSoTimeout(10000); - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - _manager.accept(server); + try (Socket client = newClient()) + { + client.setSoTimeout(10000); + try (SocketChannel server = _connector.accept()) + { + server.configureBlocking(false); + _manager.accept(server); - byte[] buffer = new byte[1024]; - int len=client.getInputStream().read(buffer); - Assert.assertEquals("Hello Client",new String(buffer,0,len,StandardCharsets.UTF_8)); - Assert.assertEquals(null,_writeCallback.get(100,TimeUnit.MILLISECONDS)); - client.close(); + byte[] buffer = new byte[1024]; + int len = client.getInputStream().read(buffer); + Assert.assertEquals("Hello Client", new String(buffer, 0, len, StandardCharsets.UTF_8)); + Assert.assertNull(_writeCallback.get(100, TimeUnit.MILLISECONDS)); + } + } } - - @Test public void testBlockedWrite() throws Exception { - Socket client = newClient(); - client.setSoTimeout(5000); + try (Socket client = newClient()) + { + client.setSoTimeout(5000); + try (SocketChannel server = _connector.accept()) + { + server.configureBlocking(false); + _manager.accept(server); - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - _manager.accept(server); + __startBlocking.set(5); + __blockFor.set(3); - __startBlocking.set(5); - __blockFor.set(3); - - client.getOutputStream().write("Hello".getBytes(StandardCharsets.UTF_8)); - byte[] buffer = new byte[1024]; - int len=client.getInputStream().read(buffer); - Assert.assertEquals(5, len); - Assert.assertEquals("Hello",new String(buffer,0,len,StandardCharsets.UTF_8)); + client.getOutputStream().write("Hello".getBytes(StandardCharsets.UTF_8)); + byte[] buffer = new byte[1024]; + int len = client.getInputStream().read(buffer); + Assert.assertEquals(5, len); + Assert.assertEquals("Hello", new String(buffer, 0, len, StandardCharsets.UTF_8)); - _dispatches.set(0); - client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8)); - len=5; - while(len>0) - len-=client.getInputStream().read(buffer); - Assert.assertEquals(0, len); - client.close(); + _dispatches.set(0); + client.getOutputStream().write("World".getBytes(StandardCharsets.UTF_8)); + len = 5; + while (len > 0) + len -= client.getInputStream().read(buffer); + Assert.assertEquals(0, len); + } + } } @Test public void testManyLines() throws Exception { - final Socket client = newClient(); - client.setSoTimeout(10000); - - SocketChannel server = _connector.accept(); - server.configureBlocking(false); - _manager.accept(server); - - final int LINES=20; - final CountDownLatch count=new CountDownLatch(LINES); - - - new Thread() + try (Socket client = newClient()) { - @Override - public void run() + client.setSoTimeout(10000); + try (SocketChannel server = _connector.accept()) { - try + server.configureBlocking(false); + _manager.accept(server); + + final int LINES = 20; + final CountDownLatch count = new CountDownLatch(LINES); + + new Thread(() -> { - BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream(),StandardCharsets.UTF_8)); - while(count.getCount()>0) + try { - String line=in.readLine(); - if (line==null) - break; - // System.err.println(line); - count.countDown(); + BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream(), StandardCharsets.UTF_8)); + while (count.getCount() > 0) + { + String line = in.readLine(); + if (line == null) + break; + // System.err.println(line); + count.countDown(); + } + } + catch (IOException e) + { + e.printStackTrace(); + } + }).start(); + + for (int i = 0; i < LINES; i++) + { + client.getOutputStream().write(("HelloWorld " + i + "\n").getBytes(StandardCharsets.UTF_8)); + // System.err.println("wrote"); + if (i % 1000 == 0) + { + client.getOutputStream().flush(); + Thread.sleep(10); } } - catch(IOException e) - { - e.printStackTrace(); - } - } - }.start(); - for (int i=0;iorg.eclipse.jetty.its.jetty-deploy-war-mojo-it jetty-simple-project 0.0.1-SNAPSHOT - jar + pom Jetty :: Simple deploy war mojo test @project.version@ - ${project.build.directory}/jetty-run-war-port.txt + ${project.build.directory}/jetty-deploy-war-port.txt @@ -53,33 +53,6 @@ - - org.apache.maven.plugins - maven-failsafe-plugin - @surefireVersion@ - - - ${jetty.port.file} - - - **/*TestGetContent* - - - - - integration-test - - integration-test - - - - verify - - verify - - - - org.eclipse.jetty jetty-maven-plugin @@ -92,6 +65,7 @@ deploy-war + @jetty.runPort@ pom diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-client/pom.xml b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-client/pom.xml new file mode 100644 index 00000000000..d1602c95c72 --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-client/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + + + org.olamy + beer + 1.0-SNAPSHOT + + + beer-client + gwt-app + + + + ${project.groupId} + beer-shared + ${project.version} + + + ${project.groupId} + beer-shared + ${project.version} + sources + + + com.google.gwt + gwt-user + + + com.google.gwt + gwt-dev + + + + + + + net.ltgt.gwt.maven + gwt-maven-plugin + + org.olamy.App + app + + + + + diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-client/src/main/java/org/olamy/App.java b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-client/src/main/java/org/olamy/App.java new file mode 100644 index 00000000000..862044d77f4 --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-client/src/main/java/org/olamy/App.java @@ -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.olamy; + +import com.google.gwt.core.client.EntryPoint; +import com.google.gwt.core.client.GWT; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.event.dom.client.KeyUpEvent; +import com.google.gwt.event.dom.client.KeyUpHandler; +import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.DialogBox; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.RootPanel; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.VerticalPanel; + +/** + * Entry point classes define onModuleLoad(). + */ +public class App implements EntryPoint { + /** + * The message displayed to the user when the server cannot be reached or + * returns an error. + */ + private static final String SERVER_ERROR = "An error occurred while " + + "attempting to contact the server. Please check your network " + + "connection and try again."; + + /** + * Create a remote service proxy to talk to the server-side Greeting service. + */ + private final GreetingServiceAsync greetingService = GWT + .create(GreetingService.class); + + /** + * This is the entry point method. + */ + public void onModuleLoad() { + final Button sendButton = new Button("Send"); + final TextBox nameField = new TextBox(); + nameField.setText("GWT User"); + final Label errorLabel = new Label(); + + // We can add style names to widgets + sendButton.addStyleName("sendButton"); + + // Add the nameField and sendButton to the RootPanel + // Use RootPanel.get() to get the entire body element + RootPanel.get("nameFieldContainer").add(nameField); + RootPanel.get("sendButtonContainer").add(sendButton); + RootPanel.get("errorLabelContainer").add(errorLabel); + + // Focus the cursor on the name field when the app loads + nameField.setFocus(true); + nameField.selectAll(); + + // Create the popup dialog box + final DialogBox dialogBox = new DialogBox(); + dialogBox.setText("Remote Procedure Call"); + dialogBox.setAnimationEnabled(true); + final Button closeButton = new Button("Close"); + // We can set the id of a widget by accessing its Element + closeButton.getElement().setId("closeButton"); + final Label textToServerLabel = new Label(); + final HTML serverResponseLabel = new HTML(); + VerticalPanel dialogVPanel = new VerticalPanel(); + dialogVPanel.addStyleName("dialogVPanel"); + dialogVPanel.add(new HTML("Sending name to the server:")); + dialogVPanel.add(textToServerLabel); + dialogVPanel.add(new HTML("
    Server replies:")); + dialogVPanel.add(serverResponseLabel); + dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT); + dialogVPanel.add(closeButton); + dialogBox.setWidget(dialogVPanel); + + // Add a handler to close the DialogBox + closeButton.addClickHandler(new ClickHandler() { + public void onClick(ClickEvent event) { + dialogBox.hide(); + sendButton.setEnabled(true); + sendButton.setFocus(true); + } + }); + + // Create a handler for the sendButton and nameField + class MyHandler implements ClickHandler, KeyUpHandler { + /** + * Fired when the user clicks on the sendButton. + */ + public void onClick(ClickEvent event) { + sendNameToServer(); + } + + /** + * Fired when the user types in the nameField. + */ + public void onKeyUp(KeyUpEvent event) { + if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) { + sendNameToServer(); + } + } + + /** + * Send the name from the nameField to the server and wait for a response. + */ + private void sendNameToServer() { + // First, we validate the input. + errorLabel.setText(""); + String textToServer = nameField.getText(); + if (!FieldVerifier.isValidName(textToServer)) { + errorLabel.setText("Please enter at least four characters"); + return; + } + + // Then, we send the input to the server. + sendButton.setEnabled(false); + textToServerLabel.setText(textToServer); + serverResponseLabel.setText(""); + greetingService.greetServer(textToServer, + new AsyncCallback() { + public void onFailure(Throwable caught) { + // Show the RPC error message to the user + dialogBox + .setText("Remote Procedure Call - Failure"); + serverResponseLabel + .addStyleName("serverResponseLabelError"); + serverResponseLabel.setHTML(SERVER_ERROR); + dialogBox.center(); + closeButton.setFocus(true); + } + + public void onSuccess(GreetingResponse result) { + dialogBox.setText("Remote Procedure Call"); + serverResponseLabel + .removeStyleName("serverResponseLabelError"); + serverResponseLabel.setHTML(new SafeHtmlBuilder() + .appendEscaped(result.getGreeting()) + .appendHtmlConstant("

    I am running ") + .appendEscaped(result.getServerInfo()) + .appendHtmlConstant(".

    It looks like you are using:
    ") + .appendEscaped(result.getUserAgent()) + .toSafeHtml()); + dialogBox.center(); + closeButton.setFocus(true); + } + }); + } + } + + // Add a handler to send the name to the server + MyHandler handler = new MyHandler(); + sendButton.addClickHandler(handler); + nameField.addKeyUpHandler(handler); + } +} diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-client/src/main/module.gwt.xml b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-client/src/main/module.gwt.xml new file mode 100644 index 00000000000..6cda0e54be6 --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-client/src/main/module.gwt.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/pom.xml b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/pom.xml new file mode 100644 index 00000000000..ba0ea68de2f --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/pom.xml @@ -0,0 +1,161 @@ + + + 4.0.0 + + + org.olamy + beer + 1.0-SNAPSHOT + + + beer-server + war + + + ${project.build.directory}/jetty-run-mojo.txt + + + + + ${project.groupId} + beer-shared + ${project.version} + + + com.google.gwt + gwt-servlet + + + javax.servlet + javax.servlet-api + provided + + + + org.eclipse.jetty + jetty-client + ${jetty.version} + test + + + org.eclipse.jetty + jetty-util + ${jetty.version} + test + + + org.eclipse.jetty + jetty-http + ${jetty.version} + test + + + org.eclipse.jetty + jetty-io + ${jetty.version} + test + + + junit + junit + 4.12 + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + @surefireVersion@ + + + ${jetty.port.file} + + + + + org.eclipse.jetty + jetty-maven-plugin + + + run + test-compile + + run + + + + + jetty.port.file + ${jetty.port.file} + + + true + 1 + + ${basedir}/../beer-shared/target/classes/ + + ${basedir}/src/main/jettyconf/context.xml + ${basedir}/src/config/jetty.xml + + + + + + + + + + + env-prod + + true + + + + ${project.groupId} + beer-client + ${project.version} + war + runtime + + + + + env-dev + + + env + dev + + + + + + + org.eclipse.jetty + jetty-maven-plugin + + + + ${basedir}/src/main/webapp + ${basedir}/../target/gwt/launcherDir/ + + + + + + org.apache.tomcat.maven + tomcat7-maven-plugin + + ${basedir}/src/main/tomcatconf/context.xml + + + + + + + + diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/config/jetty.xml b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/config/jetty.xml new file mode 100644 index 00000000000..c38bcced0e1 --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/config/jetty.xml @@ -0,0 +1,40 @@ + + + + + + https + + 32768 + 8192 + 8192 + 512 + + + + + + + + + + + + + + + + + + + + + + + + 0 + 30000 + + + + diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/java/org/olamy/GreetingServiceImpl.java b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/java/org/olamy/GreetingServiceImpl.java new file mode 100644 index 00000000000..1fedbbbeea1 --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/java/org/olamy/GreetingServiceImpl.java @@ -0,0 +1,48 @@ +// +// ======================================================================== +// 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.olamy; + +import com.google.gwt.user.server.rpc.RemoteServiceServlet; + +/** + * The server side implementation of the RPC service. + */ +@SuppressWarnings("serial") +public class GreetingServiceImpl extends RemoteServiceServlet implements + GreetingService { + + public GreetingResponse greetServer(String input) throws IllegalArgumentException { + // Verify that the input is valid. + if (!FieldVerifier.isValidName(input)) { + // If the input is not valid, throw an IllegalArgumentException back to + // the client. + throw new IllegalArgumentException( + "Name must be at least 4 characters long"); + } + + GreetingResponse response = new GreetingResponse(); + + response.setServerInfo(getServletContext().getServerInfo()); + response.setUserAgent(getThreadLocalRequest().getHeader("User-Agent")); + + response.setGreeting("Hello, " + input + "!"); + + return response; + } +} diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/jettyconf/context.xml b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/jettyconf/context.xml new file mode 100644 index 00000000000..eaea86d15cf --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/jettyconf/context.xml @@ -0,0 +1,6 @@ + + + org.eclipse.jetty.servlet.Default.useFileMappedBuffer + false + + diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/webapp/WEB-INF/web.xml b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..4ece79123db --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,22 @@ + + + + + + greetServlet + org.olamy.GreetingServiceImpl + + + + greetServlet + /app/greet + + + + + index.html + + + diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/webapp/beer.css b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/webapp/beer.css new file mode 100644 index 00000000000..7aca7ac7b65 --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/webapp/beer.css @@ -0,0 +1,34 @@ +/** Add css rules here for your application. */ + + +/** Example rules used by the template application (remove for your app) */ +h1 { + font-size: 2em; + font-weight: bold; + color: #777777; + margin: 40px 0px 70px; + text-align: center; +} + +.sendButton { + display: block; + font-size: 16pt; +} + +/** Most GWT widgets already have a style name defined */ +.gwt-DialogBox { + width: 400px; +} + +.dialogVPanel { + margin: 5px; +} + +.serverResponseLabelError { + color: red; +} + +/** Set ids using widget.getElement().setId("idOfElement") */ +#closeButton { + margin: 15px 6px 6px; +} diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/webapp/favicon.ico b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/webapp/favicon.ico new file mode 100644 index 00000000000..858a707523f Binary files /dev/null and b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/webapp/favicon.ico differ diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/webapp/index.html b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/webapp/index.html new file mode 100644 index 00000000000..96cb49b86b1 --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/main/webapp/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + Web Application Starter Project + + + + + + + + + + + + + + + + + + + +

    Web Application Starter Project

    + + + + + + + + + + + + +
    Please enter your name:
    + + diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/test/java/org/olamy/TestGetContent.java b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/test/java/org/olamy/TestGetContent.java new file mode 100644 index 00000000000..63d2e5d97cd --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-server/src/test/java/org/olamy/TestGetContent.java @@ -0,0 +1,92 @@ +// +// ======================================================================== +// 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.olamy; + +import org.eclipse.jetty.client.HttpClient; +import org.junit.Assert; +import org.junit.Test; + +import java.io.File; +import java.io.FileReader; +import java.io.LineNumberReader; + +/** + * + */ +public class TestGetContent + +{ + @Test + public void get_root_response() + throws Exception + { + + int port = getPort(); + Assert.assertTrue(port > 0); + HttpClient httpClient = new HttpClient(); + try + { + httpClient.start(); + + String response = httpClient.GET( "http://localhost:" + port ).getContentAsString(); + + System.out.println( "response" + response ); + Assert.assertTrue( response.contains( "Please enter your name" ) ); + + } + finally + { + httpClient.stop(); + } + } + + + public int getPort() + throws Exception + { + int attempts = 20; + int port = -1; + String s = System.getProperty("jetty.port.file"); + Assert.assertNotNull(s); + File f = new File(s); + while (true) + { + if (f.exists()) + { + try (FileReader r = new FileReader(f); + LineNumberReader lnr = new LineNumberReader(r); + ) + { + s = lnr.readLine(); + Assert.assertNotNull(s); + port = Integer.parseInt(s.trim()); + } + break; + } + else + { + if (--attempts < 0) + break; + else + Thread.currentThread().sleep(100); + } + } + return port; + } +} diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/pom.xml b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/pom.xml new file mode 100644 index 00000000000..d9e985631b0 --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + + org.olamy + beer + 1.0-SNAPSHOT + + + beer-shared + + + + com.google.gwt + gwt-servlet + provided + + + + + + + maven-source-plugin + + + + diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/FieldVerifier.java b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/FieldVerifier.java new file mode 100644 index 00000000000..8289d061d3a --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/FieldVerifier.java @@ -0,0 +1,60 @@ +// +// ======================================================================== +// 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.olamy; + +/** + *

    + * FieldVerifier validates that the name the user enters is valid. + *

    + *

    + * This class is in the shared project because we use it in both + * the client code and on the server. On the client, we verify that the name is + * valid before sending an RPC request so the user doesn't have to wait for a + * network round trip to get feedback. On the server, we verify that the name is + * correct to ensure that the input is correct regardless of where the RPC + * originates. + *

    + *

    + * When creating a class that is used on both the client and the server, be sure + * that all code is translatable and does not use native JavaScript. Code that + * is not translatable (such as code that interacts with a database or the file + * system) cannot be compiled into client side JavaScript. Code that uses native + * JavaScript (such as Widgets) cannot be run on the server. + *

    + */ +public class FieldVerifier { + + /** + * Verifies that the specified name is valid for our service. + * + * In this example, we only require that the name is at least four + * characters. In your application, you can use more complex checks to ensure + * that usernames, passwords, email addresses, URLs, and other fields have the + * proper syntax. + * + * @param name the name to validate + * @return true if valid, false if invalid + */ + public static boolean isValidName(String name) { + if (name == null) { + return false; + } + return name.length() > 3; + } +} diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingResponse.java b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingResponse.java new file mode 100644 index 00000000000..df2d178fee5 --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingResponse.java @@ -0,0 +1,52 @@ +// +// ======================================================================== +// 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.olamy; + +import java.io.Serializable; + +@SuppressWarnings("serial") +public class GreetingResponse implements Serializable { + private String greeting; + private String serverInfo; + private String userAgent; + + public String getGreeting() { + return greeting; + } + + public void setGreeting(String greeting) { + this.greeting = greeting; + } + + public String getServerInfo() { + return serverInfo; + } + + public void setServerInfo(String serverInfo) { + this.serverInfo = serverInfo; + } + + public String getUserAgent() { + return userAgent; + } + + public void setUserAgent(String userAgent) { + this.userAgent = userAgent; + } +} \ No newline at end of file diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingService.java b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingService.java new file mode 100644 index 00000000000..0ee0b16d53c --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingService.java @@ -0,0 +1,30 @@ +// +// ======================================================================== +// 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.olamy; + +import com.google.gwt.user.client.rpc.RemoteService; +import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; + +/** + * The client side stub for the RPC service. + */ +@RemoteServiceRelativePath("greet") +public interface GreetingService extends RemoteService { + GreetingResponse greetServer(String name) throws IllegalArgumentException; +} diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingServiceAsync.java b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingServiceAsync.java new file mode 100644 index 00000000000..1b39c63cc3c --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/beer-shared/src/main/java/org/olamy/GreetingServiceAsync.java @@ -0,0 +1,29 @@ +// +// ======================================================================== +// 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.olamy; + +import com.google.gwt.user.client.rpc.AsyncCallback; + +/** + * The async counterpart of GreetingService. + */ +public interface GreetingServiceAsync { + void greetServer(String input, AsyncCallback callback) + throws IllegalArgumentException; +} diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/invoker.properties b/jetty-maven-plugin/src/it/run-mojo-gwt-it/invoker.properties new file mode 100644 index 00000000000..26652d0273a --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/invoker.properties @@ -0,0 +1 @@ +invoker.goals = verify \ No newline at end of file diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/pom.xml b/jetty-maven-plugin/src/it/run-mojo-gwt-it/pom.xml new file mode 100644 index 00000000000..2481085ced6 --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/pom.xml @@ -0,0 +1,91 @@ + + + 4.0.0 + + org.olamy + beer + 1.0-SNAPSHOT + pom + + + UTF-8 + @project.version@ + + + + + + com.google.gwt + gwt + 2.8.2 + pom + import + + + javax.servlet + javax.servlet-api + 3.1.0 + + + + + + + + net.ltgt.gwt.maven + gwt-maven-plugin + false + + ${project.build.directory}/gwt/launcherDir + + + + + + + maven-compiler-plugin + 3.1 + + 1.8 + 1.8 + + + + org.eclipse.jetty + jetty-maven-plugin + ${jetty.version} + + + + + net.ltgt.gwt.maven + gwt-maven-plugin + 1.0-rc-9 + true + + 1.8 + true + + + + maven-source-plugin + 3.0.1 + + + attach-sources + package + + jar-no-fork + + + + + + + + + beer-client + beer-shared + beer-server + + diff --git a/jetty-maven-plugin/src/it/run-mojo-gwt-it/verify.groovy b/jetty-maven-plugin/src/it/run-mojo-gwt-it/verify.groovy new file mode 100644 index 00000000000..822aaae276a --- /dev/null +++ b/jetty-maven-plugin/src/it/run-mojo-gwt-it/verify.groovy @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +File buildLog = new File( basedir, 'build.log' ) +assert buildLog.text.contains( 'Started Jetty Server' ) +assert buildLog.text.contains( 'Running org.olamy.TestGetContent') \ No newline at end of file diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java index c82a47fa91a..6adb9d98336 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java @@ -156,14 +156,10 @@ public class JettyRunMojo extends AbstractJettyMojo * List of deps that are wars */ protected List warArtifacts; - - + protected Resource originalBaseResource; - @Parameter(defaultValue = "${reactorProjects}", readonly = true, required = true) - private List reactorProjects; - - /** + /** * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#execute() */ @Override diff --git a/jetty-osgi/test-jetty-osgi/pom.xml b/jetty-osgi/test-jetty-osgi/pom.xml index 9f8de115a82..082581a7d8c 100644 --- a/jetty-osgi/test-jetty-osgi/pom.xml +++ b/jetty-osgi/test-jetty-osgi/pom.xml @@ -590,26 +590,6 @@ - - jdk10 - - 10 - - - - - org.apache.maven.plugins - maven-surefire-plugin - - ${skipTests} - - **/**/TestJettyOSGiBoot** - - - - - - jdk11 @@ -630,28 +610,5 @@ - - - alltests - - - alltests - true - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - FOOBAR - - - - - - diff --git a/jetty-server/src/main/config/etc/jetty.xml b/jetty-server/src/main/config/etc/jetty.xml index d056f22c927..9ddf95aff2c 100644 --- a/jetty-server/src/main/config/etc/jetty.xml +++ b/jetty-server/src/main/config/etc/jetty.xml @@ -62,7 +62,7 @@ - + diff --git a/jetty-server/src/main/config/modules/server.mod b/jetty-server/src/main/config/modules/server.mod index ed7d608d01f..de983ae0fef 100644 --- a/jetty-server/src/main/config/modules/server.mod +++ b/jetty-server/src/main/config/modules/server.mod @@ -59,9 +59,6 @@ etc/jetty.xml ## Maximum number of error dispatches to prevent looping # jetty.httpConfig.maxErrorDispatches=10 -## Maximum time to block in total for a blocking IO operation (default -1 is to use idleTimeout on progress) -# jetty.httpConfig.blockingTimeout=-1 - ## Cookie compliance mode of: RFC2965, RFC6265 # jetty.httpConfig.cookieCompliance=RFC6265 diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index 9ab2ba49179..f57700cb211 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -563,10 +563,10 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor } else if (failure instanceof BadMessageException | failure instanceof IOException | failure instanceof TimeoutException) { + // No stack trace unless there is debug turned on + LOG.warn("{} {}",_request.getRequestURI(), failure.toString()); if (LOG.isDebugEnabled()) LOG.debug(_request.getRequestURI(), failure); - else - LOG.warn(_request.getRequestURI(), failure); } else { @@ -721,7 +721,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor { action=_state.handling(); } - catch(IllegalStateException e) + catch(Throwable e) { // The bad message cannot be handled in the current state, // so rethrow, hopefully somebody will be able to handle. @@ -749,12 +749,15 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor } finally { - // TODO: review whether it's the right state to check. - if (_state.unhandle()==Action.COMPLETE) - _state.onComplete(); - else - throw new IllegalStateException(); // TODO: don't throw from finally blocks ! - onCompleted(); + try + { + onCompleted(); + } + catch(Throwable e) + { + LOG.debug(e); + abort(e); + } } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java index 59e6f23aff9..9c246e73a48 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java @@ -31,6 +31,8 @@ import org.eclipse.jetty.util.TreeTrie; import org.eclipse.jetty.util.Trie; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; /** * HTTP Configuration. @@ -46,6 +48,8 @@ import org.eclipse.jetty.util.annotation.ManagedObject; @ManagedObject("HTTP Configuration") public class HttpConfiguration { + private static final Logger LOG = Log.getLogger(HttpConfiguration.class); + public static final String SERVER_VERSION = "Jetty(" + Jetty.VERSION + ")"; private final List _customizers=new CopyOnWriteArrayList<>(); private final Trie _formEncodedMethods = new TreeTrie<>(); @@ -239,8 +243,10 @@ public class HttpConfiguration * * @return -1, for no blocking timeout (default), 0 for a blocking timeout equal to the * idle timeout; >0 for a timeout in ms applied to the total blocking operation. + * @deprecated Replaced by {@link #getMinResponseDataRate()} and {@link #getMinRequestDataRate()} */ - @ManagedAttribute("Total timeout in ms for blocking I/O operations.") + @ManagedAttribute(value = "Total timeout in ms for blocking I/O operations. DEPRECATED!", readonly = true) + @Deprecated public long getBlockingTimeout() { return _blockingTimeout; @@ -254,9 +260,13 @@ public class HttpConfiguration * * @param blockingTimeout -1, for no blocking timeout (default), 0 for a blocking timeout equal to the * idle timeout; >0 for a timeout in ms applied to the total blocking operation. + * @deprecated Replaced by {@link #setMinResponseDataRate(long)} and {@link #setMinRequestDataRate(long)} */ + @Deprecated public void setBlockingTimeout(long blockingTimeout) { + if (blockingTimeout>0) + LOG.warn("HttpConfiguration.setBlockingTimeout is deprecated!"); _blockingTimeout = blockingTimeout; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java index 40aefbf3136..1a491a4c069 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java @@ -679,11 +679,16 @@ public class HttpInput extends ServletInputStream implements Runnable skip(item, item.remaining()); } - return isFinished() && !isError(); + if (isFinished()) + return !isError(); + + _state = EARLY_EOF; + return false; } - catch (IOException e) + catch (Throwable e) { LOG.debug(e); + _state = new ErrorState(e); return false; } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java b/jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java index 784f87643a2..d283579093e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java @@ -18,11 +18,12 @@ package org.eclipse.jetty.server; +import java.util.ArrayList; import java.util.Enumeration; +import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; -import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -54,8 +55,8 @@ public class InclusiveByteRange { private static final Logger LOG = Log.getLogger(InclusiveByteRange.class); - long first = 0; - long last = 0; + private long first; + private long last; public InclusiveByteRange(long first, long last) { @@ -74,19 +75,87 @@ public class InclusiveByteRange } + /* ------------------------------------------------------------ */ + private void coalesce(InclusiveByteRange r) + { + first = Math.min(first,r.first); + last = Math.max(last,r.last); + } + + /* ------------------------------------------------------------ */ + private boolean overlaps(InclusiveByteRange range) + { + return (range.first>=this.first && range.first<=this.last) + || + (range.last>=this.first && range.last<=this.last) + || + (range.firstthis.last); + } + + /* ------------------------------------------------------------ */ + public long getSize() + { + return last-first+1; + } + + /* ------------------------------------------------------------ */ + public String toHeaderRangeString(long size) + { + StringBuilder sb = new StringBuilder(40); + sb.append("bytes "); + sb.append(first); + sb.append('-'); + sb.append(last); + sb.append("/"); + sb.append(size); + return sb.toString(); + } + + /* ------------------------------------------------------------ */ + @Override + public int hashCode() + { + return (int)(first ^ last); + } + + /* ------------------------------------------------------------ */ + @Override + public boolean equals( Object obj ) + { + if(obj == null) + return false; + + if(!(obj instanceof InclusiveByteRange)) + return false; + + return ((InclusiveByteRange)obj).first == this.first && + ((InclusiveByteRange)obj).last == this.last; + } + + /* ------------------------------------------------------------ */ + @Override + public String toString() + { + StringBuilder sb = new StringBuilder(60); + sb.append(Long.toString(first)); + sb.append(":"); + sb.append(Long.toString(last)); + return sb.toString(); + } + /* ------------------------------------------------------------ */ /** * @param headers Enumeration of Range header fields. * @param size Size of the resource. - * @return LazyList of satisfiable ranges + * @return List of satisfiable ranges */ public static List satisfiableRanges(Enumeration headers, long size) { - Object satRanges=null; + List ranges = null; + final long end = size-1; // walk through all Range headers - headers: while (headers.hasMoreElements()) { String header = headers.nextElement(); @@ -100,52 +169,89 @@ public class InclusiveByteRange try { t = tok.nextToken().trim(); + if ("bytes".equals(t)) + continue; long first = -1; long last = -1; - int d = t.indexOf('-'); - if (d < 0 || t.indexOf("-",d + 1) >= 0) + int dash = t.indexOf('-'); + if (dash < 0 || t.indexOf("-",dash + 1) >= 0) { - if ("bytes".equals(t)) - continue; LOG.warn("Bad range format: {}",t); - continue headers; + break; } - else if (d == 0) + + if (dash>0) + first = Long.parseLong(t.substring(0,dash).trim()); + if (dash<(t.length()-1)) + last = Long.parseLong(t.substring(dash + 1).trim()); + + if (first==-1) { - if (d + 1 < t.length()) - last = Long.parseLong(t.substring(d + 1).trim()); - else + if (last==-1) { LOG.warn("Bad range format: {}",t); + break; + } + + if (last==0) continue; + + // This is a suffix range + first = Math.max(0,size-last); + last = end; + } + else + { + // Range starts after end + if (first>=size) + continue; + + if (last==-1) + last = end; + else if (last>=end) + last = end; + } + + if (last(); + + boolean coalesced = false; + for (Iterator i = ranges.listIterator(); i.hasNext();) + { + InclusiveByteRange r = i.next(); + if (range.overlaps(r)) + { + coalesced = true; + r.coalesce(range); + while(i.hasNext()) + { + InclusiveByteRange r2 = i.next(); + + if (r2.overlaps(r)) + { + r.coalesce(r2); + i.remove(); + } + } } } - else if (d + 1 < t.length()) - { - first = Long.parseLong(t.substring(0,d).trim()); - last = Long.parseLong(t.substring(d + 1).trim()); - } - else - first = Long.parseLong(t.substring(0,d).trim()); + + if (!coalesced) + ranges.add(range); - if (first == -1 && last == -1) - continue headers; - - if (first != -1 && last != -1 && (first > last)) - continue headers; - - if (first < size) - { - InclusiveByteRange range = new InclusiveByteRange(first,last); - satRanges = LazyList.add(satRanges,range); - } } catch (NumberFormatException e) { LOG.warn("Bad range format: {}",t); LOG.ignore(e); - continue; } } } @@ -155,51 +261,8 @@ public class InclusiveByteRange LOG.ignore(e); } } - return LazyList.getList(satRanges,true); - } - - /* ------------------------------------------------------------ */ - public long getFirst(long size) - { - if (first<0) - { - long tf=size-last; - if (tf<0) - tf=0; - return tf; - } - return first; - } - - /* ------------------------------------------------------------ */ - public long getLast(long size) - { - if (first<0) - return size-1; - if (last<0 ||last>=size) - return size-1; - return last; - } - - /* ------------------------------------------------------------ */ - public long getSize(long size) - { - return getLast(size)-getFirst(size)+1; - } - - - /* ------------------------------------------------------------ */ - public String toHeaderRangeString(long size) - { - StringBuilder sb = new StringBuilder(40); - sb.append("bytes "); - sb.append(getFirst(size)); - sb.append('-'); - sb.append(getLast(size)); - sb.append("/"); - sb.append(size); - return sb.toString(); + return ranges; } /* ------------------------------------------------------------ */ @@ -212,18 +275,6 @@ public class InclusiveByteRange } - /* ------------------------------------------------------------ */ - @Override - public String toString() - { - StringBuilder sb = new StringBuilder(60); - sb.append(Long.toString(first)); - sb.append(":"); - sb.append(Long.toString(last)); - return sb.toString(); - } - - } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java index e4d2ff75a17..84504a0eb41 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java @@ -524,45 +524,51 @@ public class ProxyConnectionFactory extends AbstractConnectionFactory if (LOG.isDebugEnabled()) LOG.debug(String.format("T=%x L=%d V=%s for %s", type, length, TypeUtil.toHexString(value), this)); - // TODO interpret these values switch (type) { - case 0x01: // PP2_TYPE_ALPN - break; - case 0x02: // PP2_TYPE_AUTHORITY - break; case 0x20: // PP2_TYPE_SSL { - int i = 0; - int client = 0xff & value[i++]; - while (i < value.length) + int client = value[0] & 0xFF; + switch (client) { - int ssl_type = 0xff & value[i++]; - int ssl_length = (0xff & value[i++]) * 0x100 + (0xff & value[i++]); - byte[] ssl_val = new byte[ssl_length]; - System.arraycopy(value, i, ssl_val, 0, ssl_length); - i += ssl_length; - - switch (ssl_type) + case 0x01: // PP2_CLIENT_SSL { - case 0x21: // PP2_TYPE_SSL_VERSION - String version = new String(ssl_val, 0, ssl_length, StandardCharsets.ISO_8859_1); - if (client == 1) - proxyEndPoint.setAttribute(TLS_VERSION, version); - break; - - default: - break; + int i = 5; // Index of the first sub_tlv, after verify. + while (i < length) + { + int subType = value[i++] & 0xFF; + int subLength = (value[i++] & 0xFF) * 256 + (value[i++] & 0xFF); + byte[] subValue = new byte[subLength]; + System.arraycopy(value, i, subValue, 0, subLength); + i += subLength; + switch (subType) + { + case 0x21: // PP2_SUBTYPE_SSL_VERSION + String tlsVersion = new String(subValue, StandardCharsets.US_ASCII); + proxyEndPoint.setAttribute(TLS_VERSION, tlsVersion); + break; + case 0x22: // PP2_SUBTYPE_SSL_CN + case 0x23: // PP2_SUBTYPE_SSL_CIPHER + case 0x24: // PP2_SUBTYPE_SSL_SIG_ALG + case 0x25: // PP2_SUBTYPE_SSL_KEY_ALG + default: + break; + } + } + break; } + case 0x02: // PP2_CLIENT_CERT_CONN + case 0x04: // PP2_CLIENT_CERT_SESS + default: + break; } break; } - case 0x21: // PP2_TYPE_SSL_VERSION - break; - case 0x22: // PP2_TYPE_SSL_CN - break; + case 0x01: // PP2_TYPE_ALPN + case 0x02: // PP2_TYPE_AUTHORITY + case 0x03: // PP2_TYPE_CRC32C + case 0x04: // PP2_TYPE_NOOP case 0x30: // PP2_TYPE_NETNS - break; default: break; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java index f95402276ea..73c6b1be12e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java @@ -735,7 +735,7 @@ public class ResourceService else { // Parse the satisfiable ranges - List ranges =InclusiveByteRange.satisfiableRanges(reqRanges,content_length); + List ranges =InclusiveByteRange.satisfiableRanges( reqRanges, content_length); // if there are no satisfiable ranges, send 416 response if (ranges==null || ranges.size()==0) @@ -752,15 +752,15 @@ public class ResourceService // since were here now), send that range with a 216 response if ( ranges.size()== 1) { - InclusiveByteRange singleSatisfiableRange = ranges.get(0); - long singleLength = singleSatisfiableRange.getSize(content_length); + InclusiveByteRange singleSatisfiableRange = ranges.iterator().next(); + long singleLength = singleSatisfiableRange.getSize(); putHeaders(response,content,singleLength); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); if (!response.containsHeader(HttpHeader.DATE.asString())) response.addDateHeader(HttpHeader.DATE.asString(),System.currentTimeMillis()); response.setHeader(HttpHeader.CONTENT_RANGE.asString(), singleSatisfiableRange.toHeaderRangeString(content_length)); - content.getResource().writeTo(out,singleSatisfiableRange.getFirst(content_length),singleLength); + content.getResource().writeTo(out,singleSatisfiableRange.getFirst(),singleLength); return true; } @@ -793,9 +793,9 @@ public class ResourceService // calculate the content-length int length=0; String[] header = new String[ranges.size()]; - for (int i=0;i0)?2:0)+ @@ -803,18 +803,19 @@ public class ResourceService (mimetype==null?0:HttpHeader.CONTENT_TYPE.asString().length()+2+mimetype.length())+2+ HttpHeader.CONTENT_RANGE.asString().length()+2+header[i].length()+2+ 2+ - (ibr.getLast(content_length)-ibr.getFirst(content_length))+1; + (ibr.getLast()-ibr.getFirst())+1; + i++; } length+=2+2+multi.getBoundary().length()+2+2; response.setContentLength(length); - for (int i=0;i strings = new Vector<>(); strings.add(rangeString); - List ranges = InclusiveByteRange.satisfiableRanges(strings.elements(),200); + List ranges = InclusiveByteRange.satisfiableRanges( strings.elements(), 200); assertNull("Invalid Range [" + rangeString + "] should result in no satisfiable ranges",ranges); } private void assertRange(String msg, int expectedFirst, int expectedLast, int size, InclusiveByteRange actualRange) { - assertEquals(msg + " - first",expectedFirst,actualRange.getFirst(size)); - assertEquals(msg + " - last",expectedLast,actualRange.getLast(size)); + assertEquals(msg + " - first",expectedFirst,actualRange.getFirst()); + assertEquals(msg + " - last",expectedLast,actualRange.getLast()); String expectedHeader = String.format("bytes %d-%d/%d",expectedFirst,expectedLast,size); assertEquals(msg + " - header range string",expectedHeader,actualRange.toHeaderRangeString(size)); } @@ -54,32 +55,30 @@ public class InclusiveByteRangeTest { InclusiveByteRange range = parseRange(rangeId,size); - assertEquals("Range [" + rangeId + "] - first",expectedFirst,range.getFirst(size)); - assertEquals("Range [" + rangeId + "] - last",expectedLast,range.getLast(size)); + assertEquals("Range [" + rangeId + "] - first",expectedFirst,range.getFirst()); + assertEquals("Range [" + rangeId + "] - last",expectedLast,range.getLast()); String expectedHeader = String.format("bytes %d-%d/%d",expectedFirst,expectedLast,size); assertEquals("Range [" + rangeId + "] - header range string",expectedHeader,range.toHeaderRangeString(size)); } - @SuppressWarnings("unchecked") private InclusiveByteRange parseRange(String rangeString, int size) { - Vector strings = new Vector(); + Vector strings = new Vector<>(); strings.add(rangeString); - List ranges = InclusiveByteRange.satisfiableRanges(strings.elements(),size); + List ranges = InclusiveByteRange.satisfiableRanges(strings.elements(),size); assertNotNull("Satisfiable Ranges should not be null",ranges); assertEquals("Satisfiable Ranges of [" + rangeString + "] count",1,ranges.size()); - return (InclusiveByteRange)ranges.get(0); + return (InclusiveByteRange)ranges.iterator().next(); } - @SuppressWarnings("unchecked") - private List parseRanges(String rangeString, int size) + private List parseRanges(int size, String... rangeString) { - Vector strings = new Vector(); - strings.add(rangeString); + Vector strings = new Vector<>(); + for (String range : rangeString) + strings.add(range); - List ranges; - ranges = InclusiveByteRange.satisfiableRanges(strings.elements(),size); + List ranges = InclusiveByteRange.satisfiableRanges(strings.elements(),size); assertNotNull("Satisfiable Ranges should not be null",ranges); return ranges; } @@ -112,10 +111,26 @@ public class InclusiveByteRangeTest rangeString = "bytes=5-20,35-65"; - List ranges = parseRanges(rangeString,size); + List ranges = parseRanges(size,rangeString); assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); - assertRange("Range [" + rangeString + "]",5,20,size,ranges.get(0)); - assertRange("Range [" + rangeString + "]",35,49,size,ranges.get(1)); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",5,20,size,inclusiveByteRangeIterator.next()); + assertRange("Range [" + rangeString + "]",35,49,size,inclusiveByteRangeIterator.next()); + } + + /** + * Ranges have a multiple ranges, all absolutely defined. + */ + @Test + public void testMultipleAbsoluteRangesSplit() + { + int size = 50; + + List ranges = parseRanges(size,"bytes=5-20","bytes=35-65"); + assertEquals(2,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("testMultipleAbsoluteRangesSplit[0]",5,20,size,inclusiveByteRangeIterator.next()); + assertRange("testMultipleAbsoluteRangesSplit[1]",35,49,size,inclusiveByteRangeIterator.next()); } /** @@ -124,42 +139,122 @@ public class InclusiveByteRangeTest @Test public void testMultipleRangesClipped() { + int size = 50; String rangeString; rangeString = "bytes=5-20,35-65,-5"; - List ranges = parseRanges(rangeString,50); - assertEquals("Satisfiable Ranges of [" + rangeString + "] count",3,ranges.size()); - assertRange("Range [" + rangeString + "]",5,20,50,ranges.get(0)); - assertRange("Range [" + rangeString + "]",35,49,50,ranges.get(1)); - assertRange("Range [" + rangeString + "]",45,49,50,ranges.get(2)); + List ranges = parseRanges(size,rangeString); + assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",5,20,size,inclusiveByteRangeIterator.next()); + assertRange("Range [" + rangeString + "]",35,49,size,inclusiveByteRangeIterator.next()); } @Test public void testMultipleRangesOverlapping() { + int size = 200; String rangeString; rangeString = "bytes=5-20,15-25"; - List ranges = parseRanges(rangeString,200); - assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); - assertRange("Range [" + rangeString + "]",5,20,200,ranges.get(0)); - assertRange("Range [" + rangeString + "]",15,25,200,ranges.get(1)); + List ranges = parseRanges(size,rangeString); + assertEquals("Satisfiable Ranges of [" + rangeString + "] count",1,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",5,25,size,inclusiveByteRangeIterator.next()); } @Test public void testMultipleRangesSplit() { + int size = 200; String rangeString; rangeString = "bytes=5-10,15-20"; - List ranges = parseRanges(rangeString,200); + List ranges = parseRanges(size,rangeString); assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); - assertRange("Range [" + rangeString + "]",5,10,200,ranges.get(0)); - assertRange("Range [" + rangeString + "]",15,20,200,ranges.get(1)); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",5,10,size,inclusiveByteRangeIterator.next()); + assertRange("Range [" + rangeString + "]",15,20,size,inclusiveByteRangeIterator.next()); } + @Test + public void testMultipleSameRangesSplit() + { + int size = 200; + String rangeString; + rangeString = "bytes=5-10,15-20,5-10,15-20,5-10,5-10,5-10,5-10,5-10,5-10"; + + List ranges = parseRanges(size,rangeString); + assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",5,10,size,inclusiveByteRangeIterator.next()); + assertRange("Range [" + rangeString + "]",15,20,size,inclusiveByteRangeIterator.next()); + } + + @Test + public void testMultipleOverlappingRanges() + { + int size = 200; + String rangeString; + rangeString = "bytes=5-15,20-30,10-25"; + + List ranges = parseRanges(size,rangeString); + assertEquals("Satisfiable Ranges of [" + rangeString + "] count",1,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",5,30,size,inclusiveByteRangeIterator.next()); + } + + @Test + public void testMultipleOverlappingRangesOrdered() + { + int size = 200; + String rangeString; + rangeString = "bytes=20-30,5-15,0-5,25-35"; + + List ranges = parseRanges(size,rangeString); + assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",20,35,size,inclusiveByteRangeIterator.next()); + assertRange("Range [" + rangeString + "]",0,15,size,inclusiveByteRangeIterator.next()); + } + + @Test + public void testMultipleOverlappingRangesOrderedSplit() + { + int size = 200; + String rangeString; + rangeString = "bytes=20-30,5-15,0-5,25-35"; + List ranges = parseRanges(size,"bytes=20-30","bytes=5-15","bytes=0-5,25-35"); + + assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",20,35,size,inclusiveByteRangeIterator.next()); + assertRange("Range [" + rangeString + "]",0,15,size,inclusiveByteRangeIterator.next()); + } + + @Test + public void testNasty() + { + int size = 200; + String rangeString; + + rangeString = "bytes=90-100, 10-20, 30-40, -161"; + List ranges = parseRanges(size,rangeString); + + assertEquals("Satisfiable Ranges of [" + rangeString + "] count",2,ranges.size()); + Iterator inclusiveByteRangeIterator = ranges.iterator(); + assertRange("Range [" + rangeString + "]",30,199,size,inclusiveByteRangeIterator.next()); + assertRange("Range [" + rangeString + "]",10,20,size,inclusiveByteRangeIterator.next()); + } + + @Test + public void testRange_OpenEnded() + { + assertSimpleRange(50, 499, "bytes=50-", 500); + } + @Test public void testSimpleRange() { @@ -167,5 +262,93 @@ public class InclusiveByteRangeTest assertSimpleRange(195,199,"bytes=-5",200); assertSimpleRange(50,119,"bytes=50-150",120); assertSimpleRange(50,119,"bytes=50-",120); + + assertSimpleRange(1,50,"bytes= 1 - 50",120); + } + + // TODO: evaluate this vs assertInvalidRange() above, which behavior is correct? null? or empty list? + private void assertBadRangeList(int size, String badRange) + { + Vector strings = new Vector<>(); + strings.add(badRange); + + List ranges = InclusiveByteRange.satisfiableRanges(strings.elements(),size); + // if one part is bad, the entire set of ranges should be treated as bad, per RFC7233 + assertThat("Should have no ranges", ranges, is(nullValue())); + } + + @Test + @Ignore + public void testBadRange_SetPartiallyBad() + { + assertBadRangeList(500, "bytes=1-50,1-b,a-50"); + } + + @Test + public void testBadRange_NoNumbers() + { + assertBadRangeList(500, "bytes=a-b"); + } + + @Test + public void testBadRange_Empty() + { + assertBadRangeList(500, "bytes="); + } + + @Test + @Ignore + public void testBadRange_ZeroPrefixed() + { + assertBadRangeList(500, "bytes=01-050"); + } + + @Test + public void testBadRange_Hex() + { + assertBadRangeList(500, "bytes=0F-FF"); + } + + @Test + @Ignore + public void testBadRange_TabWhitespace() + { + assertBadRangeList(500, "bytes=\t1\t-\t50"); + } + + @Test + public void testBadRange_TabDelim() + { + assertBadRangeList(500, "bytes=1-50\t90-101\t200-250"); + } + + @Test + public void testBadRange_SemiColonDelim() + { + assertBadRangeList(500, "bytes=1-50;90-101;200-250"); + } + + @Test + public void testBadRange_NegativeSize() + { + assertBadRangeList(500, "bytes=50-1"); + } + + @Test + public void testBadRange_DoubleDash() + { + assertBadRangeList(500, "bytes=1--20"); + } + + @Test + public void testBadRange_TrippleDash() + { + assertBadRangeList(500, "bytes=1---"); + } + + @Test + public void testBadRange_ZeroedNegativeSize() + { + assertBadRangeList(500, "bytes=050-001"); } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java b/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java index 8dc10c5cfd8..2d7a3e857c2 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java @@ -269,6 +269,39 @@ public class PartialRFC2616Test assertEquals("Quality parameters","ccc",HttpFields.valueParameters(list.get(4),null)); assertEquals("Quality parameters","ddd",HttpFields.valueParameters(list.get(5),null)); } + + + + @Test + public void test4_1() throws Exception + { + int offset=0; + // If _content length not used, second request will not be read. + String response = connector.getResponses( + "\r\n" + + "GET /R1 HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "\r\n" + + "\r\n" + + "\r\n" + + "\r\n" + + "GET /R2 HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "\r\n" + + " \r\n" + + "GET /R3 HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Connection: close\r\n" + + "\r\n" + ); + offset=checkContains(response,offset,"HTTP/1.1 200 OK","2. identity")+10; + offset=checkContains(response,offset,"/R1","2. identity")+3; + offset=checkContains(response,offset,"HTTP/1.1 200 OK","2. identity")+10; + offset=checkContains(response,offset,"/R2","2. identity")+3; + checkNotContained(response,offset,"HTTP/1.1 200 OK","2. identity"); + checkNotContained(response,offset,"/R3","2. identity"); + } + @Test public void test4_4_2() throws Exception @@ -303,8 +336,8 @@ public class PartialRFC2616Test @Test public void test4_4_3() throws Exception { - // _content length is ignored, as chunking is used. If it is - // not ignored, the second request wont be seen. + // Due to smuggling concerns, handling has been changed to + // treat content length and chunking as a bad request. int offset=0; String response; LocalEndPoint endp=connector.executeRequest( @@ -328,16 +361,9 @@ public class PartialRFC2616Test "Content-Length: 6\n" + "\n" + "abcdef"); - offset=0; response = endp.getResponse(); - offset=checkContains(response,offset,"HTTP/1.1 200 OK","3. ignore c-l")+1; - offset=checkContains(response,offset,"/R1","3. ignore c-l")+1; - offset=checkContains(response,offset,"123456","3. ignore c-l")+1; - offset=0; - response = endp.getResponse(); - offset=checkContains(response,offset,"HTTP/1.1 200 OK","3. ignore c-l")+1; - offset=checkContains(response,offset,"/R2","3. _content-length")+1; - offset=checkContains(response,offset,"abcdef","3. _content-length")+1; + offset=checkContains(response,offset,"HTTP/1.1 400 Bad","3. ignore c-l")+1; + checkNotContained(response,offset,"/R2","3. _content-length"); } @Test diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletRangesTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletRangesTest.java index 8e5ec88648a..b359f2a87bd 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletRangesTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletRangesTest.java @@ -18,12 +18,15 @@ package org.eclipse.jetty.servlet; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.LocalConnector; @@ -32,7 +35,6 @@ import org.eclipse.jetty.toolchain.test.FS; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.OS; import org.eclipse.jetty.toolchain.test.TestingDir; -import org.eclipse.jetty.util.IO; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Assert; @@ -161,6 +163,59 @@ public class DefaultServletRangesTest } + + @Test + public void testMultipleSameRangeRequests() throws Exception + { + StringBuilder stringBuilder = new StringBuilder( ); + for(int i = 0; i < 1000; i++) + { + stringBuilder.append( "10-60," ); + } + + + String response; + response = connector.getResponse( + "GET /context/data.txt HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Connection: close\r\n"+ + "Range: bytes=" + stringBuilder.toString() +"0-2\r\n" + + "\r\n"); + int start = response.indexOf("--jetty"); + String body = response.substring(start); + String boundary = body.substring(0, body.indexOf("\r\n")); + assertResponseContains("206 Partial", response); + assertResponseContains("Content-Type: multipart/byteranges; boundary=", response); + + assertResponseContains("Content-Range: bytes 10-60/80", response); + assertResponseContains("Content-Range: bytes 0-2/80", response); + Assert.assertEquals( "Content range 0-60/80 in response not only 1:" + response , // + 2, response.split( "Content-Range: bytes 10-60/80" ).length); + assertTrue(body.endsWith(boundary + "--\r\n")); + } + + @Test + public void testMultipleSameRangeRequestsTooLargeHeader() throws Exception + { + StringBuilder stringBuilder = new StringBuilder( ); + for(int i = 0; i < 2000; i++) + { + stringBuilder.append( "10-60," ); + } + + + String response; + response = connector.getResponse( + "GET /context/data.txt HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Connection: close\r\n"+ + "Range: bytes=" + stringBuilder.toString() +"0-2\r\n" + + "\r\n"); + int start = response.indexOf("--jetty"); + assertEquals( -1, start ); + assertResponseContains("HTTP/1.1 431 Request Header Fields Too Large", response); + } + @Test public void testOpenEndRange() throws Exception { @@ -211,17 +266,11 @@ public class DefaultServletRangesTest private void createFile(File file, String str) throws IOException { - FileOutputStream out = null; - try + try(OutputStream out = Files.newOutputStream( file.toPath())) { - out = new FileOutputStream(file); out.write(str.getBytes(StandardCharsets.UTF_8)); out.flush(); } - finally - { - IO.close(out); - } } private void assertResponseNotContains(String forbidden, String response) diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java index 403eabac7d1..8820adc1c0b 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java @@ -1285,7 +1285,7 @@ public class StartArgs } } - // to override default https://central.maven.org/maven2/ + // to override default https://repo1.maven.org/maven2/ if (key.equals("maven.repo.uri")) { this.mavenBaseUri = value; diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/fileinits/MavenLocalRepoFileInitializer.java b/jetty-start/src/main/java/org/eclipse/jetty/start/fileinits/MavenLocalRepoFileInitializer.java index cd5e1c74a82..23bda3963e4 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/fileinits/MavenLocalRepoFileInitializer.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/fileinits/MavenLocalRepoFileInitializer.java @@ -56,7 +56,7 @@ public class MavenLocalRepoFileInitializer extends FileInitializer public String version; public String type; public String classifier; - private String mavenRepoUri = "https://central.maven.org/maven2/"; + private String mavenRepoUri = "https://repo1.maven.org/maven2/"; public String toPath() { @@ -218,4 +218,17 @@ public class MavenLocalRepoFileInitializer extends FileInitializer return coords; } + + /** + * protected only for testing purpose + * @param uri the the uri to download + * @param destination the destination File + * @throws IOException + */ + @Override + protected void download( URI uri, Path destination ) + throws IOException + { + super.download( uri, destination ); + } } diff --git a/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt b/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt index ca52da66ef8..f0ec8ce742b 100644 --- a/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt +++ b/jetty-start/src/main/resources/org/eclipse/jetty/start/usage.txt @@ -166,7 +166,7 @@ Advanced Commands: 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/. @@ -221,7 +221,7 @@ Properties: Jetty server has stopped. If not specified, the stopper will wait indefinitely. Use in conjunction with the --stop option. - maven.repo.uri=[url] default http://central.maven.org/maven2/. + maven.repo.uri=[url] default https://repo1.maven.org/maven2/. The url to use to download Maven dependencies. diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/fileinits/MavenLocalRepoFileInitializerTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/fileinits/MavenLocalRepoFileInitializerTest.java index 89787060bda..0e536272da3 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/fileinits/MavenLocalRepoFileInitializerTest.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/fileinits/MavenLocalRepoFileInitializerTest.java @@ -26,7 +26,9 @@ import static org.junit.Assert.assertThat; import java.io.IOException; import java.net.URI; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import org.eclipse.jetty.start.BaseHome; import org.eclipse.jetty.start.config.ConfigSources; @@ -95,7 +97,7 @@ public class MavenLocalRepoFileInitializerTest assertThat("coords.classifier",coords.classifier,nullValue()); assertThat("coords.toCentralURI", coords.toCentralURI().toASCIIString(), - is("https://central.maven.org/maven2/org/eclipse/jetty/jetty-start/9.3.x/jetty-start-9.3.x.jar")); + is("https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-start/9.3.x/jetty-start-9.3.x.jar")); } @Test @@ -113,7 +115,7 @@ public class MavenLocalRepoFileInitializerTest assertThat("coords.classifier",coords.classifier,nullValue()); assertThat("coords.toCentralURI", coords.toCentralURI().toASCIIString(), - is("https://central.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.3.x/jetty-distribution-9.3.x.zip")); + is("https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-distribution/9.3.x/jetty-distribution-9.3.x.zip")); } @Test @@ -131,7 +133,7 @@ public class MavenLocalRepoFileInitializerTest assertThat("coords.classifier",coords.classifier,is("tests")); assertThat("coords.toCentralURI", coords.toCentralURI().toASCIIString(), - is("https://central.maven.org/maven2/org/eclipse/jetty/jetty-http/9.3.x/jetty-http-9.3.x-tests.jar")); + is("https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-http/9.3.x/jetty-http-9.3.x-tests.jar")); } @Test @@ -149,7 +151,7 @@ public class MavenLocalRepoFileInitializerTest assertThat("coords.classifier",coords.classifier,is("tests")); assertThat("coords.toCentralURI", coords.toCentralURI().toASCIIString(), - is("https://central.maven.org/maven2/org/eclipse/jetty/jetty-http/9.3.x/jetty-http-9.3.x-tests.jar")); + is("https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-http/9.3.x/jetty-http-9.3.x-tests.jar")); } @Test @@ -157,7 +159,7 @@ public class MavenLocalRepoFileInitializerTest { MavenLocalRepoFileInitializer repo = new MavenLocalRepoFileInitializer(baseHome,null,false, - "https://repo.maven.apache.org/maven2/"); + "https://repo1.maven.org/maven2/"); String ref = "maven://org.eclipse.jetty/jetty-http/9.3.x/jar/tests"; Coordinates coords = repo.getCoordinates(URI.create(ref)); assertThat("Coordinates",coords,notNullValue()); @@ -169,7 +171,36 @@ public class MavenLocalRepoFileInitializerTest assertThat("coords.classifier",coords.classifier,is("tests")); assertThat("coords.toCentralURI", coords.toCentralURI().toASCIIString(), - is("https://repo.maven.apache.org/maven2/org/eclipse/jetty/jetty-http/9.3.x/jetty-http-9.3.x-tests.jar")); + is("https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-http/9.3.x/jetty-http-9.3.x-tests.jar")); + + + } + + + @Test + public void testDownload_default_repo() + throws Exception + { + MavenLocalRepoFileInitializer repo = + new MavenLocalRepoFileInitializer(baseHome,null,false); + String ref = "maven://org.eclipse.jetty/jetty-http/9.4.10.v20180503/jar/tests"; + Coordinates coords = repo.getCoordinates(URI.create(ref)); + assertThat("Coordinates",coords,notNullValue()); + + assertThat("coords.groupId",coords.groupId,is("org.eclipse.jetty")); + assertThat("coords.artifactId",coords.artifactId,is("jetty-http")); + assertThat("coords.version",coords.version,is("9.4.10.v20180503")); + assertThat("coords.type",coords.type,is("jar")); + assertThat("coords.classifier",coords.classifier,is("tests")); + + assertThat("coords.toCentralURI", coords.toCentralURI().toASCIIString(), + is("https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-http/9.4.10.v20180503/jetty-http-9.4.10.v20180503-tests.jar")); + + Path destination = Paths.get(System.getProperty( "java.io.tmpdir" ), "jetty-http-9.4.10.v20180503-tests.jar"); + repo.download( coords.toCentralURI(), destination); + assertThat( Files.exists(destination), is( true )); + assertThat( destination.toFile().length(), is(962621L)); + } } diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_101.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_101.mod index eebd2a92550..c349018defd 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_101.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_101.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_102.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_102.mod index eebd2a92550..c349018defd 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_102.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_102.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_111.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_111.mod index eebd2a92550..c349018defd 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_111.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_111.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_112.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_112.mod index 3887113d09b..1a3c817b03e 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_112.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_112.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_121.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_121.mod index eb50f520252..2381a1dfbf3 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_121.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_121.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_131.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_131.mod index eb50f520252..2381a1dfbf3 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_131.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_131.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_141.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_141.mod index eb50f520252..2381a1dfbf3 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_141.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_141.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_144.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_144.mod index eb50f520252..2381a1dfbf3 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_144.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_144.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_151.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_151.mod index eb50f520252..2381a1dfbf3 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_151.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_151.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_152.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_152.mod index eb50f520252..2381a1dfbf3 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_152.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_152.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_161.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_161.mod index b50a352334d..4807b8fa634 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_161.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_161.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_162.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_162.mod index b50a352334d..4807b8fa634 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_162.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_162.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_171.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_171.mod index b50a352334d..4807b8fa634 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_171.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_171.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_172.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_172.mod index b50a352334d..4807b8fa634 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_172.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_172.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_91.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_91.mod index 47bc2df34c1..5833ea84f55 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_91.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_91.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_92.mod b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_92.mod index 10d83db2181..e269346d071 100644 --- a/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_92.mod +++ b/jetty-start/src/test/resources/dist-home/modules/alpn-impl/alpn-1.8.0_92.mod @@ -1,5 +1,5 @@ [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 diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Retainable.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Retainable.java new file mode 100644 index 00000000000..3fcc03ddbef --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Retainable.java @@ -0,0 +1,24 @@ +// +// ======================================================================== +// 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.util; + +public interface Retainable +{ + public void retain(); +} diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java index bdaabc174ca..33a4dfd0f8c 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java @@ -48,7 +48,7 @@ import org.eclipse.jetty.util.log.Logger; */ public class SharedBlockingCallback { - static final Logger LOG = Log.getLogger(SharedBlockingCallback.class); + private static final Logger LOG = Log.getLogger(SharedBlockingCallback.class); private static Throwable IDLE = new ConstantThrowable("IDLE"); private static Throwable SUCCEEDED = new ConstantThrowable("SUCCEEDED"); @@ -60,6 +60,7 @@ public class SharedBlockingCallback private final Condition _complete = _lock.newCondition(); private Blocker _blocker = new Blocker(); + @Deprecated protected long getIdleTimeout() { return -1; @@ -135,7 +136,11 @@ public class SharedBlockingCallback _complete.signalAll(); } else - throw new IllegalStateException(_state); + { + LOG.warn("Succeeded after {}",_state.toString()); + if (LOG.isDebugEnabled()) + LOG.debug(_state); + } } finally { @@ -167,8 +172,12 @@ public class SharedBlockingCallback } else { - cause.printStackTrace(System.err); - throw new IllegalStateException(_state); + LOG.warn("Failed after {}: {}", _state, cause); + if (LOG.isDebugEnabled()) + { + LOG.debug(_state); + LOG.debug(cause); + } } } finally @@ -227,6 +236,7 @@ public class SharedBlockingCallback } catch (final InterruptedException e) { + _state = e; throw new InterruptedIOException(); } finally @@ -253,9 +263,9 @@ public class SharedBlockingCallback { try { - // If the blocker timed itself out, remember the state - if (_state instanceof BlockerTimeoutException) - // and create a new Blocker + // If we have a failure + if (_state!=null && _state!=SUCCEEDED) + // create a new Blocker _blocker=new Blocker(); else // else reuse Blocker diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/SharedBlockingCallbackTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/SharedBlockingCallbackTest.java index 524ddd08277..157c94db32d 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/SharedBlockingCallbackTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/SharedBlockingCallbackTest.java @@ -18,25 +18,30 @@ package org.eclipse.jetty.util; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - import java.io.IOException; +import java.io.InterruptedIOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.jetty.util.SharedBlockingCallback.Blocker; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.sameInstance; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + public class SharedBlockingCallbackTest { + private static final Logger LOG = Log.getLogger(SharedBlockingCallback.class); + final AtomicInteger notComplete = new AtomicInteger(); final SharedBlockingCallback sbcb= new SharedBlockingCallback() { @@ -52,14 +57,8 @@ public class SharedBlockingCallbackTest super.notComplete(blocker); notComplete.incrementAndGet(); } - }; - - public SharedBlockingCallbackTest() - { - } - - + @Test public void testDone() throws Exception { @@ -211,7 +210,7 @@ public class SharedBlockingCallbackTest { try (Blocker blocker=sbcb.acquire()) { - SharedBlockingCallback.LOG.info("Blocker not complete "+blocker+" warning is expected..."); + LOG.info("Blocker not complete "+blocker+" warning is expected..."); } Assert.assertEquals(1,notComplete.get()); @@ -220,6 +219,7 @@ public class SharedBlockingCallbackTest @Test public void testBlockerTimeout() throws Exception { + LOG.info("Succeeded after ... warning is expected..."); Blocker b0=null; try { @@ -238,21 +238,40 @@ public class SharedBlockingCallbackTest } Assert.assertEquals(0,notComplete.get()); - try (Blocker blocker=sbcb.acquire()) { - assertThat(blocker,not(equalTo(b0))); + assertThat(blocker,not(sameInstance(b0))); + b0.succeeded(); + blocker.succeeded(); + } + } + + @Test + public void testInterruptedException() throws Exception + { + Blocker blocker0; + try (Blocker blocker = sbcb.acquire()) + { + blocker0 = blocker; + Thread.currentThread().interrupt(); try { - b0.succeeded(); + blocker.block(); fail(); } - catch(Exception e) + catch (InterruptedIOException ignored) { - assertThat(e,instanceOf(IllegalStateException.class)); - assertThat(e.getCause(),instanceOf(TimeoutException.class)); } + } + // Blocker.close() has been called by try-with-resources. + // Simulate callback completion, must not throw. + LOG.info("Succeeded after ... warning is expected..."); + blocker0.succeeded(); + + try (Blocker blocker = sbcb.acquire()) + { + assertThat(blocker, not(sameInstance(blocker0))); blocker.succeeded(); } } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsumeTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsumeTest.java index af9eb3447af..7682f2152a0 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsumeTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/strategy/ExecuteProduceConsumeTest.java @@ -284,11 +284,6 @@ public class ExecuteProduceConsumeTest // When we unblock t0, thread1 will see the idle, t0.unblock(); - // but because there was a pending execute it will try producing again - while(_producer==null) - Thread.yield(); - Assert.assertEquals(thread0,_producer); - // and will see new tasks final Task t1 = new Task(true); _produce.add(t1); diff --git a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientConnectTest.java b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientConnectTest.java index a66f39bf846..54c96af4547 100644 --- a/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientConnectTest.java +++ b/jetty-websocket/websocket-client/src/test/java/org/eclipse/jetty/websocket/client/ClientConnectTest.java @@ -18,18 +18,11 @@ package org.eclipse.jetty.websocket.client; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; - -import java.io.IOException; import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; +import java.net.Socket; import java.net.SocketTimeoutException; import java.net.URI; import java.util.concurrent.CompletableFuture; @@ -60,6 +53,13 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + /** * Various connect condition testing */ @@ -72,15 +72,15 @@ public class ClientConnectTest private WebSocketClient client; @SuppressWarnings("unchecked") - private E assertExpectedError(ExecutionException e, JettyTrackingSocket wsocket, Matcher errorMatcher) throws IOException + private E assertExpectedError(ExecutionException e, JettyTrackingSocket wsocket, Matcher errorMatcher) { // Validate thrown cause Throwable cause = e.getCause(); - Assert.assertThat("ExecutionException.cause",cause,errorMatcher); + Assert.assertThat("ExecutionException.cause "+cause,cause,errorMatcher); // Validate websocket captured cause - Assert.assertThat("Error Queue Length",wsocket.errorQueue.size(),greaterThanOrEqualTo(1)); + Assert.assertThat("Error Queue Length "+wsocket.errorQueue,wsocket.errorQueue.size(),greaterThanOrEqualTo(1)); Throwable capcause = wsocket.errorQueue.poll(); Assert.assertThat("Error Queue[0]",capcause,notNullValue()); Assert.assertThat("Error Queue[0]",capcause,errorMatcher); @@ -462,7 +462,7 @@ public class ClientConnectTest } } - @Test(expected = TimeoutException.class) + @Test public void testConnectionTimeout_Concurrent() throws Exception { JettyTrackingSocket wsocket = new JettyTrackingSocket(); @@ -477,18 +477,17 @@ public class ClientConnectTest Future future = client.connect(wsocket, wsUri); // Accept the connection, but do nothing on it (no response, no upgrade, etc) - serverSocket.accept(); - - // The attempt to get upgrade response future should throw error - try + try (Socket socket = serverSocket.accept()) { - future.get(3, TimeUnit.SECONDS); - Assert.fail("Expected ExecutionException -> TimeoutException"); - } - catch (ExecutionException e) - { - // Expected path - java.net.ConnectException ? - assertExpectedError(e, wsocket, instanceOf(ConnectException.class)); + // The attempt to get upgrade response future should throw error + try + { + future.get(1, TimeUnit.SECONDS); + Assert.fail("Expected ExecutionException -> TimeoutException"); + } + catch (TimeoutException expected) + { + } } } } diff --git a/pom.xml b/pom.xml index 50d85ef0e2d..6fc54a9960b 100644 --- a/pom.xml +++ b/pom.xml @@ -490,7 +490,10 @@ http://docs.oracle.com/javase/8/docs/api/ http://docs.oracle.com/javaee/7/api/ + diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientContinueTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientContinueTest.java index 46f6e39e0fa..05acb8725a9 100644 --- a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientContinueTest.java +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientContinueTest.java @@ -50,7 +50,6 @@ import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.toolchain.test.annotation.Slow; import org.eclipse.jetty.util.IO; import org.hamcrest.Matchers; import org.junit.Assert; @@ -82,7 +81,7 @@ public class HttpClientContinueTest extends AbstractTest start(new AbstractHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { baseRequest.setHandled(true); // Send 100-Continue and copy the content back @@ -116,7 +115,7 @@ public class HttpClientContinueTest extends AbstractTest start(new AbstractHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { baseRequest.setHandled(true); // Send 100-Continue and copy the content back @@ -170,7 +169,7 @@ public class HttpClientContinueTest extends AbstractTest start(new AbstractHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { baseRequest.setHandled(true); response.sendError(error); @@ -209,7 +208,7 @@ public class HttpClientContinueTest extends AbstractTest start(new AbstractHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { baseRequest.setHandled(true); if (request.getRequestURI().endsWith("/done")) @@ -257,7 +256,7 @@ public class HttpClientContinueTest extends AbstractTest start(new AbstractHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { baseRequest.setHandled(true); if (request.getRequestURI().endsWith("/done")) @@ -297,7 +296,6 @@ public class HttpClientContinueTest extends AbstractTest Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); } - @Slow @Test public void test_Expect100Continue_WithContent_WithResponseFailure_Before100Continue() throws Exception { @@ -305,7 +303,7 @@ public class HttpClientContinueTest extends AbstractTest start(new AbstractHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws ServletException { baseRequest.setHandled(true); try @@ -341,7 +339,6 @@ public class HttpClientContinueTest extends AbstractTest Assert.assertTrue(latch.await(3 * idleTimeout, TimeUnit.MILLISECONDS)); } - @Slow @Test public void test_Expect100Continue_WithContent_WithResponseFailure_After100Continue() throws Exception { @@ -393,7 +390,7 @@ public class HttpClientContinueTest extends AbstractTest start(new AbstractHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { baseRequest.setHandled(true); // Send 100-Continue and consume the content @@ -445,14 +442,13 @@ public class HttpClientContinueTest extends AbstractTest Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); } - @Slow @Test public void test_Expect100Continue_WithDeferredContent_Respond100Continue() throws Exception { start(new AbstractHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { baseRequest.setHandled(true); // Send 100-Continue and echo the content @@ -493,14 +489,13 @@ public class HttpClientContinueTest extends AbstractTest Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); } - @Slow @Test public void test_Expect100Continue_WithInitialAndDeferredContent_Respond100Continue() throws Exception { start(new AbstractHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { baseRequest.setHandled(true); // Send 100-Continue and echo the content @@ -543,7 +538,7 @@ public class HttpClientContinueTest extends AbstractTest start(new AbstractHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { baseRequest.setHandled(true); // Send 100-Continue and echo the content @@ -582,7 +577,7 @@ public class HttpClientContinueTest extends AbstractTest start(new AbstractHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { baseRequest.setHandled(true); // Send 100-Continue and echo the content @@ -662,18 +657,7 @@ public class HttpClientContinueTest extends AbstractTest try (Socket socket = server.accept()) { // Read the request headers. - InputStream input = socket.getInputStream(); - int crlfs = 0; - while (true) - { - int read = input.read(); - if (read == '\r' || read == '\n') - ++crlfs; - else - crlfs = 0; - if (crlfs == 4) - break; - } + readRequestHeaders(socket.getInputStream()); OutputStream output = socket.getOutputStream(); String responses = "" + @@ -708,7 +692,7 @@ public class HttpClientContinueTest extends AbstractTest start(new AbstractHandler.ErrorDispatchHandler() { @Override - protected void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + protected void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException { jettyRequest.setHandled(true); // Force a 100 Continue response. @@ -728,4 +712,74 @@ public class HttpClientContinueTest extends AbstractTest Assert.assertEquals(HttpStatus.OK_200, response.getStatus()); Assert.assertArrayEquals(bytes, response.getContent()); } + + @Test + public void test_NoExpect_100Continue_ThenRedirect_Then100Continue_ThenResponse() throws Exception + { + Assume.assumeThat(transport, Matchers.is(Transport.HTTP)); + + startClient(); + client.setMaxConnectionsPerDestination(1); + + try (ServerSocket server = new ServerSocket()) + { + server.bind(new InetSocketAddress("localhost", 0)); + + // No Expect header, no content. + CountDownLatch latch = new CountDownLatch(1); + client.newRequest("localhost", server.getLocalPort()) + .send(result -> + { + if (result.isSucceeded() && result.getResponse().getStatus() == HttpStatus.OK_200) + latch.countDown(); + }); + + try (Socket socket = server.accept()) + { + InputStream input = socket.getInputStream(); + OutputStream output = socket.getOutputStream(); + + readRequestHeaders(input); + String response1 = "" + + "HTTP/1.1 100 Continue\r\n" + + "\r\n" + + "HTTP/1.1 303 See Other\r\n" + + "Location: /redirect\r\n" + + "Content-Length: 0\r\n" + + "\r\n"; + output.write(response1.getBytes(StandardCharsets.UTF_8)); + output.flush(); + + readRequestHeaders(input); + String response2 = "" + + "HTTP/1.1 100 Continue\r\n" + + "\r\n" + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 0\r\n" + + "Connection: close\r\n" + + "\r\n"; + output.write(response2.getBytes(StandardCharsets.UTF_8)); + output.flush(); + } + + Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); + } + } + + private void readRequestHeaders(InputStream input) throws IOException + { + int crlfs = 0; + while (true) + { + int read = input.read(); + if (read < 0) + break; + if (read == '\r' || read == '\n') + ++crlfs; + else + crlfs = 0; + if (crlfs == 4) + break; + } + } } diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTimeoutTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTimeoutTest.java index 75b3f579e30..6cc09fc18c5 100644 --- a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTimeoutTest.java +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/HttpClientTimeoutTest.java @@ -161,14 +161,12 @@ public class HttpClientTimeoutTest extends AbstractTest @Test public void testTimeoutOnListenerWithExplicitConnection() throws Exception { - Assume.assumeTrue(connector instanceof NetworkConnector); - NetworkConnector network_connector = (NetworkConnector)connector; - long timeout = 1000; start(new TimeoutHandler(2 * timeout)); + Assume.assumeTrue(connector instanceof NetworkConnector); final CountDownLatch latch = new CountDownLatch(1); - Destination destination = client.getDestination(getScheme(), "localhost", network_connector.getLocalPort()); + Destination destination = client.getDestination(getScheme(), "localhost", ((NetworkConnector)connector).getLocalPort()); FuturePromise futureConnection = new FuturePromise<>(); destination.newConnection(futureConnection); try (Connection connection = futureConnection.get(5, TimeUnit.SECONDS)) @@ -188,14 +186,12 @@ public class HttpClientTimeoutTest extends AbstractTest @Test public void testTimeoutIsCancelledOnSuccessWithExplicitConnection() throws Exception { - Assume.assumeTrue(connector instanceof NetworkConnector); - NetworkConnector network_connector = (NetworkConnector)connector; - long timeout = 1000; start(new TimeoutHandler(timeout)); + Assume.assumeTrue(connector instanceof NetworkConnector); final CountDownLatch latch = new CountDownLatch(1); - Destination destination = client.getDestination(getScheme(), "localhost", network_connector.getLocalPort()); + Destination destination = client.getDestination(getScheme(), "localhost", ((NetworkConnector)connector).getLocalPort()); FuturePromise futureConnection = new FuturePromise<>(); destination.newConnection(futureConnection); try (Connection connection = futureConnection.get(5, TimeUnit.SECONDS)) @@ -278,14 +274,13 @@ public class HttpClientTimeoutTest extends AbstractTest private void testConnectTimeoutFailsRequest(boolean blocking) throws Exception { - Assume.assumeTrue(connector instanceof NetworkConnector); - String host = "10.255.255.1"; int port = 80; int connectTimeout = 1000; assumeConnectTimeout(host, port, connectTimeout); start(new EmptyServerHandler()); + Assume.assumeTrue(connector instanceof NetworkConnector); client.stop(); client.setConnectTimeout(connectTimeout); client.setConnectBlocking(blocking); @@ -307,13 +302,13 @@ public class HttpClientTimeoutTest extends AbstractTest @Test public void testConnectTimeoutIsCancelledByShorterRequestTimeout() throws Exception { - Assume.assumeTrue(connector instanceof NetworkConnector); String host = "10.255.255.1"; int port = 80; int connectTimeout = 2000; assumeConnectTimeout(host, port, connectTimeout); start(new EmptyServerHandler()); + Assume.assumeTrue(connector instanceof NetworkConnector); client.stop(); client.setConnectTimeout(connectTimeout); client.start(); @@ -337,14 +332,13 @@ public class HttpClientTimeoutTest extends AbstractTest @Test public void retryAfterConnectTimeout() throws Exception { - Assume.assumeTrue(connector instanceof NetworkConnector); - final String host = "10.255.255.1"; final int port = 80; int connectTimeout = 1000; assumeConnectTimeout(host, port, connectTimeout); start(new EmptyServerHandler()); + Assume.assumeTrue(connector instanceof NetworkConnector); client.stop(); client.setConnectTimeout(connectTimeout); client.start(); @@ -387,13 +381,11 @@ public class HttpClientTimeoutTest extends AbstractTest @Test public void testTimeoutCancelledWhenSendingThrowsException() throws Exception { - Assume.assumeTrue(connector instanceof NetworkConnector); - NetworkConnector network_connector = (NetworkConnector)connector; - start(new EmptyServerHandler()); + Assume.assumeTrue(connector instanceof NetworkConnector); long timeout = 1000; - Request request = client.newRequest("badscheme://localhost:" + network_connector.getLocalPort()); + Request request = client.newRequest("badscheme://localhost:" + ((NetworkConnector)connector).getLocalPort()); try { diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java index 2e4a70c3360..ec3888b4465 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/rfcs/RFC2616BaseTest.java @@ -18,12 +18,12 @@ package org.eclipse.jetty.test.rfcs; -import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.junit.matchers.JUnitMatchers.containsString; import java.io.File; import java.io.IOException; @@ -384,7 +384,7 @@ public abstract class RFC2616BaseTest // 4.4.3 - // Client - do not send 'Content-Length' if entity-length // and the transfer-length are different. - // Server - ignore 'Content-Length' if 'Transfer-Encoding' is provided. + // Server - bad message to avoid smuggling concerns StringBuffer req2 = new StringBuffer(); req2.append("GET /echo/R1 HTTP/1.1\n"); @@ -409,14 +409,10 @@ public abstract class RFC2616BaseTest req2.append("7890AB"); responses = http.requests(req2); - Assert.assertEquals("Response Count",2,responses.size()); + Assert.assertEquals("Response Count",1,responses.size()); response = responses.get(0); // response 1 - assertEquals("4.4.3 Ignore Content-Length / Response Code", HttpStatus.OK_200, response.getStatus()); - assertTrue("4.4.3 Ignore Content-Length / Body", response.getContent().contains("123456\n")); - response = responses.get(1); // response 2 - assertEquals("4.4.3 Ignore Content-Length / Response Code", HttpStatus.OK_200, response.getStatus()); - assertTrue("4.4.3 Ignore Content-Length / Body", response.getContent().contains("7890AB\n")); + assertEquals("4.4.3 Ignore Content-Length / Response Code", HttpStatus.BAD_REQUEST_400, response.getStatus()); // 4.4 - Server can request valid Content-Length from client if client // fails to provide a Content-Length. @@ -535,7 +531,6 @@ public abstract class RFC2616BaseTest req4.append("\n"); // no virtual host HttpTester.Response response = http.request(req4); - System.err.println(response); assertEquals("5.2 No Host",HttpStatus.BAD_REQUEST_400,response.getStatus()); } @@ -623,7 +618,6 @@ public abstract class RFC2616BaseTest HttpTester.Response response = http.request(req7); assertEquals("5.2 Virtual Host as AbsoluteURI (and Host header)", HttpStatus.OK_200, response.getStatus()); - // System.err.println(response.getContent()); assertThat("5.2 Virtual Host as AbsoluteURI (and Host header)",response.getContent(),Matchers.containsString("VirtualHost DOCRoot")); } @@ -757,11 +751,8 @@ public abstract class RFC2616BaseTest req3.append("87654321"); // Body List responses = http.requests(req3); - - // System.err.println(responses); - + HttpTester.Response response=responses.get(0); - // System.err.println(response); assertEquals("8.2.3 ignored no 100",302, response.getStatus()); assertEquals("close",response.get("Connection")); @@ -1017,8 +1008,6 @@ public abstract class RFC2616BaseTest response = http.request(req2); - // System.err.println(response); - assertEquals("10.2.7 Partial Content",HttpStatus.PARTIAL_CONTENT_206, response.getStatus()); // (point 1) A 206 response MUST contain either a Content-Range header @@ -1578,76 +1567,6 @@ public abstract class RFC2616BaseTest assertEquals("--"+boundary+"--",lines.get(i++)); } - /** - * Test Range (Header Field) - * - * @see RFC 2616 (section 14.35) - */ - @Test - public void test14_35_Range_Multipart2() throws Exception - { - // Request the last 1 byte, last 2 bytes, and last 3 bytes. - // This is an example of overlapping ranges - - String rangedef = "-1,-2,-3"; - - StringBuffer req1 = new StringBuffer(); - req1.append("GET /rfc2616-webapp/alpha.txt HTTP/1.1\n"); - req1.append("Host: localhost\n"); - req1.append("Range: ").append(rangedef).append("\n"); - req1.append("Connection: close\n"); - req1.append("\n"); - - HttpTester.Response response = http.request(req1); - // System.err.println(response+response.getContent()); - - String msg = "Partial (Byte) Range: '" + rangedef + "'"; - assertEquals(msg,HttpStatus.PARTIAL_CONTENT_206,response.getStatus()); - - String contentType = response.get("Content-Type"); - // RFC states that multiple parts should result in multipart/byteranges Content type. - StringAssert.assertContains(msg + " Content-Type",contentType,"multipart/byteranges"); - - // Collect 'boundary' string - String boundary = null; - String parts[] = StringUtil.split(contentType,';'); - for (int i = 0; i < parts.length; i++) - { - if (parts[i].trim().startsWith("boundary=")) - { - String boundparts[] = StringUtil.split(parts[i],'='); - Assert.assertEquals(msg + " Boundary parts.length",2,boundparts.length); - boundary = boundparts[1]; - } - } - - Assert.assertNotNull(msg + " Should have found boundary in Content-Type header",boundary); - - - List lines = StringUtil.asLines(response.getContent().trim()); - int i=0; - assertEquals("--"+boundary,lines.get(i++)); - assertEquals("Content-Type: text/plain",lines.get(i++)); - assertEquals("Content-Range: bytes 26-26/27",lines.get(i++)); - assertEquals("",lines.get(i++)); - assertEquals("",lines.get(i++)); - assertEquals("",lines.get(i++)); - assertEquals("--"+boundary,lines.get(i++)); - assertEquals("Content-Type: text/plain",lines.get(i++)); - assertEquals("Content-Range: bytes 25-26/27",lines.get(i++)); - assertEquals("",lines.get(i++)); - assertEquals("Z",lines.get(i++)); - assertEquals("",lines.get(i++)); - assertEquals("--"+boundary,lines.get(i++)); - assertEquals("Content-Type: text/plain",lines.get(i++)); - assertEquals("Content-Range: bytes 24-26/27",lines.get(i++)); - assertEquals("",lines.get(i++)); - assertEquals("YZ",lines.get(i++)); - assertEquals("",lines.get(i++)); - assertEquals("--"+boundary+"--",lines.get(i++)); - - } - /** * Test Range (Header Field) * diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastClusteredInvalidationSessionTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastClusteredInvalidationSessionTest.java new file mode 100644 index 00000000000..d294a2cca04 --- /dev/null +++ b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastClusteredInvalidationSessionTest.java @@ -0,0 +1,51 @@ +// +// ======================================================================== +// 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.hazelcast.session; + +import org.eclipse.jetty.server.session.AbstractClusteredInvalidationSessionTest; +import org.eclipse.jetty.server.session.SessionDataStoreFactory; +import org.junit.After; +import org.junit.Before; + +public class HazelcastClusteredInvalidationSessionTest + extends AbstractClusteredInvalidationSessionTest +{ + + HazelcastSessionDataStoreFactory factory; + + HazelcastTestHelper _testHelper; + + @Before + public void setUp() + { + _testHelper = new HazelcastTestHelper(); + } + + @After + public void shutdown() + { + _testHelper.tearDown(); + } + + @Override + public SessionDataStoreFactory createSessionDataStoreFactory() + { + return _testHelper.createSessionDataStoreFactory( false ); + } +} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastTestHelper.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastTestHelper.java index a847ac491c9..db379fb3a35 100644 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastTestHelper.java +++ b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastTestHelper.java @@ -24,6 +24,9 @@ import static org.junit.Assert.assertTrue; import java.util.concurrent.TimeUnit; +import com.hazelcast.config.JoinConfig; +import com.hazelcast.config.MulticastConfig; +import com.hazelcast.config.NetworkConfig; import org.eclipse.jetty.server.session.SessionData; import org.eclipse.jetty.server.session.SessionDataStoreFactory; @@ -39,11 +42,14 @@ import com.hazelcast.core.HazelcastInstance; */ public class HazelcastTestHelper { - static String _hazelcastInstanceName = "SESSION_TEST_"+Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime())); + static final String _hazelcastInstanceName = "SESSION_TEST_"+Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime())); - static String _name = Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ); - static HazelcastInstance _instance = Hazelcast.getOrCreateHazelcastInstance( new Config() // + static final String _name = Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ); + static final HazelcastInstance _instance = Hazelcast.getOrCreateHazelcastInstance( new Config() // .setInstanceName(_hazelcastInstanceName ) // + .setNetworkConfig( new NetworkConfig().setJoin( // + new JoinConfig().setMulticastConfig( // + new MulticastConfig().setEnabled( false ) ) ) ) // .addMapConfig( new MapConfig().setName(_name) ) ); public HazelcastTestHelper () @@ -51,12 +57,9 @@ public class HazelcastTestHelper // noop } - // definitely not thread safe so tests cannot be executed in parallel - // TODO use ThreadContext variable for this Map name public SessionDataStoreFactory createSessionDataStoreFactory(boolean onlyClient) { HazelcastSessionDataStoreFactory factory = new HazelcastSessionDataStoreFactory(); - //_name = Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ); factory.setOnlyClient( onlyClient ); factory.setMapName(_name); factory.setHazelcastInstance(_instance);