Merge branch 'jetty-9.4.x' of https://github.com/eclipse/jetty.project into jetty-9.4.x

This commit is contained in:
Steve Bolton 2018-05-03 12:52:50 -04:00
commit c73352b1f0
281 changed files with 4408 additions and 1911 deletions

44
Jenkinsfile vendored
View File

@ -1,7 +1,7 @@
#!groovy
def jdks = ["jdk8", "jdk9"]
def oss = ["linux"] //windows? ,"linux-docker"
def jdks = ["jdk8","jdk9","jdk10","jdk11"]
def oss = ["linux"]
def builds = [:]
for (def os in oss) {
for (def jdk in jdks) {
@ -15,8 +15,11 @@ def getFullBuild(jdk, os) {
return {
node(os) {
// System Dependent Locations
def mvntool = tool name: 'maven3', type: 'hudson.tasks.Maven$MavenInstallation'
def mvntool = tool name: 'maven3.5', type: 'hudson.tasks.Maven$MavenInstallation'
def jdktool = tool name: "$jdk", type: 'hudson.model.JDK'
def mvnName = 'maven3.5'
def localRepo = "${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}" // ".repository" //
def settingsName = 'oss-settings.xml'
// Environment
List mvnEnv = ["PATH+MVN=${mvntool}/bin", "PATH+JDK=${jdktool}/bin", "JAVA_HOME=${jdktool}/", "MAVEN_HOME=${mvntool}"]
@ -38,11 +41,11 @@ def getFullBuild(jdk, os) {
withEnv(mvnEnv) {
timeout(time: 15, unit: 'MINUTES') {
withMaven(
maven: 'maven3',
maven: mvnName,
jdk: "$jdk",
publisherStrategy: 'EXPLICIT',
globalMavenSettingsConfig: 'oss-settings.xml',
mavenLocalRepo: "${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}") {
globalMavenSettingsConfig: settingsName,
mavenLocalRepo: localRepo) {
sh "mvn -V -B clean install -DskipTests -T6"
}
@ -60,12 +63,12 @@ def getFullBuild(jdk, os) {
withEnv(mvnEnv) {
timeout(time: 20, unit: 'MINUTES') {
withMaven(
maven: 'maven3',
maven: mvnName,
jdk: "$jdk",
publisherStrategy: 'EXPLICIT',
globalMavenSettingsConfig: 'oss-settings.xml',
mavenLocalRepo: "${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}") {
sh "mvn -V -B javadoc:javadoc -T5"
globalMavenSettingsConfig: settingsName,
mavenLocalRepo: localRepo) {
sh "mvn -V -B javadoc:javadoc -T6"
}
}
}
@ -82,14 +85,12 @@ def getFullBuild(jdk, os) {
timeout(time: 90, unit: 'MINUTES') {
// Run test phase / ignore test failures
withMaven(
maven: 'maven3',
maven: mvnName,
jdk: "$jdk",
publisherStrategy: 'EXPLICIT',
//options: [invokerPublisher(disabled: false)],
globalMavenSettingsConfig: 'oss-settings.xml',
mavenLocalRepo: "${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}") {
//
sh "mvn -V -B install -Dmaven.test.failure.ignore=true -Prun-its -T3 -e -Dmaven.repo.local=${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER} -Pmongodb"
globalMavenSettingsConfig: settingsName,
mavenLocalRepo: localRepo) {
sh "mvn -V -B install -Dmaven.test.failure.ignore=true -Prun-its -e -Pmongodb -T3"
}
// withMaven doesn't label..
// Report failures in the jenkins UI
@ -134,17 +135,14 @@ def getFullBuild(jdk, os) {
try
{
stage ("Compact3 - ${jdk}") {
dir("aggregates/jetty-all-compact3") {
withEnv(mvnEnv) {
withMaven(
maven: 'maven3',
maven: mvnName,
jdk: "$jdk",
publisherStrategy: 'EXPLICIT',
globalMavenSettingsConfig: 'oss-settings.xml',
mavenLocalRepo: "${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}") {
sh "mvn -V -B -Pcompact3 clean install -T5"
}
globalMavenSettingsConfig: settingsName,
mavenLocalRepo: localRepo) {
sh "mvn -f aggregates/jetty-all-compact3 -V -B -Pcompact3 clean install -T5"
}
}
}

View File

@ -1,6 +1,6 @@
==============================================================
Jetty Web Container
Copyright 1995-2017 Mort Bay Consulting Pty Ltd.
Copyright 1995-2018 Mort Bay Consulting Pty Ltd.
==============================================================
The Jetty Web Container is Copyright Mort Bay Consulting Pty Ltd

View File

@ -1,4 +1,56 @@
jetty-9.4.10-SNAPSHOT
jetty-9.4.11-SNAPSHOT
jetty-9.4.10.v20180503 - 03 May 2018
+ 110 Jetty JAASLoginService should not use getContextClassLoader to load role
class name under OSGi
+ 1027 MultiPartInputStreamParser is slow for largish files
+ 1555 AuthenticationProtocolHandler unable to parse Digest WWW Header
+ 2018 No HttpClient API for receiving Server Sent Events
+ 2145 Enabled h2, http/1.1 + https failed with invalid preface
+ 2152 Produce jetty-home-source artifacts for Eclipse Jetty source jars
+ 2164 Ensure all jetty modules that use ServiceLoader have correct OSGi
manifest headers
+ 2205 100% CPU usage in Selector using Jetty on Windows
+ 2311 TimeoutException when server sends unexpected content
+ 2337 ServletUpgradeRequest getSubProtocols() creates an ArrayList even if
sub protocols is absent in WebSocket Upgrade Request.
+ 2349 Review HTTP/2 max streams enforcement
+ 2350 Support multiplexing in RoundRobinConnectionPool
+ 2361 CachingWebAppClassLoader is not using cache properly
+ 2366 Review HTTP/2 interleaving
+ 2376 Relax ContextHandler and ServletContextHandler requirements in
WebSocket to allow SpringBoot's MockMVC to function
+ 2387 NPE in URIUtil.equalsIgnoreEncodings when working with jar:file:// URIs
+ 2388 AtomicBiInteger.compareAndSet(long,int,int) not using encoded parameter
+ 2391 Allow for optional "\u####" escaping in
org.eclipse.jetty.util.ajax.JSON.toString()
+ 2398 MultiPartFormInputStream parsing should default to UTF-8, but allowed
to be overridden by Request.setCharacterEncoding()
+ 2403 allow --add-to-start to specify maven repository location
+ 2409 Ensure no duplicate config classes are assigned to WebApps in OSGi
environments
+ 2413 Server log timestamp is inconsistent
+ 2420 Simplify HttpTransportOverHTTP2
+ 2425 Review BufferUtil.isMappedBuffer()
+ 2427 SessionInactivityTimeout does not stop upon expiration
+ 2430 CDI version mismatch with jetty-maven-plugin:run-forked and Weld
+ 2435 Class.newInstance() is deprecated in Java 9+
+ 2445 Add HttpServletRequest support to DefaultCallbackHandler
+ 2446 AttributeNormalizer does not support "user.home" to be "/"
+ 2451 ReservedThreadExecutor.getAvailable() is not atomic and can return
incorrect value
+ 2454 Avoid sending empty DATA frame in case of HTTP/2 trailers
+ 2464 NPE when constructing subclasses of ExecutorThreadPool
+ 2468 EWYK concurrent produce can fail SSL connections
+ 2472 Default Maven Central Repository URL used to download artifacts in
start.jar should use https
+ 2474 HTTP/2 client not handling invalid servers correctly
+ 2478 ThreadPoolExecutor does nto reap Idle threads
+ 2482 Possible NPE in MemcachedSessionDataMapFactory
+ 2491 WebSocket FragmentExtension can produce an invalid stream of frames
+ 2495 FileSessionDataStore: private save method
+ 2496 Jetty Maven Plugin should skip execution on projects it cannot support
+ 2498 Add QueuedThreadPool.removeThread(Thread) for extendability reasons
jetty-9.4.9.v20180320 - 20 March 2018
+ 347 Avoid sending request using a connection that is idle timing out
@ -20,8 +72,8 @@ jetty-9.4.9.v20180320 - 20 March 2018
+ 1970 ManagedSelector can lose selector thread under high concurrent load
+ 1973 Implement minimum response data rate
+ 1983 Improve warning for incompatible ALPN processor
+ 1986 ServletContextHandler.Context addListener() methods support
session listeners
+ 1986 ServletContextHandler.Context addListener() methods support session
listeners
+ 2003 Do not submit blocking tasks as managed selector actions
+ 2006 ServletInputStream.isReady not registering interest when it should
+ 2010 SniX509ExtendedKeyManager causes exception: "FIPS mode: only SunJSSE

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apache-jsp</artifactId>
@ -24,7 +24,7 @@
<Export-Package>org.eclipse.jetty.apache.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}",
org.eclipse.jetty.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=javax.servlet.ServletContainerInitializer,osgi.serviceloader;osgi.serviceloader=org.apache.juli.logging.Log</Provide-Capability>
<_nouses>true</_nouses>
</instructions>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apache-jstl</artifactId>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>example-async-rest</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.example-async-rest</groupId>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>example-async-rest</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.example-async-rest</groupId>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty.examples</groupId>
<artifactId>examples-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty.examples</groupId>
<artifactId>examples-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -4,13 +4,16 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>org.eclipse.jetty.examples</groupId>
<artifactId>examples-parent</artifactId>
<name>Jetty Examples :: Parent</name>
<packaging>pom</packaging>
<properties>
<sonar.skip>true</sonar.skip>
</properties>
<build>
<plugins>
<plugin>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-alpn-client</artifactId>
@ -24,7 +24,7 @@
<configuration>
<instructions>
<Import-Package>org.eclipse.jetty.alpn;resolution:=optional,*</Import-Package>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)", osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client)";cardinality:=multiple</Require-Capability>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional, osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client)";resolution:=optional;cardinality:=multiple</Require-Capability>
</instructions>
</configuration>
</execution>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -46,7 +46,7 @@
<Bundle-Description>Conscrypt Client ALPN</Bundle-Description>
<Import-Package>org.conscrypt;version="${conscrypt.version}",*</Import-Package>
<Export-Package>*</Export-Package>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client</Provide-Capability>
<_nouses>true</_nouses>
</instructions>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -49,7 +49,7 @@
<instructions>
<Bundle-Description>Conscrypt ALPN</Bundle-Description>
<Import-Package>org.conscrypt;version="${conscrypt.version}",*</Import-Package>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server</Provide-Capability>
<_nouses>true</_nouses>
</instructions>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -35,7 +35,7 @@
<instructions>
<Bundle-Description>JDK9 Client ALPN</Bundle-Description>
<Export-Package>*</Export-Package>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client</Provide-Capability>
<_nouses>true</_nouses>
</instructions>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -33,7 +33,7 @@
<configuration>
<instructions>
<Bundle-Description>JDK9 Server ALPN</Bundle-Description>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server</Provide-Capability>
<_nouses>true</_nouses>
</instructions>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -62,7 +62,7 @@
<Bundle-Description>OpenJDK8 Client ALPN</Bundle-Description>
<Import-Package>org.eclipse.jetty.alpn;version="${alpn.majorVersion}.${alpn.minorVersion}.${alpn.incrementalVersion}",*</Import-Package>
<Export-Package>*</Export-Package>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client</Provide-Capability>
<_nouses>true</_nouses>
</instructions>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -67,7 +67,7 @@
<Bundle-Description>OpenJDK8 Server ALPN</Bundle-Description>
<Export-Package>*</Export-Package>
<Import-Package>org.eclipse.jetty.alpn;version="${alpn.majorVersion}.${alpn.minorVersion}.${alpn.incrementalVersion}",*</Import-Package>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server</Provide-Capability>
<_nouses>true</_nouses>
</instructions>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-alpn-server</artifactId>
@ -49,7 +49,7 @@
<Bundle-SymbolicName>${bundle-symbolic-name};singleton:=true</Bundle-SymbolicName>
<Export-Package>org.eclipse.jetty.alpn.server,*</Export-Package>
<Import-Package>org.eclipse.jetty.alpn;version="${alpn.majorVersion}.${alpn.minorVersion}.${alpn.incrementalVersion}",*</Import-Package>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)", osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server)";resolution:=optional;cardinality:=multiple</Require-Capability>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional, osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server)";resolution:=optional;cardinality:=multiple</Require-Capability>
</instructions>
</configuration>
</plugin>

View File

@ -0,0 +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
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar

View File

@ -0,0 +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
[exec]
-Xbootclasspath/p:lib/alpn/alpn-boot-8.1.12.v20180117.jar

View File

@ -4,7 +4,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-alpn-parent</artifactId>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-annotations</artifactId>
@ -21,7 +21,7 @@
<configuration>
<instructions>
<Import-Package>org.objectweb.asm;version="[5.0,7)",*</Import-Package>
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=javax.servlet.ServletContainerInitializer)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)"</Require-Capability>
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=javax.servlet.ServletContainerInitializer)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional</Require-Capability>
</instructions>
</configuration>
</plugin>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-ant</artifactId>

View File

@ -47,7 +47,7 @@ public class JettyRunTask extends Task
private File tempDirectory;
/** List of web applications to be deployed. */
private List<AntWebAppContext> webapps = new ArrayList<AntWebAppContext>();
private List<AntWebAppContext> webapps = new ArrayList<>();
/** Location of jetty.xml file. */
private File jettyXml;
@ -147,20 +147,17 @@ public class JettyRunTask extends Task
{
try
{
this.requestLog = (RequestLog) Class.forName(className).newInstance();
}
catch (InstantiationException e)
{
throw new BuildException("Request logger instantiation exception: " + e);
}
catch (IllegalAccessException e)
{
throw new BuildException("Request logger instantiation exception: " + e);
this.requestLog = (RequestLog) Class.forName(className).getDeclaredConstructor().newInstance();
}
catch (ClassNotFoundException e)
{
throw new BuildException("Unknown request logger class: " + className);
}
catch (Exception e)
{
throw new BuildException("Request logger instantiation exception: " + e);
}
}
public String getRequestLog()

View File

@ -2,7 +2,7 @@
<groupId>org.eclipse.jetty</groupId>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-bom</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
<name>Jetty :: Bom</name>
<description>Jetty BOM artifact</description>
<url>http://www.eclipse.org/jetty</url>
@ -94,331 +94,331 @@
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>apache-jsp</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>apache-jstl</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-client</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-java-client</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-java-server</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-openjdk8-client</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-openjdk8-server</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-conscrypt-client</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-conscrypt-server</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-server</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-annotations</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-ant</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.cdi</groupId>
<artifactId>cdi-core</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.cdi</groupId>
<artifactId>cdi-servlet</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-continuation</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-deploy</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-distribution</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
<type>zip</type>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-distribution</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
<type>tar.gz</type>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi-client</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi-server</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.gcloud</groupId>
<artifactId>jetty-gcloud-session-manager</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-home</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
<type>zip</type>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-home</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
<type>tar.gz</type>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-client</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-common</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-hpack</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-http-client-transport</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http-spi</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-infinispan</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-hazelcast</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jaas</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jaspi</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jndi</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.memcached</groupId>
<artifactId>jetty-memcached-sessions</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-nosql</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.osgi</groupId>
<artifactId>jetty-osgi-boot</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.osgi</groupId>
<artifactId>jetty-osgi-boot-jsp</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.osgi</groupId>
<artifactId>jetty-osgi-boot-warurl</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.osgi</groupId>
<artifactId>jetty-httpservice</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-plus</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-proxy</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-quickstart</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-rewrite</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-spring</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-unixsocket</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util-ajax</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>javax-websocket-client-impl</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>javax-websocket-server-impl</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-api</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-client</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-common</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-server</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-servlet</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-xml</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty.cdi</groupId>
<artifactId>jetty-cdi-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cdi-2</artifactId>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty.cdi</groupId>
<artifactId>jetty-cdi-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cdi-core</artifactId>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty.cdi</groupId>
<artifactId>jetty-cdi-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cdi-full-servlet</artifactId>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty.cdi</groupId>
<artifactId>jetty-cdi-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cdi-servlet</artifactId>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty.cdi</groupId>
<artifactId>jetty-cdi-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cdi-websocket</artifactId>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.cdi</groupId>

View File

@ -3,7 +3,7 @@
<parent>
<groupId>org.eclipse.jetty.cdi</groupId>
<artifactId>jetty-cdi-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>test-cdi-webapp</artifactId>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -20,12 +20,14 @@ package org.eclipse.jetty.client;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jetty.client.api.Authentication;
import org.eclipse.jetty.client.api.Authentication.HeaderInfo;
import org.eclipse.jetty.client.api.Connection;
import org.eclipse.jetty.client.api.ContentProvider;
import org.eclipse.jetty.client.api.ContentResponse;
@ -35,6 +37,8 @@ import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.util.BufferingResponseListener;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.QuotedCSV;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -42,7 +46,11 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
{
public static final int DEFAULT_MAX_CONTENT_LENGTH = 16*1024;
public static final Logger LOG = Log.getLogger(AuthenticationProtocolHandler.class);
private static final Pattern AUTHENTICATE_PATTERN = Pattern.compile("([^\\s]+)\\s+realm=\"([^\"]*)\"(.*)", Pattern.CASE_INSENSITIVE);
private static final Pattern PARAM_PATTERN = Pattern.compile("([^=]+)=([^=]+)?");
private static final Pattern TYPE_PATTERN = Pattern.compile("([^\\s]+)(\\s+(.*))?");
private static final Pattern MULTIPLE_CHALLENGE_PATTERN = Pattern.compile("(.*?)\\s*,\\s*([^=\\s,]+(\\s+[^=\\s].*)?)");
private static final Pattern BASE64_PATTERN = Pattern.compile("[\\+\\-\\.\\/\\dA-Z_a-z~]+=*");
private final HttpClient client;
private final int maxContentLength;
@ -75,6 +83,80 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
return new AuthenticationListener();
}
protected List<HeaderInfo> getHeaderInfo(String value) throws IllegalArgumentException
{
String header = value;
List<HeaderInfo> headerInfos = new ArrayList<>();
while(true)
{
Matcher m = MULTIPLE_CHALLENGE_PATTERN.matcher(header);
if (m.matches())
{
headerInfos.add(newHeaderInfo(m.group(1)));
header = m.group(2);
}
else
{
headerInfos.add(newHeaderInfo(header));
break;
}
}
return headerInfos;
}
protected HeaderInfo newHeaderInfo(String value) throws IllegalArgumentException
{
String type;
Map<String,String> params = new HashMap<>();
Matcher m = TYPE_PATTERN.matcher(value);
if (m.matches())
{
type = m.group(1);
if (m.group(2) != null)
params = parseParameters(m.group(3));
}
else
{
throw new IllegalArgumentException("Invalid Authentication Format");
}
return new HeaderInfo(getAuthorizationHeader(), type, params);
}
protected Map<String, String> parseParameters(String wwwAuthenticate) throws IllegalArgumentException
{
Map<String, String> result = new HashMap<>();
Matcher b64 = BASE64_PATTERN.matcher(wwwAuthenticate);
if (b64.matches())
{
result.put("base64", wwwAuthenticate);
return result;
}
QuotedCSV parts = new QuotedCSV(false, wwwAuthenticate);
for (String part : parts)
{
Matcher params = PARAM_PATTERN.matcher(part);
if (params.matches())
{
String name = StringUtil.asciiToLowerCase(params.group(1));
String value = (params.group(2)==null) ? "" : params.group(2);
result.put(name, value);
}
else
{
throw new IllegalArgumentException("Invalid Authentication Format");
}
}
return result;
}
private class AuthenticationListener extends BufferingResponseListener
{
private AuthenticationListener()
@ -234,17 +316,17 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
{
// TODO: these should be ordered by strength
List<Authentication.HeaderInfo> result = new ArrayList<>();
List<String> values = Collections.list(response.getHeaders().getValues(header.asString()));
List<String> values = response.getHeaders().getValuesList(header);
for (String value : values)
{
Matcher matcher = AUTHENTICATE_PATTERN.matcher(value);
if (matcher.matches())
try
{
String type = matcher.group(1);
String realm = matcher.group(2);
String params = matcher.group(3);
Authentication.HeaderInfo headerInfo = new Authentication.HeaderInfo(type, realm, params, getAuthorizationHeader());
result.add(headerInfo);
result.addAll(getHeaderInfo(value));
}
catch(IllegalArgumentException e)
{
if (LOG.isDebugEnabled())
LOG.debug("Failed to parse authentication header", e);
}
}
return result;

View File

@ -19,9 +19,11 @@
package org.eclipse.jetty.client.api;
import java.net.URI;
import java.util.Map;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.StringUtil;
/**
* {@link Authentication} represents a mechanism to authenticate requests for protected resources.
@ -76,17 +78,16 @@ public interface Authentication
*/
public static class HeaderInfo
{
private final String type;
private final String realm;
private final String params;
private final HttpHeader header;
private final String type;
private final Map<String,String> params;
public HeaderInfo(String type, String realm, String params, HttpHeader header)
public HeaderInfo(HttpHeader header, String type, Map<String,String> params) throws IllegalArgumentException
{
this.type = type;
this.realm = realm;
this.params = params;
this.header = header;
this.type = type;
this.params = params;
}
/**
@ -98,21 +99,37 @@ public interface Authentication
}
/**
* @return the realm name
* @return the realm name or null if there is no realm parameter
*/
public String getRealm()
{
return realm;
return params.get("realm");
}
/**
* @return the base64 content as a string if it exists otherwise null
*/
public String getBase64()
{
return params.get("base64");
}
/**
* @return additional authentication parameters
*/
public String getParameters()
public Map<String, String> getParameters()
{
return params;
}
/**
* @return specified authentication parameter or null if does not exist
*/
public String getParameter(String paramName)
{
return params.get(StringUtil.asciiToLowerCase(paramName));
}
/**
* @return the {@code Authorization} (or {@code Proxy-Authorization}) header
*/

View File

@ -22,15 +22,11 @@ import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.AuthenticationStore;
@ -40,6 +36,7 @@ import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.log.Log;
/**
* Implementation of the HTTP "Digest" authentication defined in RFC 2617.
@ -50,8 +47,6 @@ import org.eclipse.jetty.util.TypeUtil;
*/
public class DigestAuthentication extends AbstractAuthentication
{
private static final Pattern PARAM_PATTERN = Pattern.compile("([^=]+)=(.*)");
private final String user;
private final String password;
@ -74,10 +69,21 @@ public class DigestAuthentication extends AbstractAuthentication
return "Digest";
}
@Override
public boolean matches(String type, URI uri, String realm)
{
// digest authenication requires a realm
if (realm == null)
return false;
return super.matches(type,uri,realm);
}
@Override
public Result authenticate(Request request, ContentResponse response, HeaderInfo headerInfo, Attributes context)
{
Map<String, String> params = parseParameters(headerInfo.getParameters());
Map<String, String> params = headerInfo.getParameters();
String nonce = params.get("nonce");
if (nonce == null || nonce.length() == 0)
return null;
@ -105,58 +111,6 @@ public class DigestAuthentication extends AbstractAuthentication
return new DigestResult(headerInfo.getHeader(), response.getContent(), realm, user, password, algorithm, nonce, clientQOP, opaque);
}
private Map<String, String> parseParameters(String wwwAuthenticate)
{
Map<String, String> result = new HashMap<>();
List<String> parts = splitParams(wwwAuthenticate);
for (String part : parts)
{
Matcher matcher = PARAM_PATTERN.matcher(part);
if (matcher.matches())
{
String name = matcher.group(1).trim().toLowerCase(Locale.ENGLISH);
String value = matcher.group(2).trim();
if (value.startsWith("\"") && value.endsWith("\""))
value = value.substring(1, value.length() - 1);
result.put(name, value);
}
}
return result;
}
private List<String> splitParams(String paramString)
{
List<String> result = new ArrayList<>();
int start = 0;
for (int i = 0; i < paramString.length(); ++i)
{
int quotes = 0;
char ch = paramString.charAt(i);
switch (ch)
{
case '\\':
++i;
break;
case '"':
++quotes;
break;
case ',':
if (quotes % 2 == 0)
{
String element = paramString.substring(start, i).trim();
if (element.length() > 0)
result.add(element);
start = i + 1;
}
break;
default:
break;
}
}
result.add(paramString.substring(start, paramString.length()).trim());
return result;
}
private MessageDigest getMessageDigest(String algorithm)
{
try

View File

@ -23,6 +23,7 @@ import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -43,6 +44,7 @@ import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Response.Listener;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.api.Authentication.HeaderInfo;
import org.eclipse.jetty.client.util.BasicAuthentication;
import org.eclipse.jetty.client.util.DeferredContentProvider;
import org.eclipse.jetty.client.util.DigestAuthentication;
@ -63,6 +65,7 @@ import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
@ -613,4 +616,120 @@ public class HttpClientAuthenticationTest extends AbstractHttpClientServerTest
};
}
}
@Test
public void testTestHeaderInfoParsing() {
AuthenticationProtocolHandler aph = new WWWAuthenticationProtocolHandler(client);
HeaderInfo headerInfo = aph.getHeaderInfo("Digest realm=\"thermostat\", qop=\"auth\", nonce=\"1523430383\"").get(0);
Assert.assertTrue(headerInfo.getType().equalsIgnoreCase("Digest"));
Assert.assertTrue(headerInfo.getParameter("qop").equals("auth"));
Assert.assertTrue(headerInfo.getParameter("realm").equals("thermostat"));
Assert.assertTrue(headerInfo.getParameter("nonce").equals("1523430383"));
headerInfo = aph.getHeaderInfo("Digest qop=\"auth\", realm=\"thermostat\", nonce=\"1523430383\"").get(0);
Assert.assertTrue(headerInfo.getType().equalsIgnoreCase("Digest"));
Assert.assertTrue(headerInfo.getParameter("qop").equals("auth"));
Assert.assertTrue(headerInfo.getParameter("realm").equals("thermostat"));
Assert.assertTrue(headerInfo.getParameter("nonce").equals("1523430383"));
headerInfo = aph.getHeaderInfo("Digest qop=\"auth\", nonce=\"1523430383\", realm=\"thermostat\"").get(0);
Assert.assertTrue(headerInfo.getType().equalsIgnoreCase("Digest"));
Assert.assertTrue(headerInfo.getParameter("qop").equals("auth"));
Assert.assertTrue(headerInfo.getParameter("realm").equals("thermostat"));
Assert.assertTrue(headerInfo.getParameter("nonce").equals("1523430383"));
headerInfo = aph.getHeaderInfo("Digest qop=\"auth\", nonce=\"1523430383\"").get(0);
Assert.assertTrue(headerInfo.getType().equalsIgnoreCase("Digest"));
Assert.assertTrue(headerInfo.getParameter("qop").equals("auth"));
Assert.assertTrue(headerInfo.getParameter("realm") == null);
Assert.assertTrue(headerInfo.getParameter("nonce").equals("1523430383"));
// test multiple authentications
List<HeaderInfo> headerInfoList = aph.getHeaderInfo("Digest qop=\"auth\", realm=\"thermostat\", nonce=\"1523430383\", "
+ "Digest realm=\"thermostat2\", qop=\"auth2\", nonce=\"4522530354\", "
+ "Digest qop=\"auth3\", nonce=\"9523570528\", realm=\"thermostat3\", "
+ "Digest qop=\"auth4\", nonce=\"3526435321\"");
Assert.assertTrue(headerInfoList.get(0).getType().equalsIgnoreCase("Digest"));
Assert.assertTrue(headerInfoList.get(0).getParameter("qop").equals("auth"));
Assert.assertTrue(headerInfoList.get(0).getParameter("realm").equals("thermostat"));
Assert.assertTrue(headerInfoList.get(0).getParameter("nonce").equals("1523430383"));
Assert.assertTrue(headerInfoList.get(1).getType().equalsIgnoreCase("Digest"));
Assert.assertTrue(headerInfoList.get(1).getParameter("qop").equals("auth2"));
Assert.assertTrue(headerInfoList.get(1).getParameter("realm").equals("thermostat2"));
Assert.assertTrue(headerInfoList.get(1).getParameter("nonce").equals("4522530354"));
Assert.assertTrue(headerInfoList.get(2).getType().equalsIgnoreCase("Digest"));
Assert.assertTrue(headerInfoList.get(2).getParameter("qop").equals("auth3"));
Assert.assertTrue(headerInfoList.get(2).getParameter("realm").equals("thermostat3"));
Assert.assertTrue(headerInfoList.get(2).getParameter("nonce").equals("9523570528"));
Assert.assertTrue(headerInfoList.get(3).getType().equalsIgnoreCase("Digest"));
Assert.assertTrue(headerInfoList.get(3).getParameter("qop").equals("auth4"));
Assert.assertTrue(headerInfoList.get(3).getParameter("realm") == null);
Assert.assertTrue(headerInfoList.get(3).getParameter("nonce").equals("3526435321"));
List<HeaderInfo> headerInfos = aph.getHeaderInfo("Newauth realm=\"apps\", type=1, title=\"Login to \\\"apps\\\"\", Basic realm=\"simple\"");
Assert.assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Newauth"));
Assert.assertTrue(headerInfos.get(0).getParameter("realm").equals("apps"));
Assert.assertTrue(headerInfos.get(0).getParameter("type").equals("1"));
Assert.assertThat(headerInfos.get(0).getParameter("title"), Matchers.equalTo("Login to \"apps\""));
Assert.assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Basic"));
Assert.assertTrue(headerInfos.get(1).getParameter("realm").equals("simple"));
}
@Test
public void testTestHeaderInfoParsingUnusualCases() {
AuthenticationProtocolHandler aph = new WWWAuthenticationProtocolHandler(client);
HeaderInfo headerInfo = aph.getHeaderInfo("Scheme").get(0);
Assert.assertTrue(headerInfo.getType().equalsIgnoreCase("Scheme"));
Assert.assertTrue(headerInfo.getParameter("realm") == null);
List<HeaderInfo> headerInfos = aph.getHeaderInfo("Scheme1 , Scheme2 , Scheme3");
Assert.assertEquals(3, headerInfos.size());
Assert.assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Scheme1"));
Assert.assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Scheme2"));
Assert.assertTrue(headerInfos.get(2).getType().equalsIgnoreCase("Scheme3"));
headerInfo = aph.getHeaderInfo("Scheme name=\"value\", other=\"value2\"").get(0);
Assert.assertTrue(headerInfo.getType().equalsIgnoreCase("Scheme"));
Assert.assertTrue(headerInfo.getParameter("name").equals("value"));
Assert.assertTrue(headerInfo.getParameter("other").equals("value2"));
headerInfo = aph.getHeaderInfo("Scheme name = value , other = \"value2\" ").get(0);
Assert.assertTrue(headerInfo.getType().equalsIgnoreCase("Scheme"));
Assert.assertTrue(headerInfo.getParameter("name").equals("value"));
Assert.assertTrue(headerInfo.getParameter("other").equals("value2"));
headerInfos = aph.getHeaderInfo("Scheme name=value, Scheme2 name=value2");
Assert.assertEquals(headerInfos.size(), 2);
Assert.assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Scheme"));
Assert.assertTrue(headerInfos.get(0).getParameter("nAmE").equals("value"));
Assert.assertThat(headerInfos.get(1).getType(), Matchers.equalToIgnoringCase("Scheme2"));
Assert.assertTrue(headerInfos.get(1).getParameter("nAmE").equals("value2"));
headerInfos = aph.getHeaderInfo("Scheme , ,, ,, name=value, Scheme2 name=value2");
Assert.assertEquals(headerInfos.size(), 2);
Assert.assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Scheme"));
Assert.assertTrue(headerInfos.get(0).getParameter("name").equals("value"));
Assert.assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Scheme2"));
Assert.assertTrue(headerInfos.get(1).getParameter("name").equals("value2"));
//Negotiate with base64 Content
headerInfo = aph.getHeaderInfo("Negotiate TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAFAs4OAAAADw==").get(0);
Assert.assertTrue(headerInfo.getType().equalsIgnoreCase("Negotiate"));
Assert.assertTrue(headerInfo.getBase64().equals("TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAFAs4OAAAADw=="));
headerInfos = aph.getHeaderInfo("Negotiate TlRMTVNTUAABAAAAAAAAAFAs4OAAAADw==, "
+ "Negotiate YIIJvwYGKwYBBQUCoIIJszCCCa+gJDAi=");
Assert.assertTrue(headerInfos.get(0).getType().equalsIgnoreCase("Negotiate"));
Assert.assertTrue(headerInfos.get(0).getBase64().equals("TlRMTVNTUAABAAAAAAAAAFAs4OAAAADw=="));
Assert.assertTrue(headerInfos.get(1).getType().equalsIgnoreCase("Negotiate"));
Assert.assertTrue(headerInfos.get(1).getBase64().equals("YIIJvwYGKwYBBQUCoIIJszCCCa+gJDAi="));
}
}

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-continuation</artifactId>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-deploy</artifactId>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-distribution</artifactId>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<artifactId>jetty-documentation</artifactId>
<name>Jetty :: Documentation</name>

View File

@ -344,6 +344,8 @@ The ALPN implementation, relying on modifications of OpenJDK classes, updates ev
|1.8.0u152 |8.1.11.v20170118
|1.8.0u161 |8.1.12.v20180117
|1.8.0u162 |8.1.12.v20180117
|1.8.0u171 |8.1.12.v20180117
|1.8.0u172 |8.1.12.v20180117
|=============================
[[alpn-build]]

View File

@ -258,3 +258,7 @@ This allows for some complex hierarchies of configuration details.
If the file does not exist at the given location, download it from the given http URI.
Note: location is always relative to `${jetty.base}`.
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/.

View File

@ -377,11 +377,15 @@ The `AbstractLoginModule` does not support any caching, so if you want to cache
==== Other Goodies
===== ServletRequestCallback
This callback gives you access to the ServletRequest that is involved in the authentication, and thus to other features like the current Session. This callback can be configured in your custom LoginModule implementation. Note that none of the LoginModule implementations provided with Jetty currently use this callback.
===== RequestParameterCallback
As all servlet containers intercept and process a form submission with action `j_security_check`, it is usually not possible to insert any extra input fields onto a login form with which to perform authentication: you may only pass `j_username` and `j_password`.
For those rare occasions when this is not good enough, and you require more information from the user in order to authenticate them, you can use the JAAS callback handler `org.eclipse.jetty.jaas.callback.RequestParameterCallback`.
This callback handler gives you access to all parameters that were passed in the form submission.
This callback gives you access to all parameters that were passed in the form submission.
To use it, in the `login()` method of your custom login module, add the `RequestParameterCallback` to the list of callback handlers the login module uses, tell it which params you are interested in, and then get the value of the parameter back.
Here is an example:

View File

@ -1,5 +1,5 @@
<copyright>
<year>1995-2017</year>
<year>1995-2018</year>
<holder>Mort Bay Consulting Pty. Ltd.</holder>
</copyright>
<revhistory>

View File

@ -100,7 +100,7 @@ To test a Jetty release, complete the following steps for each release you want
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jetty-version>7.6.2.v20120308</jetty-version>
<jetty-plugin-version>${jetty-version}</jetty-plugin-version>
<slf4j-version>1.6.4</slf4j-version>
<slf4j.version>1.6.4</slf4j.version>
<spring-version>3.1.0.RELEASE</spring-version>
</properties>
<repositories>

View File

@ -3,7 +3,7 @@
<parent>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -3,7 +3,7 @@
<parent>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -3,7 +3,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>org.eclipse.jetty.gcloud</groupId>
<artifactId>gcloud-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -3,7 +3,7 @@
<parent>
<artifactId>jetty-project</artifactId>
<groupId>org.eclipse.jetty</groupId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -3,7 +3,7 @@
<parent>
<artifactId>jetty-project</artifactId>
<groupId>org.eclipse.jetty</groupId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-home</artifactId>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-http-spi</artifactId>
@ -52,7 +52,7 @@
<configuration>
<instructions>
<Bundle-Description>Jetty Http SPI</Bundle-Description>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=com.sun.net.httpserver.spi.HttpServerProvider</Provide-Capability>
<_nouses>true</_nouses>
</instructions>

View File

@ -3,7 +3,7 @@
<parent>
<artifactId>jetty-project</artifactId>
<groupId>org.eclipse.jetty</groupId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-http</artifactId>
@ -55,9 +55,6 @@
<configuration>
<instructions>
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
<!--
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
-->
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder</Provide-Capability>
</instructions>
</configuration>

View File

@ -101,7 +101,7 @@ public class PreEncodedHttpField extends HttpField
{
super(header,name, value);
for (int i=0;i<__encoders.length;i++)
_encodedField[i]=__encoders[i].getEncodedField(header,header.asString(),value);
_encodedField[i]=__encoders[i].getEncodedField(header,name,value);
}
public PreEncodedHttpField(HttpHeader header,String value)

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.http;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@ -181,4 +182,14 @@ public class HttpFieldTest
assertEquals("Accept: something\r\n",s);
}
@Test
public void testCachedFieldWithHeaderName()
{
PreEncodedHttpField field = new PreEncodedHttpField("X-My-Custom-Header", "something");
assertNull(field.getHeader());
assertEquals("X-My-Custom-Header", field.getName());
assertEquals("something", field.getValue());
}
}

View File

@ -3,7 +3,7 @@
<parent>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -3,7 +3,7 @@
<parent>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -129,11 +129,12 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
@Override
public void succeeded()
{
super.onOpen();
promise.succeeded(getSession());
// Only start reading from server after we have sent the client preface,
// otherwise we risk to read the server preface (a SETTINGS frame) and
// reply to that before we have the chance to send the client preface.
super.onOpen();
promise.succeeded(getSession());
produce();
}
@Override

View File

@ -69,7 +69,6 @@ import org.eclipse.jetty.util.Promise;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.After;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
@ -314,7 +313,7 @@ public abstract class FlowControlStrategyTest
{
final int windowSize = 1536;
final int length = 5 * windowSize;
final CountDownLatch settingsLatch = new CountDownLatch(1);
final CountDownLatch settingsLatch = new CountDownLatch(2);
start(new ServerSessionListener.Adapter()
{
@Override
@ -343,7 +342,9 @@ public abstract class FlowControlStrategyTest
Map<Integer, Integer> settings = new HashMap<>();
settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, windowSize);
session.settings(new SettingsFrame(settings, false), Callback.NOOP);
Callback.Completable completable = new Callback.Completable();
session.settings(new SettingsFrame(settings, false), completable);
completable.thenRun(settingsLatch::countDown);
Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
@ -661,88 +662,6 @@ public abstract class FlowControlStrategyTest
Assert.assertArrayEquals(data, bytes);
}
// TODO
// Since we changed the API to disallow consecutive data() calls without waiting
// for the callback, it is now not possible to have DATA1, DATA2 in the queue for
// the same stream. Perhaps this test should just be deleted.
@Ignore
@Test
public void testServerTwoDataFramesWithStalledStream() throws Exception
{
// Frames in queue = DATA1, DATA2.
// Server writes part of DATA1, then stalls.
// A window update unstalls the session, verify that the data is correctly sent.
Random random = new Random();
final byte[] chunk1 = new byte[1024];
random.nextBytes(chunk1);
final byte[] chunk2 = new byte[2048];
random.nextBytes(chunk2);
// Two SETTINGS frames: the initial after the preface,
// and the explicit where we set the stream window size to zero.
final AtomicReference<CountDownLatch> settingsLatch = new AtomicReference<>(new CountDownLatch(2));
final CountDownLatch dataLatch = new CountDownLatch(1);
start(new ServerSessionListener.Adapter()
{
@Override
public void onSettings(Session session, SettingsFrame frame)
{
settingsLatch.get().countDown();
}
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
{
stream.data(new DataFrame(stream.getId(), ByteBuffer.wrap(chunk1), false), Callback.NOOP);
stream.data(new DataFrame(stream.getId(), ByteBuffer.wrap(chunk2), true), Callback.NOOP);
dataLatch.countDown();
return null;
}
});
Session session = newClient(new Session.Listener.Adapter());
Map<Integer, Integer> settings = new HashMap<>();
settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, 0);
session.settings(new SettingsFrame(settings, false), Callback.NOOP);
Assert.assertTrue(settingsLatch.get().await(5, TimeUnit.SECONDS));
byte[] content = new byte[chunk1.length + chunk2.length];
final ByteBuffer buffer = ByteBuffer.wrap(content);
MetaData.Request metaData = newRequest("GET", new HttpFields());
HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
final CountDownLatch responseLatch = new CountDownLatch(1);
session.newStream(requestFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@Override
public void onData(Stream stream, DataFrame frame, Callback callback)
{
buffer.put(frame.getData());
callback.succeeded();
if (frame.isEndStream())
responseLatch.countDown();
}
});
Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
// Now we have the 2 DATA frames queued in the server.
// Unstall the stream window.
settingsLatch.set(new CountDownLatch(1));
settings.clear();
settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, chunk1.length / 2);
session.settings(new SettingsFrame(settings, false), Callback.NOOP);
Assert.assertTrue(settingsLatch.get().await(5, TimeUnit.SECONDS));
Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
// Check that the data is sent correctly.
byte[] expected = new byte[content.length];
System.arraycopy(chunk1, 0, expected, 0, chunk1.length);
System.arraycopy(chunk2, 0, expected, chunk1.length, chunk2.length);
Assert.assertArrayEquals(expected, content);
}
@Test
public void testClientSendingInitialSmallWindow() throws Exception
{

View File

@ -236,7 +236,7 @@ public class HTTP2Test extends AbstractTest
});
}
Assert.assertTrue(latch.await(requests, TimeUnit.SECONDS));
Assert.assertTrue(server.dump() + System.lineSeparator() + client.dump(), latch.await(requests, TimeUnit.SECONDS));
}
@Test

View File

@ -0,0 +1,76 @@
//
// ========================================================================
// 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.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.util.Promise;
import org.junit.Assert;
import org.junit.Test;
public class InvalidServerTest extends AbstractTest
{
@Test
public void testInvalidPreface() throws Exception
{
try (ServerSocket server = new ServerSocket(0))
{
prepareClient();
client.start();
CountDownLatch failureLatch = new CountDownLatch(1);
Promise.Completable<Session> promise = new Promise.Completable<>();
InetSocketAddress address = new InetSocketAddress("localhost", server.getLocalPort());
client.connect(address, new Session.Listener.Adapter()
{
@Override
public void onFailure(Session session, Throwable failure)
{
failureLatch.countDown();
}
}, 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)
{
int read = input.read();
if (read < 0)
break;
}
}
}
}

View File

@ -263,6 +263,14 @@ public class RawHTTP2ProxyTest
Assert.assertTrue(latch2.await(5, TimeUnit.SECONDS));
}
private static DataFrame copyDataFrame(DataFrame frame)
{
ByteBuffer data = frame.getData();
ByteBuffer dataCopy = ByteBuffer.allocate(data.remaining());
dataCopy.put(data).flip();
return new DataFrame(frame.getStreamId(), dataCopy, frame.isEndStream(), frame.padding());
}
private static class ClientToProxySessionListener extends ServerSessionListener.Adapter
{
private final Map<Integer, ClientToProxyToServer> forwarders = new ConcurrentHashMap<>();
@ -497,7 +505,8 @@ public class RawHTTP2ProxyTest
{
if (LOGGER.isDebugEnabled())
LOGGER.debug("CPS received {} on {}", frame, stream);
offer(stream, frame, callback);
// Must copy the bytes because they are not consumed here.
offer(stream, copyDataFrame(frame), callback);
}
@Override
@ -659,7 +668,8 @@ public class RawHTTP2ProxyTest
{
if (LOGGER.isDebugEnabled())
LOGGER.debug("SPC received {} on {}", frame, stream);
offer(stream, frame, callback);
// Must copy the bytes because they are not consumed here.
offer(stream, copyDataFrame(frame), callback);
}
@Override

View File

@ -20,6 +20,9 @@ package org.eclipse.jetty.http2.client;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -37,11 +40,14 @@ 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.DataFrame;
import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.Promise;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
@ -223,4 +229,62 @@ public class TrailersTest extends AbstractTest
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
}
@Test
public void testTrailersSentByServerShouldNotSendEmptyDataFrame() throws Exception
{
String trailerName = "X-Trailer";
String trailerValue = "Zot!";
start(new EmptyHttpServlet()
{
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
Request jettyRequest = (Request)request;
Response jettyResponse = jettyRequest.getResponse();
HttpFields trailers = new HttpFields();
jettyResponse.setTrailers(() -> trailers);
jettyResponse.getOutputStream().write("hello_trailers".getBytes(StandardCharsets.UTF_8));
jettyResponse.flushBuffer();
// Force the content to be sent above, and then only send the trailers below.
trailers.put(trailerName, trailerValue);
}
});
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
HeadersFrame requestFrame = new HeadersFrame(request, null, true);
CountDownLatch latch = new CountDownLatch(1);
List<Frame> frames = new ArrayList<>();
session.newStream(requestFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
{
@Override
public void onHeaders(Stream stream, HeadersFrame frame)
{
frames.add(frame);
if (frame.isEndStream())
latch.countDown();
}
@Override
public void onData(Stream stream, DataFrame frame, Callback callback)
{
frames.add(frame);
callback.succeeded();
}
});
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
Assert.assertThat(frames.toString(), frames.size(), Matchers.is(3));
HeadersFrame headers = (HeadersFrame)frames.get(0);
DataFrame data = (DataFrame)frames.get(1);
HeadersFrame trailers = (HeadersFrame)frames.get(2);
Assert.assertFalse(headers.isEndStream());
Assert.assertFalse(data.isEndStream());
Assert.assertTrue(trailers.isEndStream());
Assert.assertThat(trailers.getMetaData().getFields().get(trailerName), Matchers.equalTo(trailerValue));
}
}

View File

@ -3,7 +3,7 @@
<parent>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -103,7 +103,6 @@ public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy
float ratio = bufferRatio;
WindowUpdateFrame windowFrame = null;
int level = sessionLevel.addAndGet(length);
int maxLevel = (int)(maxSessionRecvWindow.get() * ratio);
if (level > maxLevel)
@ -113,7 +112,7 @@ public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy
session.updateRecvWindow(level);
if (LOG.isDebugEnabled())
LOG.debug("Data consumed, {} bytes, updated session recv window by {}/{} for {}", length, level, maxLevel, session);
windowFrame = new WindowUpdateFrame(0, level);
session.frames(null, Callback.NOOP, new WindowUpdateFrame(0, level), Frame.EMPTY_ARRAY);
}
else
{
@ -127,7 +126,6 @@ public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy
LOG.debug("Data consumed, {} bytes, session recv window level {}/{} for {}", length, level, maxLevel, session);
}
Frame[] windowFrames = Frame.EMPTY_ARRAY;
if (stream != null)
{
if (stream.isRemotelyClosed())
@ -148,11 +146,7 @@ public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy
stream.updateRecvWindow(level);
if (LOG.isDebugEnabled())
LOG.debug("Data consumed, {} bytes, updated stream recv window by {}/{} for {}", length, level, maxLevel, stream);
WindowUpdateFrame frame = new WindowUpdateFrame(stream.getId(), level);
if (windowFrame == null)
windowFrame = frame;
else
windowFrames = new Frame[]{frame};
session.frames(stream, Callback.NOOP, new WindowUpdateFrame(stream.getId(), level), Frame.EMPTY_ARRAY);
}
else
{
@ -162,9 +156,6 @@ public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy
}
}
}
if (windowFrame != null)
session.frames(stream, Callback.NOOP, windowFrame, windowFrames);
}
@Override

View File

@ -101,7 +101,6 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher.
if (LOG.isDebugEnabled())
LOG.debug("HTTP2 Open {} ", this);
super.onOpen();
strategy.produce();
}
@Override
@ -119,7 +118,7 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher.
{
if (LOG.isDebugEnabled())
LOG.debug("HTTP2 onFillable {} ", this);
strategy.produce();
produce();
}
private int fill(EndPoint endPoint, ByteBuffer buffer)
@ -154,11 +153,25 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher.
{
offerTask(task);
if (dispatch)
strategy.dispatch();
dispatch();
else
produce();
}
protected void produce()
{
if (LOG.isDebugEnabled())
LOG.debug("HTTP2 produce {} ", this);
strategy.produce();
}
protected void dispatch()
{
if (LOG.isDebugEnabled())
LOG.debug("HTTP2 dispatch {} ", this);
strategy.dispatch();
}
@Override
public void close()
{
@ -186,8 +199,7 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher.
@Override
public void onFlushed(long bytes) throws IOException
{
// TODO: add method to ISession ?
((HTTP2Session)session).onFlushed(bytes);
session.onFlushed(bytes);
}
protected class HTTP2Producer implements ExecutionStrategy.Producer

View File

@ -21,16 +21,17 @@ package org.eclipse.jetty.http2;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import org.eclipse.jetty.http2.frames.Frame;
import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.WriteFlusher;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IteratingCallback;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
@ -41,15 +42,16 @@ import org.eclipse.jetty.util.log.Logger;
public class HTTP2Flusher extends IteratingCallback implements Dumpable
{
private static final Logger LOG = Log.getLogger(HTTP2Flusher.class);
private static final ByteBuffer[] EMPTY_BYTE_BUFFERS = new ByteBuffer[0];
private final Queue<WindowEntry> windows = new ArrayDeque<>();
private final Deque<Entry> frames = new ArrayDeque<>();
private final Queue<Entry> entries = new ArrayDeque<>();
private final List<Entry> actives = new ArrayList<>();
private final Deque<Entry> entries = new ArrayDeque<>();
private final Queue<Entry> pendingEntries = new ArrayDeque<>();
private final Set<Entry> processedEntries = new HashSet<>();
private final HTTP2Session session;
private final ByteBufferPool.Lease lease;
private Entry stalled;
private Throwable terminated;
private Entry stalledEntry;
public HTTP2Flusher(HTTP2Session session)
{
@ -79,9 +81,9 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
closed = terminated;
if (closed == null)
{
frames.offerFirst(entry);
entries.offerFirst(entry);
if (LOG.isDebugEnabled())
LOG.debug("Prepended {}, frames={}", entry, frames.size());
LOG.debug("Prepended {}, entries={}", entry, entries.size());
}
}
if (closed == null)
@ -98,9 +100,9 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
closed = terminated;
if (closed == null)
{
frames.offer(entry);
entries.offer(entry);
if (LOG.isDebugEnabled())
LOG.debug("Appended {}, frames={}", entry, frames.size());
LOG.debug("Appended {}, entries={}", entry, entries.size());
}
}
if (closed == null)
@ -121,7 +123,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
{
synchronized (this)
{
return frames.size();
return entries.size();
}
}
@ -136,39 +138,44 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
if (terminated != null)
throw terminated;
while (!windows.isEmpty())
{
WindowEntry entry = windows.poll();
entry.perform();
WindowEntry windowEntry;
while ((windowEntry = windows.poll()) != null)
windowEntry.perform();
Entry entry;
while ((entry = entries.poll()) != null)
pendingEntries.offer(entry);
}
for (Entry entry : frames)
{
entries.offer(entry);
actives.add(entry);
}
frames.clear();
}
if (entries.isEmpty())
if (pendingEntries.isEmpty())
{
if (LOG.isDebugEnabled())
LOG.debug("Flushed {}", session);
return Action.IDLE;
}
while (!entries.isEmpty())
while (true)
{
Entry entry = entries.poll();
boolean progress = false;
if (pendingEntries.isEmpty())
break;
Iterator<Entry> pending = pendingEntries.iterator();
while (pending.hasNext())
{
Entry entry = pending.next();
if (LOG.isDebugEnabled())
LOG.debug("Processing {}", entry);
// If the stream has been reset or removed, don't send the frame.
// If the stream has been reset or removed,
// don't send the frame and fail it here.
if (entry.isStale())
{
if (LOG.isDebugEnabled())
LOG.debug("Stale {}", entry);
entry.failed(new EofException("reset"));
pending.remove();
continue;
}
@ -176,103 +183,113 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
{
if (entry.generate(lease))
{
if (entry.getDataBytesRemaining() > 0)
entries.offer(entry);
if (LOG.isDebugEnabled())
LOG.debug("Generated {} frame bytes for {}", entry.getFrameBytesGenerated(), entry);
progress = true;
processedEntries.add(entry);
if (entry.getDataBytesRemaining() == 0)
pending.remove();
}
else
{
if (stalled == null)
stalled = entry;
if (session.getSendWindow() <= 0 && stalledEntry == null)
{
stalledEntry = entry;
if (LOG.isDebugEnabled())
LOG.debug("Flow control stalled at {}", entry);
// Continue to process control frames.
}
}
}
catch (Throwable failure)
{
// Failure to generate the entry is catastrophic.
if (LOG.isDebugEnabled())
LOG.debug("Failure generating frame " + entry.frame, failure);
LOG.debug("Failure generating " + entry, failure);
failed(failure);
return Action.SUCCEEDED;
}
}
if (!progress)
break;
if (stalledEntry != null)
break;
int writeThreshold = session.getWriteThreshold();
if (lease.getTotalLength() >= writeThreshold)
{
if (LOG.isDebugEnabled())
LOG.debug("Write threshold {} exceeded", writeThreshold);
break;
}
}
List<ByteBuffer> byteBuffers = lease.getByteBuffers();
if (byteBuffers.isEmpty())
{
complete();
finish();
return Action.IDLE;
}
if (LOG.isDebugEnabled())
LOG.debug("Writing {} buffers ({} bytes) for {} frames {}", byteBuffers.size(), lease.getTotalLength(), actives.size(), actives);
session.getEndPoint().write(this, byteBuffers.toArray(new ByteBuffer[byteBuffers.size()]));
LOG.debug("Writing {} buffers ({} bytes) - entries processed/pending {}/{}: {}/{}",
byteBuffers.size(),
lease.getTotalLength(),
processedEntries.size(),
pendingEntries.size(),
processedEntries,
pendingEntries);
session.getEndPoint().write(this, byteBuffers.toArray(EMPTY_BYTE_BUFFERS));
return Action.SCHEDULED;
}
void onFlushed(long bytes) throws IOException
{
// For the given flushed bytes, we want to only
// forward those that belong to data frame content.
for (Entry entry : actives)
{
int frameBytesLeft = entry.getFrameBytesRemaining();
if (frameBytesLeft > 0)
{
int update = (int)Math.min(bytes, frameBytesLeft);
entry.onFrameBytesFlushed(update);
bytes -= update;
IStream stream = entry.stream;
if (stream != null && !entry.isControl())
{
Object channel = stream.getAttachment();
if (channel instanceof WriteFlusher.Listener)
((WriteFlusher.Listener)channel).onFlushed(update - Frame.HEADER_LENGTH);
}
if (bytes == 0)
break;
}
}
// A single EndPoint write may be flushed multiple times (for example with SSL).
for (Entry entry : processedEntries)
bytes = entry.onFlushed(bytes);
}
@Override
public void succeeded()
{
if (LOG.isDebugEnabled())
LOG.debug("Written {} frames for {}", actives.size(), actives);
complete();
LOG.debug("Written {} buffers - entries processed/pending {}/{}: {}/{}",
lease.getByteBuffers().size(),
processedEntries.size(),
pendingEntries.size(),
processedEntries,
pendingEntries);
finish();
super.succeeded();
}
private void complete()
private void finish()
{
lease.recycle();
actives.forEach(Entry::complete);
processedEntries.forEach(Entry::succeeded);
processedEntries.clear();
if (stalled != null)
if (stalledEntry != null)
{
// We have written part of the frame, but there is more to write.
// The API will not allow to send two data frames for the same
// stream so we append the unfinished frame at the end to allow
// better interleaving with other streams.
int index = actives.indexOf(stalled);
for (int i = index; i < actives.size(); ++i)
int size = pendingEntries.size();
for (int i = 0; i < size; ++i)
{
Entry entry = actives.get(i);
if (entry.getDataBytesRemaining() > 0)
append(entry);
Entry entry = pendingEntries.peek();
if (entry == stalledEntry)
break;
pendingEntries.poll();
pendingEntries.offer(entry);
}
for (int i = 0; i < index; ++i)
{
Entry entry = actives.get(i);
if (entry.getDataBytesRemaining() > 0)
append(entry);
stalledEntry = null;
}
stalled = null;
}
actives.clear();
}
@Override
@ -287,18 +304,26 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
lease.recycle();
Throwable closed;
Set<Entry> allEntries;
synchronized (this)
{
closed = terminated;
terminated = x;
if (LOG.isDebugEnabled())
LOG.debug("{}, active/queued={}/{}", closed != null ? "Closing" : "Failing", actives.size(), frames.size());
actives.addAll(frames);
frames.clear();
LOG.debug(String.format("%s, entries processed/pending/queued=%d/%d/%d",
closed != null ? "Closing" : "Failing",
processedEntries.size(),
pendingEntries.size(),
entries.size()), x);
allEntries = new HashSet<>(entries);
entries.clear();
}
actives.forEach(entry -> entry.failed(x));
actives.clear();
allEntries.addAll(processedEntries);
processedEntries.clear();
allEntries.addAll(pendingEntries);
pendingEntries.clear();
allEntries.forEach(entry -> entry.failed(x));
// If the failure came from within the
// flusher, we need to close the connection.
@ -340,11 +365,12 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
@Override
public String toString()
{
return String.format("%s[window_queue=%d,frame_queue=%d,actives=%d]",
return String.format("%s[window_queue=%d,frame_queue=%d,processed/pending=%d/%d]",
super.toString(),
getWindowQueueSize(),
getFrameQueueSize(),
actives.size());
processedEntries.size(),
pendingEntries.size());
}
public static abstract class Entry extends Callback.Nested
@ -359,9 +385,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
this.stream = stream;
}
public abstract int getFrameBytesRemaining();
public abstract void onFrameBytesFlushed(int bytesFlushed);
public abstract int getFrameBytesGenerated();
public int getDataBytesRemaining()
{
@ -370,13 +394,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
protected abstract boolean generate(ByteBufferPool.Lease lease);
private void complete()
{
if (isStale())
failed(new EofException("reset"));
else
succeeded();
}
public abstract long onFlushed(long bytes) throws IOException;
@Override
public void failed(Throwable x)
@ -417,17 +435,6 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
}
}
private boolean isControl()
{
switch (frame.getType())
{
case DATA:
return false;
default:
return true;
}
}
@Override
public String toString()
{

View File

@ -51,6 +51,7 @@ import org.eclipse.jetty.http2.generator.Generator;
import org.eclipse.jetty.http2.parser.Parser;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.WriteFlusher;
import org.eclipse.jetty.util.AtomicBiInteger;
import org.eclipse.jetty.util.Atomics;
import org.eclipse.jetty.util.Callback;
@ -88,6 +89,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
private int maxRemoteStreams;
private long streamIdleTimeout;
private int initialSessionRecvWindow;
private int writeThreshold;
private boolean pushEnabled;
private long idleTime;
private GoAwayFrame closeFrame;
@ -106,6 +108,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
this.streamIdleTimeout = endPoint.getIdleTimeout();
this.sendWindow.set(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
this.recvWindow.set(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
this.writeThreshold = 32 * 1024;
this.pushEnabled = true; // SPEC: by default, push is enabled.
this.idleTime = System.nanoTime();
addBean(flowControl);
@ -186,6 +189,16 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
this.initialSessionRecvWindow = initialSessionRecvWindow;
}
public int getWriteThreshold()
{
return writeThreshold;
}
public void setWriteThreshold(int writeThreshold)
{
this.writeThreshold = writeThreshold;
}
public EndPoint getEndPoint()
{
return endPoint;
@ -962,7 +975,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
{
}
void onFlushed(long bytes) throws IOException
@Override
public void onFlushed(long bytes) throws IOException
{
flusher.onFlushed(bytes);
}
@ -1144,7 +1158,6 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
private class ControlEntry extends HTTP2Flusher.Entry
{
private int bytes;
private int frameBytes;
private ControlEntry(Frame frame, IStream stream, Callback callback)
@ -1153,25 +1166,27 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
}
@Override
public int getFrameBytesRemaining()
public int getFrameBytesGenerated()
{
return frameBytes;
}
@Override
public void onFrameBytesFlushed(int bytesFlushed)
protected boolean generate(ByteBufferPool.Lease lease)
{
frameBytes -= bytesFlushed;
frameBytes = generator.control(lease, frame);
beforeSend();
return true;
}
@Override
protected boolean generate(ByteBufferPool.Lease lease)
public long onFlushed(long bytes)
{
bytes = frameBytes = generator.control(lease, frame);
long flushed = Math.min(frameBytes, bytes);
if (LOG.isDebugEnabled())
LOG.debug("Generated {}", frame);
beforeSend();
return true;
LOG.debug("Flushed {}/{} frame bytes for {}", flushed, bytes, this);
frameBytes -= flushed;
return bytes - flushed;
}
/**
@ -1215,7 +1230,9 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
@Override
public void succeeded()
{
bytesWritten.addAndGet(bytes);
bytesWritten.addAndGet(frameBytes);
frameBytes = 0;
switch (frame.getType())
{
case HEADERS:
@ -1264,6 +1281,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
break;
}
}
super.succeeded();
}
@ -1278,10 +1296,10 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
private class DataEntry extends HTTP2Flusher.Entry
{
private int bytes;
private int frameBytes;
private int frameRemaining;
private int dataBytes;
private int dataWritten;
private int dataRemaining;
private DataEntry(DataFrame frame, IStream stream, Callback callback)
{
@ -1291,61 +1309,74 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
// of data frames that cannot be completely written due to
// the flow control window exhausting, since in that case
// we would have to count the padding only once.
dataBytes = frame.remaining();
dataRemaining = frame.remaining();
}
@Override
public int getFrameBytesRemaining()
public int getFrameBytesGenerated()
{
return frameBytes;
}
@Override
public void onFrameBytesFlushed(int bytesFlushed)
{
frameBytes -= bytesFlushed;
}
@Override
public int getDataBytesRemaining()
{
return dataBytes;
return dataRemaining;
}
@Override
protected boolean generate(ByteBufferPool.Lease lease)
{
int dataBytes = getDataBytesRemaining();
int dataRemaining = getDataBytesRemaining();
int sessionSendWindow = getSendWindow();
int streamSendWindow = stream.updateSendWindow(0);
int window = Math.min(streamSendWindow, sessionSendWindow);
if (window <= 0 && dataBytes > 0)
if (window <= 0 && dataRemaining > 0)
return false;
int length = Math.min(dataBytes, window);
int length = Math.min(dataRemaining, window);
// Only one DATA frame is generated.
DataFrame dataFrame = (DataFrame)frame;
bytes = frameBytes = generator.data(lease, dataFrame, length);
int written = bytes - Frame.HEADER_LENGTH;
int frameBytes = generator.data(lease, (DataFrame)frame, length);
this.frameBytes += frameBytes;
this.frameRemaining += frameBytes;
int dataBytes = frameBytes - Frame.HEADER_LENGTH;
this.dataBytes += dataBytes;
this.dataRemaining -= dataBytes;
if (LOG.isDebugEnabled())
LOG.debug("Generated {}, length/window/data={}/{}/{}", dataFrame, written, window, dataBytes);
LOG.debug("Generated {}, length/window/data={}/{}/{}", frame, dataBytes, window, dataRemaining);
this.dataWritten = written;
this.dataBytes -= written;
flowControl.onDataSending(stream, written);
stream.updateClose(dataFrame.isEndStream(), CloseState.Event.BEFORE_SEND);
flowControl.onDataSending(stream, dataBytes);
return true;
}
@Override
public long onFlushed(long bytes) throws IOException
{
long flushed = Math.min(frameRemaining, bytes);
if (LOG.isDebugEnabled())
LOG.debug("Flushed {}/{} frame bytes for {}", flushed, bytes, this);
frameRemaining -= flushed;
// We should only forward data (not frame) bytes,
// but we trade precision for simplicity.
Object channel = stream.getAttachment();
if (channel instanceof WriteFlusher.Listener)
((WriteFlusher.Listener)channel).onFlushed(flushed);
return bytes - flushed;
}
@Override
public void succeeded()
{
bytesWritten.addAndGet(bytes);
flowControl.onDataSent(stream, dataWritten);
bytesWritten.addAndGet(frameBytes);
frameBytes = 0;
frameRemaining = 0;
flowControl.onDataSent(stream, dataBytes);
dataBytes = 0;
// Do we have more to send ?
DataFrame dataFrame = (DataFrame)frame;

View File

@ -18,6 +18,8 @@
package org.eclipse.jetty.http2;
import java.io.IOException;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.api.Stream;
import org.eclipse.jetty.http2.frames.DataFrame;
@ -129,6 +131,14 @@ public interface ISession extends Session
*/
public void onFrame(Frame frame);
/**
* <p>Callback method invoked when bytes are flushed to the network.</p>
*
* @param bytes the number of bytes flushed to the network
* @throws IOException if the flush should fail
*/
public void onFlushed(long bytes) throws IOException;
/**
* @return the number of bytes written by this session
*/

View File

@ -3,7 +3,7 @@
<parent>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -51,7 +51,7 @@
<configuration>
<instructions>
<Bundle-Description>Http2 Hpack</Bundle-Description>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder</Provide-Capability>
<_nouses>true</_nouses>
</instructions>

View File

@ -3,7 +3,7 @@
<parent>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -3,7 +3,7 @@
<parent>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-parent</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -24,6 +24,7 @@ import org.eclipse.jetty.http2.BufferingFlowControlStrategy;
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.generator.Generator;
import org.eclipse.jetty.http2.parser.ServerParser;
import org.eclipse.jetty.io.Connection;
@ -62,6 +63,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
throw new IllegalArgumentException("Unsupported HTTP2 Protocol variant: "+p);
this.httpConfiguration = Objects.requireNonNull(httpConfiguration);
addBean(httpConfiguration);
setInputBufferSize(Frame.DEFAULT_MAX_LENGTH + Frame.HEADER_LENGTH);
}
@ManagedAttribute("The HPACK dynamic table maximum size")
@ -185,6 +187,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
streamIdleTimeout = endPoint.getIdleTimeout();
session.setStreamIdleTimeout(streamIdleTimeout);
session.setInitialSessionRecvWindow(getInitialSessionRecvWindow());
session.setWriteThreshold(getHttpConfiguration().getOutputBufferSize());
ServerParser parser = newServerParser(connector, session);
HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(),

View File

@ -145,6 +145,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
for (Frame frame : upgradeFrames)
getSession().onFrame(frame);
super.onOpen();
produce();
}
private void notifyAccept(ISession session)

View File

@ -91,41 +91,61 @@ public class HttpTransportOverHTTP2 implements HttpTransport
if (info != null)
{
metaData = info;
int status = info.getStatus();
boolean informational = HttpStatus.isInformational(status) && status != HttpStatus.SWITCHING_PROTOCOLS_101;
if (informational)
boolean interimResponse = status == HttpStatus.CONTINUE_100 || status == HttpStatus.PROCESSING_102;
if (interimResponse)
{
if (transportCallback.start(callback, false))
sendHeaders(info, false, transportCallback);
// Must not commit interim responses.
if (hasContent)
{
callback.failed(new IllegalStateException("Interim response cannot have content"));
}
else
{
boolean needsCommit = commit.compareAndSet(false, true);
if (needsCommit)
if (transportCallback.start(callback, false))
sendHeadersFrame(info, false, transportCallback);
}
}
else
{
if (commit.compareAndSet(false, true))
{
Supplier<HttpFields> trailers = info.getTrailerSupplier();
if (hasContent)
{
Callback nested = trailers == null || !lastContent ? callback : new SendTrailers(callback);
Callback commitCallback = new Callback.Nested(nested)
Callback commitCallback = new Callback.Nested(callback)
{
@Override
public void succeeded()
{
if (transportCallback.start(nested, false))
sendContent(content, lastContent, trailers == null && lastContent, transportCallback);
}
};
if (transportCallback.start(commitCallback, true))
sendHeaders(info, false, transportCallback);
if (lastContent)
{
Supplier<HttpFields> trailers = info.getTrailerSupplier();
if (transportCallback.start(new SendTrailers(getCallback(), trailers), false))
sendDataFrame(content, true, trailers == null, transportCallback);
}
else
{
Callback nested = trailers == null ? callback : new SendTrailers(callback);
if (transportCallback.start(nested, true))
sendHeaders(info, trailers == null && lastContent, transportCallback);
if (transportCallback.start(getCallback(), false))
sendDataFrame(content, false, false, transportCallback);
}
}
};
if (transportCallback.start(commitCallback, true))
sendHeadersFrame(info, false, transportCallback);
}
else
{
if (lastContent)
{
Supplier<HttpFields> trailers = info.getTrailerSupplier();
if (transportCallback.start(new SendTrailers(callback, trailers), true))
sendHeadersFrame(info, trailers == null, transportCallback);
}
else
{
if (transportCallback.start(callback, true))
sendHeadersFrame(info, false, transportCallback);
}
}
}
else
@ -137,11 +157,26 @@ public class HttpTransportOverHTTP2 implements HttpTransport
else
{
if (hasContent || lastContent)
{
if (lastContent)
{
Supplier<HttpFields> trailers = metaData.getTrailerSupplier();
Callback nested = trailers == null ? callback : new SendTrailers(callback);
if (transportCallback.start(nested, false))
sendContent(content, lastContent, trailers == null && lastContent, transportCallback);
SendTrailers sendTrailers = new SendTrailers(callback, trailers);
if (hasContent || trailers == null)
{
if (transportCallback.start(sendTrailers, false))
sendDataFrame(content, true, trailers == null, transportCallback);
}
else
{
sendTrailers.succeeded();
}
}
else
{
if (transportCallback.start(callback, false))
sendDataFrame(content, false, false, transportCallback);
}
}
else
{
@ -186,7 +221,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport
}, new Stream.Listener.Adapter()); // TODO: handle reset from the client ?
}
private void sendHeaders(MetaData.Response info, boolean endStream, Callback callback)
private void sendHeadersFrame(MetaData.Response info, boolean endStream, Callback callback)
{
if (LOG.isDebugEnabled())
{
@ -200,7 +235,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport
stream.headers(frame, callback);
}
private void sendContent(ByteBuffer content, boolean lastContent, boolean endStream, Callback callback)
private void sendDataFrame(ByteBuffer content, boolean lastContent, boolean endStream, Callback callback)
{
if (LOG.isDebugEnabled())
{
@ -212,7 +247,7 @@ public class HttpTransportOverHTTP2 implements HttpTransport
stream.data(frame, callback);
}
private void sendTrailers(MetaData metaData, Callback callback)
private void sendTrailersFrame(MetaData metaData, Callback callback)
{
if (LOG.isDebugEnabled())
{
@ -385,16 +420,26 @@ public class HttpTransportOverHTTP2 implements HttpTransport
private class SendTrailers extends Callback.Nested
{
private SendTrailers(Callback callback)
private final Supplier<HttpFields> trailers;
private SendTrailers(Callback callback, Supplier<HttpFields> trailers)
{
super(callback);
this.trailers = trailers;
}
@Override
public void succeeded()
{
if (trailers != null)
{
if (transportCallback.start(getCallback(), false))
sendTrailers(new MetaData(HttpVersion.HTTP_2, metaData.getTrailerSupplier().get()), transportCallback);
sendTrailersFrame(new MetaData(HttpVersion.HTTP_2, trailers.get()), transportCallback);
}
else
{
super.succeeded();
}
}
}
}

View File

@ -3,7 +3,7 @@
<parent>
<artifactId>jetty-project</artifactId>
<groupId>org.eclipse.jetty</groupId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-infinispan</artifactId>

View File

@ -2,7 +2,7 @@
<parent>
<artifactId>jetty-project</artifactId>
<groupId>org.eclipse.jetty</groupId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-io</artifactId>

View File

@ -101,8 +101,8 @@ public interface ByteBufferPool
public long getTotalLength()
{
long length = 0;
for (int i = 0; i < buffers.size(); ++i)
length += buffers.get(i).remaining();
for (ByteBuffer buffer : buffers)
length += buffer.remaining();
return length;
}

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-jaas</artifactId>
@ -34,5 +34,10 @@
<artifactId>jetty-security</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -20,7 +20,6 @@ package org.eclipse.jetty.jaas;
import java.io.IOException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashSet;
@ -32,25 +31,34 @@ import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.servlet.ServletRequest;
import org.eclipse.jetty.jaas.callback.ServletRequestCallback;
import org.eclipse.jetty.jaas.callback.DefaultCallbackHandler;
import org.eclipse.jetty.jaas.callback.ObjectCallback;
import org.eclipse.jetty.jaas.callback.RequestParameterCallback;
import org.eclipse.jetty.security.DefaultIdentityService;
import org.eclipse.jetty.security.IdentityService;
import org.eclipse.jetty.security.LoginService;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.util.ArrayUtil;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/* ---------------------------------------------------- */
/**
* JAASLoginService
*
*
* Implementation of jetty's LoginService that works with JAAS for
* authorization and authentication.
*
*/
public class JAASLoginService extends AbstractLifeCycle implements LoginService
{
@ -65,20 +73,17 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
protected String _loginModuleName;
protected JAASUserPrincipal _defaultUser = new JAASUserPrincipal(null, null, null);
protected IdentityService _identityService;
protected Configuration _configuration;
/* ---------------------------------------------------- */
/**
* Constructor.
*
*/
public JAASLoginService()
{
}
/* ---------------------------------------------------- */
/**
* Constructor.
*
* @param name the name of the realm
*/
@ -90,7 +95,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
}
/* ---------------------------------------------------- */
/**
* Get the name of the realm.
*
@ -103,7 +108,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
}
/* ---------------------------------------------------- */
/**
* Set the name of the realm
*
@ -114,8 +119,29 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
_realmName = name;
}
/* ------------------------------------------------------------ */
/** Get the identityService.
/**
* @return the configuration
*/
public Configuration getConfiguration()
{
return _configuration;
}
/**
* @param configuration the configuration to set
*/
public void setConfiguration(Configuration configuration)
{
_configuration = configuration;
}
/**
* Get the identityService.
* @return the identityService
*/
@Override
@ -124,8 +150,9 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
return _identityService;
}
/* ------------------------------------------------------------ */
/** Set the identityService.
/**
* Set the identityService.
* @param identityService the identityService to set
*/
@Override
@ -134,7 +161,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
_identityService = identityService;
}
/* ------------------------------------------------------------ */
/**
* Set the name to use to index into the config
* file of LoginModules.
@ -146,52 +173,47 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
_loginModuleName = name;
}
/* ------------------------------------------------------------ */
public void setCallbackHandlerClass (String classname)
{
_callbackHandlerClass = classname;
}
/* ------------------------------------------------------------ */
public void setRoleClassNames (String[] classnames)
{
ArrayList<String> tmp = new ArrayList<String>();
if (classnames != null)
tmp.addAll(Arrays.asList(classnames));
if (!tmp.contains(DEFAULT_ROLE_CLASS_NAME))
tmp.add(DEFAULT_ROLE_CLASS_NAME);
_roleClassNames = tmp.toArray(new String[tmp.size()]);
if (classnames == null || classnames.length == 0)
{
_roleClassNames = DEFAULT_ROLE_CLASS_NAMES;
return;
}
/* ------------------------------------------------------------ */
_roleClassNames = ArrayUtil.addToArray(classnames, DEFAULT_ROLE_CLASS_NAME, String.class);
}
public String[] getRoleClassNames()
{
return _roleClassNames;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
*/
@Override
protected void doStart() throws Exception
{
if (_identityService==null)
_identityService=new DefaultIdentityService();
_identityService = new DefaultIdentityService();
super.doStart();
}
/* ------------------------------------------------------------ */
@Override
public UserIdentity login(final String username,final Object credentials, final ServletRequest request)
{
try
{
CallbackHandler callbackHandler = null;
if (_callbackHandlerClass == null)
{
callbackHandler = new CallbackHandler()
@ -207,7 +229,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
}
else if (callback instanceof PasswordCallback)
{
((PasswordCallback)callback).setPassword((char[]) credentials.toString().toCharArray());
((PasswordCallback)callback).setPassword(credentials.toString().toCharArray());
}
else if (callback instanceof ObjectCallback)
{
@ -219,6 +241,10 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
if (request!=null)
rpc.setParameterValues(Arrays.asList(request.getParameterValues(rpc.getParameterName())));
}
else if (callback instanceof ServletRequestCallback)
{
((ServletRequestCallback)callback).setRequest(request);
}
else
throw new UnsupportedCallbackException(callback);
}
@ -228,12 +254,21 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
else
{
Class<?> clazz = Loader.loadClass(_callbackHandlerClass);
callbackHandler = (CallbackHandler)clazz.newInstance();
callbackHandler = (CallbackHandler)clazz.getDeclaredConstructor().newInstance();
if (DefaultCallbackHandler.class.isAssignableFrom(clazz))
{
DefaultCallbackHandler dch = (DefaultCallbackHandler)callbackHandler;
if (request instanceof Request)
dch.setRequest((Request)request);
dch.setCredential(credentials);
dch.setUserName(username);
}
}
//set up the login context
//TODO jaspi requires we provide the Configuration parameter
Subject subject = new Subject();
LoginContext loginContext = new LoginContext(_loginModuleName, subject, callbackHandler);
LoginContext loginContext = (_configuration==null?new LoginContext(_loginModuleName, subject, callbackHandler)
:new LoginContext(_loginModuleName, subject, callbackHandler, _configuration));
loginContext.login();
@ -243,34 +278,14 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
return _identityService.newUserIdentity(subject,userPrincipal,getGroups(subject));
}
catch (LoginException e)
{
LOG.warn(e);
}
catch (IOException e)
{
LOG.warn(e);
}
catch (UnsupportedCallbackException e)
{
LOG.warn(e);
}
catch (InstantiationException e)
{
LOG.warn(e);
}
catch (IllegalAccessException e)
{
LOG.warn(e);
}
catch (ClassNotFoundException e)
catch (Exception e)
{
LOG.warn(e);
}
return null;
}
/* ------------------------------------------------------------ */
@Override
public boolean validate(UserIdentity user)
{
@ -278,7 +293,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
return true;
}
/* ------------------------------------------------------------ */
private String getUserName(CallbackHandler callbackHandler) throws IOException, UnsupportedCallbackException
{
NameCallback nameCallback = new NameCallback("foo");
@ -286,7 +301,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
return nameCallback.getName();
}
/* ------------------------------------------------------------ */
@Override
public void logout(UserIdentity user)
{
@ -303,31 +318,64 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
}
/* ------------------------------------------------------------ */
@SuppressWarnings({ "unchecked", "rawtypes" })
private String[] getGroups (Subject subject)
/**
* Get all of the groups for the user.
*
* @param subject the Subject representing the user
*
* @return all the names of groups that the user is in, or 0 length array if none
*/
protected String[] getGroups (Subject subject)
{
//get all the roles of the various types
String[] roleClassNames = getRoleClassNames();
Collection<String> groups = new LinkedHashSet<String>();
try
Collection<String> groups = new LinkedHashSet<>();
Set<Principal> principals = subject.getPrincipals();
for (Principal principal : principals)
{
for (String roleClassName : roleClassNames)
Class<?> c = principal.getClass();
while (c!=null)
{
Class load_class = Thread.currentThread().getContextClassLoader().loadClass(roleClassName);
Set<Principal> rolesForType = subject.getPrincipals(load_class);
for (Principal principal : rolesForType)
if (roleClassNameMatches(c.getName()))
{
groups.add(principal.getName());
break;
}
boolean added = false;
for (Class<?> ci:c.getInterfaces())
{
if (roleClassNameMatches(ci.getName()))
{
groups.add(principal.getName());
added = true;
break;
}
}
if (!added)
{
c = c.getSuperclass();
}
else
break;
}
}
return groups.toArray(new String[groups.size()]);
}
catch (ClassNotFoundException e)
private boolean roleClassNameMatches (String classname)
{
throw new RuntimeException(e);
boolean result = false;
for (String roleClassName:getRoleClassNames())
{
if (roleClassName.equals(classname))
{
result = true;
break;
}
}
return result;
}
}

View File

@ -30,7 +30,10 @@ import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.security.Password;
/**
* DefaultUsernameCredentialCallbackHandler
* DefaultCallbackHandler
*
* An implementation of the JAAS CallbackHandler. Users can provide
* their own implementation instead and set the name of its class on the JAASLoginService.
*/
public class DefaultCallbackHandler extends AbstractCallbackHandler
{
@ -38,7 +41,7 @@ public class DefaultCallbackHandler extends AbstractCallbackHandler
public void setRequest (Request request)
{
this._request = request;
_request = request;
}
@Override
@ -71,6 +74,10 @@ public class DefaultCallbackHandler extends AbstractCallbackHandler
RequestParameterCallback callback = (RequestParameterCallback)callbacks[i];
callback.setParameterValues(Arrays.asList(_request.getParameterValues(callback.getParameterName())));
}
else if (callbacks[i] instanceof ServletRequestCallback)
{
((ServletRequestCallback)callbacks[i]).setRequest(_request);
}
else
throw new UnsupportedCallbackException(callbacks[i]);
}

View File

@ -0,0 +1,44 @@
//
// ========================================================================
// 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.jaas.callback;
import javax.security.auth.callback.Callback;
import javax.servlet.ServletRequest;
/**
* ServletRequestCallback
*
* Provides access to the request associated with the authentication.
*/
public class ServletRequestCallback implements Callback
{
protected ServletRequest _request;
public void setRequest (ServletRequest request)
{
_request = request;
}
public ServletRequest getRequest ()
{
return _request;
}
}

View File

@ -115,6 +115,12 @@ public abstract class AbstractLoginModule implements LoginModule
}
}
public abstract UserInfo getUserInfo (String username) throws Exception;
public Subject getSubject ()
{
return this.subject;
@ -198,7 +204,6 @@ public abstract class AbstractLoginModule implements LoginModule
public Callback[] configureCallbacks ()
{
Callback[] callbacks = new Callback[3];
callbacks[0] = new NameCallback("Enter user name");
callbacks[1] = new ObjectCallback();
@ -213,8 +218,6 @@ public abstract class AbstractLoginModule implements LoginModule
}
public abstract UserInfo getUserInfo (String username) throws Exception;
/**

View File

@ -105,17 +105,9 @@ public class JDBCLoginModule extends AbstractDatabaseLoginModule
dbPassword = "";
if (dbDriver != null)
Loader.loadClass(dbDriver).newInstance();
Loader.loadClass(dbDriver).getDeclaredConstructor().newInstance();
}
catch (ClassNotFoundException e)
{
throw new IllegalStateException (e.toString());
}
catch (InstantiationException e)
{
throw new IllegalStateException (e.toString());
}
catch (IllegalAccessException e)
catch (Exception e)
{
throw new IllegalStateException (e.toString());
}

View File

@ -0,0 +1,182 @@
//
// ========================================================================
// 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.jaas;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.security.Principal;
import java.util.Collections;
import javax.security.auth.Subject;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
import javax.security.auth.login.Configuration;
import org.eclipse.jetty.security.DefaultIdentityService;
import org.eclipse.jetty.server.Request;
import org.junit.Test;
/**
* JAASLoginServiceTest
*
*
*/
public class JAASLoginServiceTest
{
public static class TestConfiguration extends Configuration
{
AppConfigurationEntry _entry = new AppConfigurationEntry(TestLoginModule.class.getCanonicalName(), LoginModuleControlFlag.REQUIRED, Collections.emptyMap());
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name)
{
return new AppConfigurationEntry[] {_entry};
}
}
interface SomeRole
{
}
public class TestRole implements Principal, SomeRole
{
String _name;
public TestRole (String name)
{
_name = name;
}
public String getName()
{
return _name;
}
}
public class AnotherTestRole extends TestRole
{
public AnotherTestRole(String name)
{
super(name);
}
}
public class NotTestRole implements Principal
{
String _name;
public NotTestRole (String n)
{
_name = n;
}
public String getName()
{
return _name;
}
}
@Test
public void testServletRequestCallback () throws Exception
{
//Test with the DefaultCallbackHandler
JAASLoginService ls = new JAASLoginService("foo");
ls.setCallbackHandlerClass("org.eclipse.jetty.jaas.callback.DefaultCallbackHandler");
ls.setIdentityService(new DefaultIdentityService());
ls.setConfiguration(new TestConfiguration());
Request request = new Request(null, null);
ls.login("aaardvaark", "aaa", request);
//Test with the fallback CallbackHandler
ls = new JAASLoginService("foo");
ls.setIdentityService(new DefaultIdentityService());
ls.setConfiguration(new TestConfiguration());
ls.login("aaardvaark", "aaa", request);
}
@Test
public void testLoginServiceRoles () throws Exception
{
JAASLoginService ls = new JAASLoginService("foo");
//test that we always add in the DEFAULT ROLE CLASSNAME
ls.setRoleClassNames(new String[] {"arole", "brole"});
String[] roles = ls.getRoleClassNames();
assertEquals(3, roles.length);
assertEquals(JAASLoginService.DEFAULT_ROLE_CLASS_NAME, roles[2]);
ls.setRoleClassNames(new String[] {});
assertEquals(1, ls.getRoleClassNames().length);
assertEquals(JAASLoginService.DEFAULT_ROLE_CLASS_NAME, ls.getRoleClassNames()[0]);
ls.setRoleClassNames(null);
assertEquals(1, ls.getRoleClassNames().length);
assertEquals(JAASLoginService.DEFAULT_ROLE_CLASS_NAME, ls.getRoleClassNames()[0]);
//test a custom role class where some of the roles are subclasses of it
ls.setRoleClassNames(new String[] {TestRole.class.getName()});
Subject subject = new Subject();
subject.getPrincipals().add(new NotTestRole("w"));
subject.getPrincipals().add(new TestRole("x"));
subject.getPrincipals().add(new TestRole("y"));
subject.getPrincipals().add(new AnotherTestRole("z"));
String[] groups = ls.getGroups(subject);
assertEquals(3, groups.length);
for (String g:groups)
assertTrue(g.equals("x") || g.equals("y") || g.equals("z"));
//test a custom role class
ls.setRoleClassNames(new String[] {AnotherTestRole.class.getName()});
Subject subject2 = new Subject();
subject2.getPrincipals().add(new NotTestRole("w"));
subject2.getPrincipals().add(new TestRole("x"));
subject2.getPrincipals().add(new TestRole("y"));
subject2.getPrincipals().add(new AnotherTestRole("z"));
assertEquals(1, ls.getGroups(subject2).length);
assertEquals("z", ls.getGroups(subject2)[0]);
//test a custom role class that implements an interface
ls.setRoleClassNames(new String[] {SomeRole.class.getName()});
Subject subject3 = new Subject();
subject3.getPrincipals().add(new NotTestRole("w"));
subject3.getPrincipals().add(new TestRole("x"));
subject3.getPrincipals().add(new TestRole("y"));
subject3.getPrincipals().add(new AnotherTestRole("z"));
assertEquals(3, ls.getGroups(subject3).length);
for (String g:groups)
assertTrue(g.equals("x") || g.equals("y") || g.equals("z"));
//test a class that doesn't match
ls.setRoleClassNames(new String[] {NotTestRole.class.getName()});
Subject subject4 = new Subject();
subject4.getPrincipals().add(new TestRole("x"));
subject4.getPrincipals().add(new TestRole("y"));
subject4.getPrincipals().add(new AnotherTestRole("z"));
assertEquals(0, ls.getGroups(subject4).length);
}
}

View File

@ -0,0 +1,59 @@
//
// ========================================================================
// 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.jaas;
import static org.junit.Assert.assertNotNull;
import javax.security.auth.callback.Callback;
import javax.security.auth.login.LoginException;
import org.eclipse.jetty.jaas.callback.ServletRequestCallback;
import org.eclipse.jetty.jaas.spi.AbstractLoginModule;
import org.eclipse.jetty.jaas.spi.UserInfo;
import org.eclipse.jetty.util.ArrayUtil;
import org.eclipse.jetty.util.security.Password;
public class TestLoginModule extends AbstractLoginModule
{
public ServletRequestCallback _callback = new ServletRequestCallback();
@Override
public UserInfo getUserInfo(String username) throws Exception
{
return new UserInfo(username, new Password("aaa"));
}
@Override
public Callback[] configureCallbacks()
{
return ArrayUtil.addToArray(super.configureCallbacks(), _callback, Callback.class);
}
@Override
public boolean login() throws LoginException
{
boolean result = super.login();
assertNotNull(_callback.getRequest());
return result;
}
}

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-jaspi</artifactId>

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-jmx</artifactId>

View File

@ -148,7 +148,7 @@ public class ObjectMBean implements DynamicMBean
LOG.ignore(e);
if (ModelMBean.class.isAssignableFrom(mClass))
{
mbean = mClass.newInstance();
mbean = mClass.getDeclaredConstructor().newInstance();
((ModelMBean)mbean).setManagedResource(o, "objectReference");
}
}

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-jndi</artifactId>

View File

@ -187,7 +187,9 @@ public class ContextFactory implements ObjectFactory
Reference ref = (Reference)obj;
StringRefAddr parserAddr = (StringRefAddr)ref.get("parser");
String parserClassName = (parserAddr==null?null:(String)parserAddr.getContent());
NameParser parser = (NameParser)(parserClassName==null?null:loader.loadClass(parserClassName).newInstance());
NameParser parser =
(NameParser)(parserClassName==null?
null:loader.loadClass(parserClassName).getDeclaredConstructor().newInstance());
return new NamingContext (env,
name.get(0),

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-jspc-maven-plugin</artifactId>

View File

@ -1,5 +1,5 @@
<!-- ======================================================================== -->
<!-- Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. -->
<!-- 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 -->

View File

@ -2,7 +2,7 @@
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>9.4.10-SNAPSHOT</version>
<version>9.4.11-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-maven-plugin</artifactId>

View File

@ -0,0 +1 @@
invoker.goals = test -fae

Some files were not shown because too many files have changed in this diff Show More