Merge remote-tracking branch 'origin/jetty-12.0.x' into jetty-12.0.x-8426-aliaschecker-review

This commit is contained in:
Lachlan Roberts 2022-08-15 10:40:59 +10:00
commit 8e172f311e
1006 changed files with 6236 additions and 4182 deletions

14
Jenkinsfile vendored
View File

@ -155,6 +155,18 @@ pipeline {
}
}
}
stage("Javadocs") {
steps {
container('jetty-build') {
timeout(time: 120, unit: 'MINUTES') {
dir("${env.WORKSPACE}/buildy") {
mavenBuild("jdk17", "clean install -DskipTests", "maven3")
mavenBuild("jdk17", "javadoc:javadoc", "maven3")
}
}
}
}
}
}
}
}
@ -177,7 +189,7 @@ def mavenBuild(jdk, cmdline, mvnName) {
"MAVEN_OPTS=-Xms2g -Xmx4g -Djava.awt.headless=true"]) {
configFileProvider(
[configFile(fileId: 'oss-settings.xml', variable: 'GLOBAL_MVN_SETTINGS')]) {
sh "mvn --no-transfer-progress -s $GLOBAL_MVN_SETTINGS -Dmaven.repo.local=.repository -Pci -DexcludedGroups=\"external, large-disk-resource, stress, slow\" -V -B -e -Djetty.testtracker.log=true $cmdline"
sh "mvn -Dmaven.test.failure.ignore=true --no-transfer-progress -s $GLOBAL_MVN_SETTINGS -Dmaven.repo.local=.repository -Pci -DexcludedGroups=\"external, large-disk-resource, stress, slow\" -V -B -e -Djetty.testtracker.log=true $cmdline"
}
}
}

View File

@ -22,11 +22,22 @@ Webapp Example
--------------
```shell
$ mkdir base && cd base
$ java -jar $JETTY_HOME/start.jar --add-modules=http,deploy
$ java -jar $JETTY_HOME/start.jar --add-modules=http,ee10-deploy
$ cp ~/src/myproj/target/mywebapp.war webapps
$ java -jar $JETTY_HOME/start.jar
```
Multiple Versions Webapp Example
--------------------------------
```shell
$ mkdir base && cd base
$ java -jar $JETTY_HOME/start.jar --add-modules=http,ee10-deploy,ee8-deploy
$ cp ~/src/myproj/target/mywebapp10.war webapps
$ cp ~/src/myproj/target/mywebapp8.war webapps
$ echo environment: ee8 > webapps/mywebapp8.properties
$ java -jar $JETTY_HOME/start.jar
```
Embedded Example
----------------
```java

View File

@ -198,23 +198,23 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi-client</artifactId>
<artifactId>jetty-fcgi-client</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<artifactId>jetty-http2-server</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-http-client-transport</artifactId>
<artifactId>jetty-http2-client-transport</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-server</artifactId>
<artifactId>jetty-http3-server</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-http-client-transport</artifactId>
<artifactId>jetty-http3-client-transport</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>

View File

@ -31,7 +31,7 @@ The Maven artifact coordinates for the HTTP/2 client library are the following:
----
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-client</artifactId>
<artifactId>jetty-http2-client</artifactId>
<version>{version}</version>
</dependency>
----

View File

@ -31,7 +31,7 @@ The Maven artifact coordinates for the HTTP/3 client library are the following:
----
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-client</artifactId>
<artifactId>jetty-http3-client</artifactId>
<version>{version}</version>
</dependency>
----

View File

@ -29,7 +29,7 @@ The Maven artifact coordinates for the HTTP/2 client library are the following:
----
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<artifactId>jetty-http2-server</artifactId>
<version>{version}</version>
</dependency>
----

View File

@ -29,7 +29,7 @@ The Maven artifact coordinates for the HTTP/3 client library are the following:
----
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-server</artifactId>
<artifactId>jetty-http3-server</artifactId>
<version>{version}</version>
</dependency>
----

View File

@ -60,10 +60,10 @@ import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.http.ClientConnectionFactoryOverHTTP2;
import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2;
import org.eclipse.jetty.http2.client.transport.ClientConnectionFactoryOverHTTP2;
import org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2;
import org.eclipse.jetty.http3.client.HTTP3Client;
import org.eclipse.jetty.http3.client.http.HttpClientTransportOverHTTP3;
import org.eclipse.jetty.http3.client.transport.HttpClientTransportOverHTTP3;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.ClientConnector;

View File

@ -27,8 +27,8 @@ import org.eclipse.jetty.ee10.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.ee10.websocket.client.JettyUpgradeListener;
import org.eclipse.jetty.ee10.websocket.client.WebSocketClient;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.http.ClientConnectionFactoryOverHTTP2;
import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2;
import org.eclipse.jetty.http2.client.transport.ClientConnectionFactoryOverHTTP2;
import org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2;
import org.eclipse.jetty.util.component.LifeCycle;
@SuppressWarnings("unused")

View File

@ -36,9 +36,6 @@ import org.eclipse.jetty.util.thread.SerializedInvoker;
@SuppressWarnings("unused")
public class HandlerDocs
{
// TODO this class has been temporarily moved to jetty-core/jetty-demo
// move it back when documentation is re-enabled
public static class HelloHandler0 extends Handler.Abstract
{
@Override

View File

@ -135,17 +135,7 @@
<doctitle>Eclipse Jetty API Doc - v${project.version}</doctitle>
<windowtitle>Eclipse Jetty API Doc - v${project.version}</windowtitle>
<excludePackageNames>
org.eclipse.jetty.http3.client.http.internal;
org.eclipse.jetty.http3.client.internal;
org.eclipse.jetty.http3.internal;
org.eclipse.jetty.http3.internal.*;
org.eclipse.jetty.http3.qpack.internal;
org.eclipse.jetty.http3.qpack.internal.*;
org.eclipse.jetty.http3.server.internal;
org.eclipse.jetty.quic.common.internal;
org.eclipse.jetty.quic.quiche;
org.eclipse.jetty.quic.quiche.*;
org.eclipse.jetty.quic.server.internal;
org.eclipse.jetty.http3.client.transport.internal; org.eclipse.jetty.http3.client.internal; org.eclipse.jetty.http3.internal; org.eclipse.jetty.http3.internal.*; org.eclipse.jetty.http3.qpack.internal; org.eclipse.jetty.http3.qpack.internal.*; org.eclipse.jetty.http3.server.internal; org.eclipse.jetty.quic.common.internal; org.eclipse.jetty.quic.quiche; org.eclipse.jetty.quic.quiche.*; org.eclipse.jetty.quic.server.internal;
</excludePackageNames>
</configuration>
</execution>
@ -160,11 +150,6 @@
<artifactId>jetty-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-ant</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-client</artifactId>
@ -217,12 +202,12 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi-client</artifactId>
<artifactId>jetty-fcgi-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi-server</artifactId>
<artifactId>jetty-fcgi-server</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
@ -237,32 +222,32 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-client</artifactId>
<artifactId>jetty-http2-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-http-client-transport</artifactId>
<artifactId>jetty-http2-client-transport</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<artifactId>jetty-http2-server</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-client</artifactId>
<artifactId>jetty-http3-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-http-client-transport</artifactId>
<artifactId>jetty-http3-client-transport</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-server</artifactId>
<artifactId>jetty-http3-server</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
@ -297,12 +282,12 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.quic</groupId>
<artifactId>quic-client</artifactId>
<artifactId>jetty-quic-client</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.quic</groupId>
<artifactId>quic-server</artifactId>
<artifactId>jetty-quic-server</artifactId>
<scope>provided</scope>
</dependency>
<dependency>

View File

@ -117,12 +117,12 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi-client</artifactId>
<artifactId>jetty-fcgi-client</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi-server</artifactId>
<artifactId>jetty-fcgi-server</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
@ -149,52 +149,52 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-client</artifactId>
<artifactId>jetty-http2-client</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-common</artifactId>
<artifactId>jetty-http2-common</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-hpack</artifactId>
<artifactId>jetty-http2-hpack</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-http-client-transport</artifactId>
<artifactId>jetty-http2-client-transport</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<artifactId>jetty-http2-server</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-client</artifactId>
<artifactId>jetty-http3-client</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-common</artifactId>
<artifactId>jetty-http3-common</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-http-client-transport</artifactId>
<artifactId>jetty-http3-client-transport</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-qpack</artifactId>
<artifactId>jetty-http3-qpack</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-server</artifactId>
<artifactId>jetty-http3-server</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
@ -294,27 +294,27 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.quic</groupId>
<artifactId>quic-client</artifactId>
<artifactId>jetty-quic-client</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.quic</groupId>
<artifactId>quic-common</artifactId>
<artifactId>jetty-quic-common</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.quic</groupId>
<artifactId>quic-quiche-common</artifactId>
<artifactId>jetty-quic-quiche-common</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.quic</groupId>
<artifactId>quic-quiche-jna</artifactId>
<artifactId>jetty-quic-quiche-jna</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.quic</groupId>
<artifactId>quic-server</artifactId>
<artifactId>jetty-quic-server</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
@ -449,17 +449,17 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-core-common</artifactId>
<artifactId>jetty-websocket-core-common</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-core-client</artifactId>
<artifactId>jetty-websocket-core-client</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-core-server</artifactId>
<artifactId>jetty-websocket-core-server</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
@ -480,7 +480,7 @@
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.quic</groupId>
<artifactId>quic-quiche-foreign-incubator</artifactId>
<artifactId>jetty-quic-quiche-foreign-incubator</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
</dependencies>

View File

@ -30,7 +30,7 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-client</artifactId>
<artifactId>jetty-http2-client</artifactId>
<scope>test</scope>
</dependency>
<dependency>

View File

@ -38,7 +38,7 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<artifactId>jetty-http2-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
@ -53,12 +53,12 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-client</artifactId>
<artifactId>jetty-http2-client</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-http-client-transport</artifactId>
<artifactId>jetty-http2-client-transport</artifactId>
<scope>test</scope>
</dependency>

View File

@ -23,7 +23,7 @@ import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2;
import org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2;
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.server.Handler;

View File

@ -46,7 +46,7 @@
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-client</artifactId>
<artifactId>jetty-http2-client</artifactId>
<scope>test</scope>
</dependency>
<dependency>

View File

@ -60,7 +60,7 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<artifactId>jetty-http2-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>

View File

@ -97,12 +97,12 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi-client</artifactId>
<artifactId>jetty-fcgi-client</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi-server</artifactId>
<artifactId>jetty-fcgi-server</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
@ -129,52 +129,52 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-client</artifactId>
<artifactId>jetty-http2-client</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-common</artifactId>
<artifactId>jetty-http2-common</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-hpack</artifactId>
<artifactId>jetty-http2-hpack</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-http-client-transport</artifactId>
<artifactId>jetty-http2-client-transport</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<artifactId>jetty-http2-server</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-client</artifactId>
<artifactId>jetty-http3-client</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-common</artifactId>
<artifactId>jetty-http3-common</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-http-client-transport</artifactId>
<artifactId>jetty-http3-client-transport</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-qpack</artifactId>
<artifactId>jetty-http3-qpack</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http3</groupId>
<artifactId>http3-server</artifactId>
<artifactId>jetty-http3-server</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
@ -244,27 +244,27 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.quic</groupId>
<artifactId>quic-client</artifactId>
<artifactId>jetty-quic-client</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.quic</groupId>
<artifactId>quic-common</artifactId>
<artifactId>jetty-quic-common</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.quic</groupId>
<artifactId>quic-quiche-common</artifactId>
<artifactId>jetty-quic-quiche-common</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.quic</groupId>
<artifactId>quic-quiche-jna</artifactId>
<artifactId>jetty-quic-quiche-jna</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.quic</groupId>
<artifactId>quic-server</artifactId>
<artifactId>jetty-quic-server</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
@ -315,17 +315,17 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-core-common</artifactId>
<artifactId>jetty-websocket-core-common</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-core-client</artifactId>
<artifactId>jetty-websocket-core-client</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-core-server</artifactId>
<artifactId>jetty-websocket-core-server</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency>
@ -346,7 +346,7 @@
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.quic</groupId>
<artifactId>quic-quiche-foreign-incubator</artifactId>
<artifactId>jetty-quic-quiche-foreign-incubator</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
</dependencies>

View File

@ -51,24 +51,16 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
private final Callback requester;
private final Pool<Connection> pool;
private boolean maximizeConnections;
private volatile long maxDurationNanos = 0L;
private volatile long maxDurationNanos;
private volatile int maxUsage;
private volatile int initialMaxMultiplex;
protected AbstractConnectionPool(HttpDestination destination, int maxConnections, boolean cache, Callback requester)
{
this(destination, Pool.StrategyType.FIRST, maxConnections, cache, requester);
}
protected AbstractConnectionPool(HttpDestination destination, Pool.StrategyType strategy, int maxConnections, boolean cache, Callback requester)
{
this(destination, new Pool<>(strategy, maxConnections, cache), requester);
}
protected AbstractConnectionPool(HttpDestination destination, Pool<Connection> pool, Callback requester)
protected AbstractConnectionPool(HttpDestination destination, Pool<Connection> pool, Callback requester, int initialMaxMultiplex)
{
this.destination = destination;
this.requester = requester;
this.pool = pool;
pool.setMaxMultiplex(1); // Force the use of multiplexing.
this.initialMaxMultiplex = initialMaxMultiplex;
addBean(pool);
}
@ -101,14 +93,17 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
}
/**
* <p>Get the max usage duration in milliseconds of the pool's connections.
* Values {@code 0} and negative mean that there is no limit.</p>
* <p>This only guarantees that a connection cannot be acquired after the configured
* duration elapses, so that is only enforced when {@link #acquire(boolean)} is called.
* If a pool stays completely idle for a duration longer than the value
* <p>Returns the max usage duration in milliseconds of a pooled connection.</p>
* <p>Values {@code 0} and negative mean that there is no limit.</p>
* <p>This property only guarantees that a connection cannot be acquired
* after the configured duration elapses, so that is only enforced when
* {@link #acquire(boolean)} is called.</p>
* <p>If a pool stays completely idle for a duration longer than the value
* returned by this method, the max duration will not be enforced.
* It's up to the idle timeout mechanism (see {@link HttpClient#getIdleTimeout()})
* to handle closing idle connections.</p>
*
* @return the max usage duration, in milliseconds, of a pooled connection
*/
@ManagedAttribute(value = "The maximum duration in milliseconds a connection can be used for before it gets closed")
public long getMaxDuration()
@ -121,24 +116,31 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
this.maxDurationNanos = TimeUnit.MILLISECONDS.toNanos(maxDurationInMs);
}
protected int getMaxMultiplex()
protected int getInitialMaxMultiplex()
{
return pool.getMaxMultiplex();
return initialMaxMultiplex;
}
protected void setMaxMultiplex(int maxMultiplex)
protected void setInitialMaxMultiplex(int initialMaxMultiplex)
{
pool.setMaxMultiplex(maxMultiplex);
this.initialMaxMultiplex = initialMaxMultiplex;
}
protected int getMaxUsageCount()
/**
* <p>Returns the max number of times a pooled connection can be used.</p>
* <p>Values {@code 0} and negative mean that there is no limit.</p>
*
* @return the max number of times a pooled connection can be used
*/
@ManagedAttribute(value = "The maximum amount of times a connection is used before it gets closed")
public int getMaxUsage()
{
return pool.getMaxUsageCount();
return maxUsage;
}
protected void setMaxUsageCount(int maxUsageCount)
public void setMaxUsage(int maxUsage)
{
pool.setMaxUsageCount(maxUsageCount);
this.maxUsage = maxUsage;
}
@ManagedAttribute(value = "The number of active connections", readonly = true)
@ -235,7 +237,7 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
* <p>Whether a new connection is created is determined by the {@code create} parameter
* and a count of demand and supply, where the demand is derived from the number of
* queued requests, and the supply is the number of pending connections time the
* {@link #getMaxMultiplex()} factor: if the demand is less than the supply, the
* {@link #getInitialMaxMultiplex()} factor: if the demand is less than the supply, the
* connection will not be created.</p>
* <p>Since the number of queued requests used to derive the demand may be a stale
* value, it is possible that few more connections than strictly necessary may be
@ -250,7 +252,7 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
LOG.debug("Try creating connection {}/{} with {} pending", connectionCount, getMaxConnectionCount(), getPendingConnectionCount());
// If we have already pending sufficient multiplexed connections, then do not create another.
int multiplexed = getMaxMultiplex();
int multiplexed = getInitialMaxMultiplex();
while (true)
{
int pending = this.pending.get();
@ -288,14 +290,13 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
@Override
public boolean accept(Connection connection)
{
if (!(connection instanceof Attachable))
if (!(connection instanceof Attachable attachable))
throw new IllegalArgumentException("Invalid connection object: " + connection);
Pool<Connection>.Entry entry = pool.reserve();
if (entry == null)
return false;
if (LOG.isDebugEnabled())
LOG.debug("onCreating {} {}", entry, connection);
Attachable attachable = (Attachable)connection;
attachable.setAttachment(new EntryHolder(entry));
onCreated(connection);
entry.enable(connection, false);
@ -327,11 +328,29 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
if (canClose)
IO.close(connection);
if (LOG.isDebugEnabled())
LOG.debug("Connection removed{} due to expiration {} {}", (canClose ? " and closed" : ""), entry, pool);
LOG.debug("Connection removed{}: expired {} {}", (canClose ? " and closed" : ""), entry, pool);
continue;
}
}
int maxUsage = getMaxUsage();
if (connection instanceof MaxUsable maxUsable)
maxUsage = maxUsable.getMaxUsage();
if (maxUsage > 0)
{
EntryHolder holder = (EntryHolder)((Attachable)connection).getAttachment();
if (!holder.use(maxUsage))
{
boolean canClose = remove(connection);
if (canClose)
IO.close(connection);
if (LOG.isDebugEnabled())
LOG.debug("Connection removed{}: over used {} {}", (canClose ? " and closed" : ""), entry, pool);
continue;
}
// Entry is now used, so it must be acquired.
}
if (LOG.isDebugEnabled())
LOG.debug("Activated {} {}", entry, pool);
acquired(connection);
@ -344,9 +363,8 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
@Override
public boolean isActive(Connection connection)
{
if (!(connection instanceof Attachable))
if (!(connection instanceof Attachable attachable))
throw new IllegalArgumentException("Invalid connection object: " + connection);
Attachable attachable = (Attachable)connection;
EntryHolder holder = (EntryHolder)attachable.getAttachment();
if (holder == null)
return false;
@ -364,9 +382,8 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
protected boolean deactivate(Connection connection)
{
if (!(connection instanceof Attachable))
if (!(connection instanceof Attachable attachable))
throw new IllegalArgumentException("Invalid connection object: " + connection);
Attachable attachable = (Attachable)connection;
EntryHolder holder = (EntryHolder)attachable.getAttachment();
if (holder == null)
return true;
@ -377,28 +394,33 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
// Remove instead of release if the connection expired.
return !remove(connection);
}
else
int maxUsage = getMaxUsage();
if (connection instanceof MaxUsable maxUsable)
maxUsage = maxUsable.getMaxUsage();
if (maxUsage > 0 && holder.isOverUsed(maxUsage))
{
// Release if the connection has not expired, then remove if not reusable.
boolean reusable = pool.release(holder.entry);
if (LOG.isDebugEnabled())
LOG.debug("Released ({}) {} {}", reusable, holder.entry, pool);
if (reusable)
return true;
// Remove instead of release if the connection is overused.
return !remove(connection);
}
boolean reusable = holder.entry.release();
if (LOG.isDebugEnabled())
LOG.debug("Released ({}) {} {}", reusable, holder.entry, pool);
if (reusable)
return true;
return !remove(connection);
}
@Override
public boolean remove(Connection connection)
{
if (!(connection instanceof Attachable))
if (!(connection instanceof Attachable attachable))
throw new IllegalArgumentException("Invalid connection object: " + connection);
Attachable attachable = (Attachable)connection;
EntryHolder holder = (EntryHolder)attachable.getAttachment();
if (holder == null)
return false;
boolean removed = pool.remove(holder.entry);
boolean removed = holder.entry.remove();
if (removed)
attachable.setAttachment(null);
if (LOG.isDebugEnabled())
@ -411,12 +433,6 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
return removed;
}
@Deprecated
protected boolean remove(Connection connection, boolean force)
{
return remove(connection);
}
protected void onCreated(Connection connection)
{
}
@ -575,7 +591,8 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
private static class EntryHolder
{
private final Pool<Connection>.Entry entry;
private final long creationTimestamp = System.nanoTime();
private final long creationNanos = System.nanoTime();
private final AtomicInteger usage = new AtomicInteger();
private EntryHolder(Pool<Connection>.Entry entry)
{
@ -584,7 +601,24 @@ public abstract class AbstractConnectionPool extends ContainerLifeCycle implemen
private boolean isExpired(long timeoutNanos)
{
return System.nanoTime() - creationTimestamp >= timeoutNanos;
return System.nanoTime() - creationNanos >= timeoutNanos;
}
private boolean use(int maxUsage)
{
while (true)
{
int current = usage.get();
if (current >= maxUsage)
return false;
if (usage.compareAndSet(current, current + 1))
return true;
}
}
public boolean isOverUsed(int maxUsage)
{
return usage.get() >= maxUsage;
}
}
}

View File

@ -108,21 +108,12 @@ public interface ConnectionPool extends Closeable
/**
* Marks a connection as supporting multiplexed requests.
*/
interface Multiplexable
interface MaxMultiplexable
{
/**
* @return the max number of requests multiplexable on a single connection
*/
int getMaxMultiplex();
/**
* @param maxMultiplex the max number of requests multiplexable on a single connection
* @deprecated do not use, as the maxMultiplex value is pulled, rather than pushed
*/
@Deprecated
default void setMaxMultiplex(int maxMultiplex)
{
}
}
/**
@ -133,6 +124,6 @@ public interface ConnectionPool extends Closeable
/**
* @return the max number of requests on a single connection
*/
int getMaxUsageCount();
int getMaxUsage();
}
}

View File

@ -13,10 +13,8 @@
package org.eclipse.jetty.client;
import org.eclipse.jetty.client.api.Connection;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Pool;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
@ManagedObject
@ -24,30 +22,6 @@ public class DuplexConnectionPool extends AbstractConnectionPool
{
public DuplexConnectionPool(HttpDestination destination, int maxConnections, Callback requester)
{
this(destination, maxConnections, false, requester);
}
public DuplexConnectionPool(HttpDestination destination, int maxConnections, boolean cache, Callback requester)
{
super(destination, Pool.StrategyType.FIRST, maxConnections, cache, requester);
}
@Deprecated
public DuplexConnectionPool(HttpDestination destination, Pool<Connection> pool, Callback requester)
{
super(destination, pool, requester);
}
@Override
@ManagedAttribute(value = "The maximum amount of times a connection is used before it gets closed")
public int getMaxUsageCount()
{
return super.getMaxUsageCount();
}
@Override
public void setMaxUsageCount(int maxUsageCount)
{
super.setMaxUsageCount(maxUsageCount);
super(destination, new Pool<>(Pool.StrategyType.FIRST, maxConnections, false), requester, 1);
}
}

View File

@ -47,7 +47,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ManagedObject
public abstract class HttpDestination extends ContainerLifeCycle implements Destination, Closeable, Callback, Dumpable
public class HttpDestination extends ContainerLifeCycle implements Destination, Closeable, Callback, Dumpable
{
private static final Logger LOG = LoggerFactory.getLogger(HttpDestination.class);
@ -519,12 +519,6 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest
getConnectionPool());
}
@FunctionalInterface
public interface Multiplexed
{
void setMaxRequestsPerConnection(int maxRequestsPerConnection);
}
/**
* <p>Enforces the total timeout for for exchanges that are still in the queue.</p>
* <p>The total timeout for exchanges that are not in the destination queue

View File

@ -13,7 +13,6 @@
package org.eclipse.jetty.client;
import org.eclipse.jetty.client.api.Connection;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Pool;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
@ -22,71 +21,32 @@ import org.eclipse.jetty.util.annotation.ManagedObject;
@ManagedObject
public class MultiplexConnectionPool extends AbstractConnectionPool
{
public MultiplexConnectionPool(HttpDestination destination, int maxConnections, Callback requester, int maxMultiplex)
public MultiplexConnectionPool(HttpDestination destination, int maxConnections, Callback requester, int initialMaxMultiplex)
{
this(destination, maxConnections, false, requester, maxMultiplex);
this(destination, Pool.StrategyType.FIRST, maxConnections, false, requester, initialMaxMultiplex);
}
public MultiplexConnectionPool(HttpDestination destination, int maxConnections, boolean cache, Callback requester, int maxMultiplex)
protected MultiplexConnectionPool(HttpDestination destination, Pool.StrategyType strategy, int maxConnections, boolean cache, Callback requester, int initialMaxMultiplex)
{
this(destination, Pool.StrategyType.FIRST, maxConnections, cache, requester, maxMultiplex);
}
public MultiplexConnectionPool(HttpDestination destination, Pool.StrategyType strategy, int maxConnections, boolean cache, Callback requester, int maxMultiplex)
{
super(destination, new Pool<>(strategy, maxConnections, cache)
super(destination, new Pool<>(strategy, maxConnections, cache, connection ->
{
@Override
protected int getMaxUsageCount(Connection connection)
{
int maxUsage = (connection instanceof MaxUsable)
? ((MaxUsable)connection).getMaxUsageCount()
: super.getMaxUsageCount(connection);
return maxUsage > 0 ? maxUsage : -1;
}
@Override
protected int getMaxMultiplex(Connection connection)
{
int multiplex = (connection instanceof Multiplexable)
? ((Multiplexable)connection).getMaxMultiplex()
: super.getMaxMultiplex(connection);
return multiplex > 0 ? multiplex : 1;
}
}, requester);
setMaxMultiplex(maxMultiplex);
}
@Deprecated
public MultiplexConnectionPool(HttpDestination destination, Pool<Connection> pool, Callback requester, int maxMultiplex)
{
super(destination, pool, requester);
setMaxMultiplex(maxMultiplex);
int maxMultiplex = initialMaxMultiplex;
if (connection instanceof MaxMultiplexable maxMultiplexable)
maxMultiplex = maxMultiplexable.getMaxMultiplex();
return maxMultiplex;
}), requester, initialMaxMultiplex);
}
@Override
@ManagedAttribute(value = "The multiplexing factor of connections")
public int getMaxMultiplex()
@ManagedAttribute(value = "The initial multiplexing factor of connections")
public int getInitialMaxMultiplex()
{
return super.getMaxMultiplex();
return super.getInitialMaxMultiplex();
}
@Override
public void setMaxMultiplex(int maxMultiplex)
public void setInitialMaxMultiplex(int initialMaxMultiplex)
{
super.setMaxMultiplex(maxMultiplex);
}
@Override
@ManagedAttribute(value = "The maximum amount of times a connection is used before it gets closed")
public int getMaxUsageCount()
{
return super.getMaxUsageCount();
}
@Override
public void setMaxUsageCount(int maxUsageCount)
{
super.setMaxUsageCount(maxUsageCount);
super.setInitialMaxMultiplex(initialMaxMultiplex);
}
}

View File

@ -1,54 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.client;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
/**
* <p>A destination for those transports that are multiplex (e.g. HTTP/2).</p>
* <p>Transports that negotiate the protocol, and therefore do not know in advance
* whether they are duplex or multiplex, should use this class and when the
* cardinality is known call {@link #setMaxRequestsPerConnection(int)} with
* the proper cardinality.</p>
* <p>If the cardinality is {@code 1}, the behavior of this class is similar
* to that of {@link DuplexHttpDestination}.</p>
*/
public class MultiplexHttpDestination extends HttpDestination implements HttpDestination.Multiplexed
{
public MultiplexHttpDestination(HttpClient client, Origin origin)
{
this(client, origin, false);
}
public MultiplexHttpDestination(HttpClient client, Origin origin, boolean intrinsicallySecure)
{
super(client, origin, intrinsicallySecure);
}
@ManagedAttribute(value = "The maximum number of concurrent requests per connection")
public int getMaxRequestsPerConnection()
{
ConnectionPool connectionPool = getConnectionPool();
if (connectionPool instanceof AbstractConnectionPool)
return ((AbstractConnectionPool)connectionPool).getMaxMultiplex();
return 1;
}
public void setMaxRequestsPerConnection(int maxRequestsPerConnection)
{
ConnectionPool connectionPool = getConnectionPool();
if (connectionPool instanceof AbstractConnectionPool)
((AbstractConnectionPool)connectionPool).setMaxMultiplex(maxRequestsPerConnection);
}
}

View File

@ -61,7 +61,7 @@ public class ValidatingConnectionPool extends DuplexConnectionPool
public ValidatingConnectionPool(HttpDestination destination, int maxConnections, Callback requester, Scheduler scheduler, long timeout)
{
super((HttpDestination)destination, maxConnections, requester);
super(destination, maxConnections, requester);
this.scheduler = scheduler;
this.timeout = timeout;
this.quarantine = new ConcurrentHashMap<>(maxConnections);
@ -90,17 +90,12 @@ public class ValidatingConnectionPool extends DuplexConnectionPool
public boolean remove(Connection connection)
{
Holder holder = quarantine.remove(connection);
if (holder == null)
return super.remove(connection);
if (LOG.isDebugEnabled())
LOG.debug("Removed while validating {}", connection);
boolean cancelled = holder.cancel();
if (cancelled)
return remove(connection, true);
if (holder != null)
{
if (LOG.isDebugEnabled())
LOG.debug("Removed while validating {}", connection);
holder.cancel();
}
return super.remove(connection);
}

View File

@ -32,7 +32,6 @@ import org.eclipse.jetty.client.HttpClientTransport;
import org.eclipse.jetty.client.HttpDestination;
import org.eclipse.jetty.client.HttpRequest;
import org.eclipse.jetty.client.MultiplexConnectionPool;
import org.eclipse.jetty.client.MultiplexHttpDestination;
import org.eclipse.jetty.client.Origin;
import org.eclipse.jetty.client.http.HttpClientConnectionFactory;
import org.eclipse.jetty.http.HttpHeader;
@ -179,7 +178,7 @@ public class HttpClientTransportDynamic extends AbstractConnectorHttpClientTrans
public HttpDestination newHttpDestination(Origin origin)
{
SocketAddress address = origin.getAddress().getSocketAddress();
return new MultiplexHttpDestination(getHttpClient(), origin, getClientConnector().isIntrinsicallySecure(address));
return new HttpDestination(getHttpClient(), origin, getClientConnector().isIntrinsicallySecure(address));
}
@Override

View File

@ -20,7 +20,6 @@ import java.util.Map;
import org.eclipse.jetty.client.AbstractConnectorHttpClientTransport;
import org.eclipse.jetty.client.DuplexConnectionPool;
import org.eclipse.jetty.client.DuplexHttpDestination;
import org.eclipse.jetty.client.HttpDestination;
import org.eclipse.jetty.client.HttpRequest;
import org.eclipse.jetty.client.Origin;
@ -70,7 +69,7 @@ public class HttpClientTransportOverHTTP extends AbstractConnectorHttpClientTran
public HttpDestination newHttpDestination(Origin origin)
{
SocketAddress address = origin.getAddress().getSocketAddress();
return new DuplexHttpDestination(getHttpClient(), origin, getClientConnector().isIntrinsicallySecure(address));
return new HttpDestination(getHttpClient(), origin, getClientConnector().isIntrinsicallySecure(address));
}
@Override

View File

@ -0,0 +1,149 @@
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.client;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.component.LifeCycle;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
public class ConnectionPoolMaxUsageTest
{
private Server server;
private ServerConnector connector;
private HttpClient httpClient;
public void start(Handler handler) throws Exception
{
server = new Server();
connector = new ServerConnector(server, 1, 1);
server.addConnector(connector);
server.setHandler(handler);
server.start();
httpClient = new HttpClient();
httpClient.start();
}
@AfterEach
public void dispose()
{
LifeCycle.stop(httpClient);
LifeCycle.stop(server);
}
@Test
public void testMaxUsage() throws Exception
{
start(new Handler.Processor()
{
@Override
public void process(Request request, Response response, Callback callback)
{
response.getHeaders().put(HttpHeader.CONTENT_TYPE, "text/plain");
Content.Sink.write(response, true, String.valueOf(Request.getRemotePort(request)), callback);
}
});
String host = "localhost";
int port = connector.getLocalPort();
HttpDestination destination = httpClient.resolveDestination(new Origin("http", host, port, null, HttpClientTransportOverHTTP.HTTP11));
AbstractConnectionPool connectionPool = (AbstractConnectionPool)destination.getConnectionPool();
int maxUsage = 3;
connectionPool.setMaxUsage(maxUsage);
Set<String> clientPorts = new HashSet<>();
for (int i = 0; i < maxUsage; ++i)
{
ContentResponse response = httpClient.newRequest(host, port)
.timeout(5, TimeUnit.SECONDS)
.send();
assertEquals(HttpStatus.OK_200, response.getStatus());
int expected = i == maxUsage - 1 ? 0 : 1;
assertEquals(expected, connectionPool.getConnectionCount());
clientPorts.add(response.getContentAsString());
}
assertEquals(1, clientPorts.size());
// Make one more request, it must open a new connection.
ContentResponse response = httpClient.newRequest(host, port)
.timeout(5, TimeUnit.SECONDS)
.send();
assertEquals(HttpStatus.OK_200, response.getStatus());
assertEquals(1, connectionPool.getConnectionCount());
assertNotEquals(clientPorts.iterator().next(), response.getContentAsString());
}
@Test
public void testMaxUsageSetToSmallerValue() throws Exception
{
start(new Handler.Processor()
{
@Override
public void process(Request request, Response response, Callback callback)
{
response.getHeaders().put(HttpHeader.CONTENT_TYPE, "text/plain");
Content.Sink.write(response, true, String.valueOf(Request.getRemotePort(request)), callback);
}
});
String host = "localhost";
int port = connector.getLocalPort();
HttpDestination destination = httpClient.resolveDestination(new Origin("http", host, port, null, HttpClientTransportOverHTTP.HTTP11));
AbstractConnectionPool connectionPool = (AbstractConnectionPool)destination.getConnectionPool();
int maxUsage = 3;
connectionPool.setMaxUsage(maxUsage);
// Make a number of requests smaller than maxUsage.
Set<String> clientPorts = new HashSet<>();
for (int i = 0; i < maxUsage - 1; ++i)
{
ContentResponse response = httpClient.newRequest(host, port)
.timeout(5, TimeUnit.SECONDS)
.send();
assertEquals(HttpStatus.OK_200, response.getStatus());
assertEquals(1, connectionPool.getConnectionCount());
clientPorts.add(response.getContentAsString());
}
assertEquals(1, clientPorts.size());
// Set maxUsage to a smaller value.
connectionPool.setMaxUsage(1);
// Make one more request, it must open a new connection.
ContentResponse response = httpClient.newRequest(host, port)
.timeout(5, TimeUnit.SECONDS)
.send();
assertEquals(HttpStatus.OK_200, response.getStatus());
assertEquals(0, connectionPool.getConnectionCount());
assertNotEquals(clientPorts.iterator().next(), response.getContentAsString());
}
}

View File

@ -585,11 +585,11 @@ public class ConnectionPoolTest
{
startServer(new EmptyServerHandler());
int maxUsageCount = 2;
int maxUsage = 2;
startClient(destination ->
{
AbstractConnectionPool connectionPool = (AbstractConnectionPool)factory.factory.newConnectionPool(destination);
connectionPool.setMaxUsageCount(maxUsageCount);
connectionPool.setMaxUsage(maxUsage);
connectionPool.setMaxDuration(0); // Disable max duration expiry as it may expire the connection between the 1st and 2nd request.
return connectionPool;
});

View File

@ -46,7 +46,7 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
{
start(scenario, new EmptyServerHandler());
try (HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", connector.getLocalPort())))
try (HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false))
{
destination.start();
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
@ -66,7 +66,7 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
{
start(scenario, new EmptyServerHandler());
try (HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", connector.getLocalPort())))
try (HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false))
{
destination.start();
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
@ -90,7 +90,7 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
{
start(scenario, new EmptyServerHandler());
try (HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", connector.getLocalPort())))
try (HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false))
{
destination.start();
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
@ -119,7 +119,7 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
CountDownLatch idleLatch = new CountDownLatch(1);
CountDownLatch latch = new CountDownLatch(1);
try (HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()))
try (HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false)
{
@Override
protected ConnectionPool newConnectionPool(HttpClient client)
@ -181,7 +181,7 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
{
start(scenario, new EmptyServerHandler());
try (HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", connector.getLocalPort())))
try (HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false))
{
destination.start();
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();
@ -218,7 +218,7 @@ public class DuplexHttpDestinationTest extends AbstractHttpClientServerTest
long idleTimeout = 1000;
startClient(scenario, httpClient -> httpClient.setIdleTimeout(idleTimeout));
try (HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", connector.getLocalPort())))
try (HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", connector.getLocalPort()), false))
{
destination.start();
DuplexConnectionPool connectionPool = (DuplexConnectionPool)destination.getConnectionPool();

View File

@ -95,7 +95,7 @@ public class HttpClientIdleTimeoutTest
@Override
public HttpDestination newHttpDestination(Origin origin)
{
return new DuplexHttpDestination(getHttpClient(), origin)
return new HttpDestination(getHttpClient(), origin, false)
{
@Override
protected SendFailure send(IConnection connection, HttpExchange exchange)

View File

@ -21,7 +21,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Stream;
import org.eclipse.jetty.client.DuplexHttpDestination;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpDestination;
import org.eclipse.jetty.client.HttpExchange;
@ -74,7 +73,7 @@ public class HttpReceiverOverHTTPTest
client = new HttpClient();
client.setHttpCompliance(compliance);
client.start();
destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
destination = new HttpDestination(client, new Origin("http", "localhost", 8080), false);
destination.start();
endPoint = new ByteArrayEndPoint();
connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<>());

View File

@ -20,7 +20,6 @@ import java.util.Locale;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.DuplexHttpDestination;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpDestination;
import org.eclipse.jetty.client.Origin;
@ -61,7 +60,7 @@ public class HttpSenderOverHTTPTest
public void testSendNoRequestContent() throws Exception
{
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", 8080), false);
destination.start();
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
Request request = client.newRequest(URI.create("http://localhost/"));
@ -94,7 +93,7 @@ public class HttpSenderOverHTTPTest
public void testSendNoRequestContentIncompleteFlush() throws Exception
{
ByteArrayEndPoint endPoint = new ByteArrayEndPoint("", 16);
HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", 8080), false);
destination.start();
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
Request request = client.newRequest(URI.create("http://localhost/"));
@ -124,7 +123,7 @@ public class HttpSenderOverHTTPTest
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
// Shutdown output to trigger the exception on write
endPoint.shutdownOutput();
HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", 8080), false);
destination.start();
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
Request request = client.newRequest(URI.create("http://localhost/"));
@ -154,7 +153,7 @@ public class HttpSenderOverHTTPTest
public void testSendNoRequestContentIncompleteFlushException() throws Exception
{
ByteArrayEndPoint endPoint = new ByteArrayEndPoint("", 16);
HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", 8080), false);
destination.start();
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
Request request = client.newRequest(URI.create("http://localhost/"));
@ -190,7 +189,7 @@ public class HttpSenderOverHTTPTest
public void testSendSmallRequestContentInOneBuffer() throws Exception
{
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", 8080), false);
destination.start();
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
Request request = client.newRequest(URI.create("http://localhost/"));
@ -225,7 +224,7 @@ public class HttpSenderOverHTTPTest
public void testSendSmallRequestContentInTwoBuffers() throws Exception
{
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", 8080), false);
destination.start();
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
Request request = client.newRequest(URI.create("http://localhost/"));
@ -261,7 +260,7 @@ public class HttpSenderOverHTTPTest
public void testSendSmallRequestContentChunkedInTwoChunks() throws Exception
{
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
HttpDestination destination = new DuplexHttpDestination(client, new Origin("http", "localhost", 8080));
HttpDestination destination = new HttpDestination(client, new Origin("http", "localhost", 8080), false);
destination.start();
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, destination, new Promise.Adapter<Connection>());
Request request = client.newRequest(URI.create("http://localhost/"));

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
<!-- ==================================================================
Configure and deploy the test web application
===================================================================== -->
<Configure id="coreDemo" class="org.eclipse.jetty.server.handler.ContextHandler">
<Set name="handler">
<New class="org.eclipse.jetty.core.demo.HandlerDocs$RootHandler">
<Call name="addHandler"><Arg><New class="org.eclipse.jetty.core.demo.HandlerDocs$HelloHandler0"/></Arg></Call>
<Call name="addHandler"><Arg><New class="org.eclipse.jetty.core.demo.HandlerDocs$HelloHandler1"/></Arg></Call>
<Call name="addHandler"><Arg><New class="org.eclipse.jetty.core.demo.HandlerDocs$HelloHandler2"/></Arg></Call>
<Call name="addHandler"><Arg><New class="org.eclipse.jetty.core.demo.HandlerDocs$HelloHandler3"/></Arg></Call>
<Call name="addHandler"><Arg><New class="org.eclipse.jetty.core.demo.HandlerDocs$HelloHandler4"/></Arg></Call>
<Call name="addHandler"><Arg><New class="org.eclipse.jetty.core.demo.HandlerDocs$HelloHandler5"/></Arg></Call>
<Call name="addHandler"><Arg><New class="org.eclipse.jetty.core.demo.HandlerDocs$EchoHandler"/></Arg></Call>
</New>
</Set>
</Configure>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
<Configure id="helloDemo" class="org.eclipse.jetty.server.handler.ContextHandler">
<Set name="handler">
<New class="org.eclipse.jetty.demo.HelloHandler" />
</Set>
</Configure>

View File

@ -1,208 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.core.demo;
import java.io.IOException;
import java.io.PrintStream;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.Flow;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Blocker;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.thread.SerializedInvoker;
public class HandlerDocs
{
public static class HelloHandler0 extends Handler.Abstract
{
@Override
public Request.Processor handle(Request request) throws Exception
{
return (req, response, callback) ->
{
response.setStatus(200);
response.getHeaders().add(HttpHeader.CONTENT_TYPE, "text/plain");
response.write(true, BufferUtil.toBuffer("Hello World\n"), callback);
};
}
}
public static class HelloHandler1 extends Handler.Abstract
{
@Override
public Request.Processor handle(Request request) throws Exception
{
return this::process;
}
private void process(Request request, Response response, Callback callback)
{
response.setStatus(200);
response.getHeaders().add(HttpHeader.CONTENT_TYPE, "text/plain");
Content.Sink.write(response, true, "Hello World", callback);
}
}
public static class HelloHandler2 extends Handler.Processor.NonBlocking
{
@Override
public void process(Request request, Response response, Callback callback)
{
response.setStatus(200);
response.getHeaders().add(HttpHeader.CONTENT_TYPE, "text/plain");
response.write(true, BufferUtil.toBuffer("Hello World\n"), callback);
}
}
public static class HelloHandler3 extends Handler.Processor.Blocking
{
@Override
public void process(Request request, Response response, Callback callback) throws IOException
{
response.setStatus(200);
response.getHeaders().add(HttpHeader.CONTENT_TYPE, "text/plain");
try (Blocker.Callback blocker = Blocker.callback())
{
response.write(false, BufferUtil.toBuffer("Hello "), blocker);
blocker.block();
}
Content.Sink.write(response, true, BufferUtil.toBuffer("World\n"));
callback.succeeded();
}
}
public static class HelloHandler4 extends Handler.Processor.Blocking
{
@Override
public void process(Request request, Response response, Callback callback) throws IOException
{
response.setStatus(200);
response.getHeaders().add(HttpHeader.CONTENT_TYPE, "text/plain");
try (PrintStream out = new PrintStream(Content.Sink.asOutputStream(response)))
{
out.print("Hello ");
out.println("World");
callback.succeeded();
}
catch (Throwable t)
{
callback.failed(t);
}
}
}
public static class HelloHandler5 extends Handler.Processor.NonBlocking
{
@Override
public void process(Request request, Response response, Callback callback) throws IOException
{
response.setStatus(200);
response.getHeaders().add(HttpHeader.CONTENT_TYPE, "text/plain");
new HelloWorldPublisher().subscribe(Content.Sink.asSubscriber(response, callback));
}
}
public static class HelloWorldPublisher implements Flow.Publisher<Content.Chunk>
{
@Override
public void subscribe(Flow.Subscriber<? super Content.Chunk> subscriber)
{
final SerializedInvoker invoker = new SerializedInvoker();
final Queue<Content.Chunk> chunks = new LinkedList<>(List.of(
Content.Chunk.from(BufferUtil.toBuffer("Hello "), false),
Content.Chunk.from(BufferUtil.toBuffer("World "), false),
Content.Chunk.EOF));
subscriber.onSubscribe(new Flow.Subscription()
{
@Override
public void request(long n)
{
while (n-- > 0 && !chunks.isEmpty())
invoker.run(() -> subscriber.onNext(chunks.poll()));
}
@Override
public void cancel()
{
subscriber.onNext(Content.Chunk.from(new IOException("Cancelled")));
}
});
}
}
public static class EchoHandler extends Handler.Processor.NonBlocking
{
@Override
public void process(Request request, Response response, Callback callback)
{
response.setStatus(200);
response.getHeaders().put(HttpHeader.CONTENT_TYPE, request.getHeaders().get(HttpHeader.CONTENT_TYPE));
long contentLength = request.getHeaders().getLongField(HttpHeader.CONTENT_LENGTH);
if (contentLength >= 0)
response.getHeaders().putLongField(HttpHeader.CONTENT_LENGTH, contentLength);
Content.copy(request, response, callback);
}
}
public static class RootHandler extends Handler.Collection
{
@Override
public Request.Processor handle(Request request) throws Exception
{
final StringBuilder index = new StringBuilder();
index.append("<h2>Handler Demos</h2>\n<ul>\n");
for (Handler handler : getHandlers())
{
String name = handler.getClass().getSimpleName().replace("Handler", "");
String path = "/" + name;
if (request.getPathInContext().equals(path))
{
Request.Processor processor = handler.handle(request);
if (processor != null)
return processor;
}
index.append("<li><a href=\"")
.append(URIUtil.addPaths(request.getContext().getContextPath(), path))
.append("\">")
.append(name)
.append("</a></li>\n");
}
index.append("</ul>");
return (req, res, callback) ->
{
res.setStatus(200);
res.getHeaders().add(HttpHeader.CONTENT_TYPE, MimeTypes.Type.TEXT_HTML_UTF_8.asString());
Content.Sink.write(res, true, index.toString(), callback);
};
}
}
}

View File

@ -11,22 +11,23 @@
// ========================================================================
//
package org.eclipse.jetty.client;
package org.eclipse.jetty.demo;
/**
* <p>A destination for those network transports that are duplex (e.g. HTTP/1.1 and FastCGI).</p>
*
* @see MultiplexHttpDestination
*/
public class DuplexHttpDestination extends HttpDestination
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.BufferUtil;
public class HelloHandler extends Handler.Abstract
{
public DuplexHttpDestination(HttpClient client, Origin origin)
@Override
public Request.Processor handle(Request req)
{
this(client, origin, false);
}
public DuplexHttpDestination(HttpClient client, Origin origin, boolean intrinsicallySecure)
{
super(client, origin, intrinsicallySecure);
return (request, response, callback) ->
{
response.setStatus(200);
response.getHeaders().add(HttpHeader.CONTENT_TYPE, "text/plain");
response.write(true, BufferUtil.toBuffer("Hello World\n"), callback);
};
}
}

View File

@ -2,12 +2,12 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi</artifactId>
<artifactId>jetty-fcgi</artifactId>
<version>12.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fcgi-client</artifactId>
<artifactId>jetty-fcgi-client</artifactId>
<name>Jetty Core :: FastCGI :: Client</name>
<properties>

View File

@ -13,12 +13,12 @@
package org.eclipse.jetty.fcgi.client.http;
import java.net.SocketAddress;
import java.util.List;
import java.util.Map;
import org.eclipse.jetty.client.AbstractConnectorHttpClientTransport;
import org.eclipse.jetty.client.DuplexConnectionPool;
import org.eclipse.jetty.client.DuplexHttpDestination;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpDestination;
import org.eclipse.jetty.client.HttpRequest;
@ -81,7 +81,8 @@ public class HttpClientTransportOverFCGI extends AbstractConnectorHttpClientTran
@Override
public HttpDestination newHttpDestination(Origin origin)
{
return new DuplexHttpDestination(getHttpClient(), origin);
SocketAddress address = origin.getAddress().getSocketAddress();
return new HttpDestination(getHttpClient(), origin, getClientConnector().isIntrinsicallySecure(address));
}
@Override

View File

@ -2,12 +2,12 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi</artifactId>
<artifactId>jetty-fcgi</artifactId>
<version>12.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fcgi-server</artifactId>
<artifactId>jetty-fcgi-server</artifactId>
<name>Jetty Core :: FastCGI :: Server</name>
<properties>
@ -26,7 +26,7 @@
</dependency>-->
<dependency>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi-client</artifactId>
<artifactId>jetty-fcgi-client</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
@ -39,7 +39,7 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
<artifactId>jetty-http2-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>

View File

@ -8,13 +8,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi</artifactId>
<artifactId>jetty-fcgi</artifactId>
<packaging>pom</packaging>
<name>Jetty Core :: FastCGI :: Parent</name>
<name>Jetty Core :: FastCGI</name>
<modules>
<module>fcgi-client</module>
<module>fcgi-server</module>
<module>jetty-fcgi-client</module>
<module>jetty-fcgi-server</module>
</modules>
<dependencies>

View File

@ -18,12 +18,13 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.util.VirtualThreads;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.thread.ThreadPool;
import org.eclipse.jetty.util.thread.TryExecutor;
public class DelegatingThreadPool extends ContainerLifeCycle implements ThreadPool, TryExecutor
public class DelegatingThreadPool extends ContainerLifeCycle implements ThreadPool, TryExecutor, VirtualThreads.Configurable
{
private Executor _executor; // memory barrier provided by start/stop semantics
private TryExecutor _tryExecutor;
@ -61,6 +62,19 @@ public class DelegatingThreadPool extends ContainerLifeCycle implements ThreadPo
return _tryExecutor.tryExecute(task);
}
@Override
public boolean isUseVirtualThreads()
{
return VirtualThreads.isUseVirtualThreads(_executor);
}
@Override
public void setUseVirtualThreads(boolean useVirtualThreads)
{
if (_executor instanceof VirtualThreads.Configurable)
((VirtualThreads.Configurable)_executor).setUseVirtualThreads(useVirtualThreads);
}
@Override
public int getIdleThreads()
{

View File

@ -13,8 +13,12 @@
package org.eclipse.jetty.http;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.util.Attributes;
@ -76,7 +80,7 @@ public class HttpCookie
private final int _version;
private final boolean _httpOnly;
private final long _expiration;
private final SameSite _sameSite;
private final Map<String, String> _attributes;
public HttpCookie(String name, String value)
{
@ -100,10 +104,16 @@ public class HttpCookie
public HttpCookie(String name, String value, String domain, String path, long maxAge, boolean httpOnly, boolean secure, String comment, int version)
{
this(name, value, domain, path, maxAge, httpOnly, secure, comment, version, null);
this(name, value, domain, path, maxAge, httpOnly, secure, comment, version, (SameSite)null);
}
public HttpCookie(String name, String value, String domain, String path, long maxAge, boolean httpOnly, boolean secure, String comment, int version, SameSite sameSite)
{
this(name, value, domain, path, maxAge, httpOnly, secure, comment, version, Collections.singletonMap("SameSite", sameSite == null ? null : sameSite.getAttributeValue()));
}
public HttpCookie(String name, String value, String domain, String path, long maxAge, boolean httpOnly, boolean secure, String comment, int version, Map<String, String> attributes)
{
_name = name;
_value = value;
@ -115,29 +125,26 @@ public class HttpCookie
_comment = comment;
_version = version;
_expiration = maxAge < 0 ? -1 : System.nanoTime() + TimeUnit.SECONDS.toNanos(maxAge);
_sameSite = sameSite;
_attributes = (attributes == null ? Collections.emptyMap() : attributes);
}
public HttpCookie(String setCookie)
public HttpCookie(String name, String value, int version, Map<String, String> attributes)
{
List<java.net.HttpCookie> cookies = java.net.HttpCookie.parse(setCookie);
if (cookies.size() != 1)
throw new IllegalStateException();
_name = name;
_value = value;
_version = version;
_attributes = (attributes == null ? Collections.emptyMap() : new TreeMap<>(attributes));
//remove all of the well-known attributes, leaving only those pass-through ones
_domain = _attributes.remove("Domain");
_path = _attributes.remove("Path");
java.net.HttpCookie cookie = cookies.get(0);
_name = cookie.getName();
_value = cookie.getValue();
_domain = cookie.getDomain();
_path = cookie.getPath();
_maxAge = cookie.getMaxAge();
_httpOnly = cookie.isHttpOnly();
_secure = cookie.getSecure();
_comment = cookie.getComment();
_version = cookie.getVersion();
String tmp = _attributes.remove("Max-Age");
_maxAge = StringUtil.isBlank(tmp) ? -1L : Long.valueOf(tmp);
_expiration = _maxAge < 0 ? -1 : System.nanoTime() + TimeUnit.SECONDS.toNanos(_maxAge);
// support for SameSite values has not yet been added to java.net.HttpCookie
_sameSite = getSameSiteFromComment(cookie.getComment());
_httpOnly = Boolean.parseBoolean(_attributes.remove("HttpOnly"));
_secure = Boolean.parseBoolean(_attributes.remove("Secure"));
_comment = _attributes.remove("Comment");
}
/**
@ -209,7 +216,10 @@ public class HttpCookie
*/
public SameSite getSameSite()
{
return _sameSite;
String val = _attributes.get("SameSite");
if (val == null)
return null;
return SameSite.valueOf(val.toUpperCase(Locale.ENGLISH));
}
/**
@ -421,12 +431,21 @@ public class HttpCookie
buf.append("; Secure");
if (_httpOnly)
buf.append("; HttpOnly");
if (_sameSite != null)
String sameSite = _attributes.get("SameSite");
if (sameSite != null)
{
buf.append("; SameSite=");
buf.append(_sameSite.getAttributeValue());
buf.append(sameSite);
}
//Add all other attributes
_attributes.entrySet().stream().filter(e -> !"SameSite".equals(e.getKey())).forEach(e ->
{
buf.append("; " + e.getKey() + "=");
buf.append(e.getValue());
});
return buf.toString();
}
@ -491,6 +510,109 @@ public class HttpCookie
throw new IllegalStateException(e);
}
}
/**
* Extract the bare minimum of info from a Set-Cookie header string.
*
* Ideally this method should not be necessary, however as java.net.HttpCookie
* does not yet support generic attributes, we have to use it in a minimal
* fashion. When it supports attributes, we could look at reverting to a
* constructor on o.e.j.h.HttpCookie to take the set-cookie header string.
*
* @param setCookieHeader the header as a string
* @return a map containing the name, value, domain, path. max-age of the set cookie header
*/
public static Map<String, String> extractBasics(String setCookieHeader)
{
//Parse the bare minimum
List<java.net.HttpCookie> cookies = java.net.HttpCookie.parse(setCookieHeader);
if (cookies.size() != 1)
return Collections.emptyMap();
java.net.HttpCookie cookie = cookies.get(0);
Map<String, String> fields = new HashMap<>();
fields.put("name", cookie.getName());
fields.put("value", cookie.getValue());
fields.put("domain", cookie.getDomain());
fields.put("path", cookie.getPath());
fields.put("max-age", Long.toString(cookie.getMaxAge()));
return fields;
}
/**
* Check if the Set-Cookie header represented as a string is for the name, domain and path given.
*
* @param setCookieHeader a Set-Cookie header
* @param name the cookie name to check
* @param domain the cookie domain to check
* @param path the cookie path to check
* @return true if all of the name, domain and path match the Set-Cookie header, false otherwise
*/
public static boolean match(String setCookieHeader, String name, String domain, String path)
{
//Parse the bare minimum
List<java.net.HttpCookie> cookies = java.net.HttpCookie.parse(setCookieHeader);
if (cookies.size() != 1)
return false;
java.net.HttpCookie cookie = cookies.get(0);
return match(cookie.getName(), cookie.getDomain(), cookie.getPath(), name, domain, path);
}
/**
* Check if the HttpCookie is for the given name, domain and path.
*
* @param cookie the jetty HttpCookie to check
* @param name the cookie name to check
* @param domain the cookie domain to check
* @param path the cookie path to check
* @return true if all of the name, domain and path all match the HttpCookie, false otherwise
*/
public static boolean match(HttpCookie cookie, String name, String domain, String path)
{
if (cookie == null)
return false;
return match(cookie.getName(), cookie.getDomain(), cookie.getPath(), name, domain, path);
}
/**
* Check if all old parameters match the new parameters.
*
* @param oldName
* @param oldDomain
* @param oldPath
* @param newName
* @param newDomain
* @param newPath
* @return true if old and new names match exactly and the old and new domains match case-insensitively and the paths match exactly
*/
private static boolean match(String oldName, String oldDomain, String oldPath, String newName, String newDomain, String newPath)
{
if (oldName == null)
{
if (newName != null)
return false;
}
else if (!oldName.equals(newName))
return false;
if (oldDomain == null)
{
if (newDomain != null)
return false;
}
else if (!oldDomain.equalsIgnoreCase(newDomain))
return false;
if (oldPath == null)
{
if (newPath != null)
return false;
}
else if (!oldPath.equals(newPath))
return false;
return true;
}
/**
* @deprecated We should not need to do this now
@ -563,7 +685,7 @@ public class HttpCookie
return _cookie;
}
}
/**
* Check that samesite is set on the cookie. If not, use a
* context default value, if one has been set.

View File

@ -13,6 +13,7 @@
package org.eclipse.jetty.http;
import java.util.Collections;
import java.util.stream.Stream;
import org.eclipse.jetty.http.HttpCookie.SameSite;
@ -64,9 +65,28 @@ public class HttpCookieTest
}
@Test
public void testConstructFromSetCookie()
public void testMatchCookie()
{
HttpCookie cookie = new HttpCookie("everything=value; Path=path; Domain=domain; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly");
//match with header string
assertTrue(HttpCookie.match("everything=value; Path=path; Domain=domain; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly; SameSite=Lax; Foo=Bar",
"everything", "domain", "path"));
assertFalse(HttpCookie.match("everything=value; Path=path; Domain=domain; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly; SameSite=Lax; Foo=Bar",
"something", "domain", "path"));
assertFalse(HttpCookie.match("everything=value; Path=path; Domain=domain; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly; SameSite=Lax; Foo=Bar",
"everything", "realm", "path"));
assertFalse(HttpCookie.match("everything=value; Path=path; Domain=domain; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly; SameSite=Lax; Foo=Bar",
"everything", "domain", "street"));
//match including set-cookie:, this is really testing the java.net.HttpCookie parser, but worth throwing in there
assertTrue(HttpCookie.match("Set-Cookie: everything=value; Path=path; Domain=domain; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly; SameSite=Lax; Foo=Bar",
"everything", "domain", "path"));
//match via cookie
HttpCookie httpCookie = new HttpCookie("everything", "value", "domain", "path", 0, true, true, "comment", 0);
assertTrue(HttpCookie.match(httpCookie, "everything", "domain", "path"));
assertFalse(HttpCookie.match(httpCookie, "something", "domain", "path"));
assertFalse(HttpCookie.match(httpCookie, "everything", "realm", "path"));
assertFalse(HttpCookie.match(httpCookie, "everything", "domain", "street"));
}
@Test
@ -131,6 +151,9 @@ public class HttpCookieTest
httpCookie = new HttpCookie("everything", "value", "domain", "path", 0, true, true, null, -1, HttpCookie.SameSite.STRICT);
assertEquals("everything=value; Path=path; Domain=domain; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly; SameSite=Strict", httpCookie.getRFC6265SetCookie());
httpCookie = new HttpCookie("everything", "value", "domain", "path", 0, true, true, null, -1, Collections.singletonMap("SameSite", "None"));
assertEquals("everything=value; Path=path; Domain=domain; Expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Secure; HttpOnly; SameSite=None", httpCookie.getRFC6265SetCookie());
}
public static Stream<String> rfc6265BadNameSource()

View File

@ -2,13 +2,13 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2</artifactId>
<artifactId>jetty-http2</artifactId>
<version>12.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>http2-http-client-transport</artifactId>
<name>Jetty Core :: HTTP2 :: HTTP Client Transport</name>
<artifactId>jetty-http2-client-transport</artifactId>
<name>Jetty Core :: HTTP2 :: Client Transport</name>
<properties>
<bundle-symbolic-name>${project.groupId}.client.http</bundle-symbolic-name>
@ -21,7 +21,7 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-client</artifactId>
<artifactId>jetty-http2-client</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>

View File

@ -19,5 +19,5 @@ module org.eclipse.jetty.http2.http.client.transport
requires transitive org.eclipse.jetty.client;
requires transitive org.eclipse.jetty.http2.client;
exports org.eclipse.jetty.http2.client.http;
exports org.eclipse.jetty.http2.client.transport;
}

View File

@ -11,7 +11,7 @@
// ========================================================================
//
package org.eclipse.jetty.http2.client.http;
package org.eclipse.jetty.http2.client.transport;
import java.io.IOException;
import java.io.UncheckedIOException;
@ -25,8 +25,8 @@ import org.eclipse.jetty.client.dynamic.HttpClientTransportDynamic;
import org.eclipse.jetty.client.http.HttpClientConnectionFactory;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.HTTP2ClientConnectionFactory;
import org.eclipse.jetty.http2.client.http.internal.HTTPSessionListenerPromise;
import org.eclipse.jetty.http2.client.http.internal.HttpConnectionOverHTTP2;
import org.eclipse.jetty.http2.client.transport.internal.HTTPSessionListenerPromise;
import org.eclipse.jetty.http2.client.transport.internal.HttpConnectionOverHTTP2;
import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.ssl.SslClientConnectionFactory;

View File

@ -11,7 +11,7 @@
// ========================================================================
//
package org.eclipse.jetty.http2.client.http;
package org.eclipse.jetty.http2.client.transport;
import java.io.IOException;
import java.net.InetSocketAddress;
@ -26,15 +26,14 @@ import org.eclipse.jetty.client.HttpConnection;
import org.eclipse.jetty.client.HttpDestination;
import org.eclipse.jetty.client.HttpRequest;
import org.eclipse.jetty.client.MultiplexConnectionPool;
import org.eclipse.jetty.client.MultiplexHttpDestination;
import org.eclipse.jetty.client.Origin;
import org.eclipse.jetty.client.ProxyConfiguration;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.HTTP2ClientConnectionFactory;
import org.eclipse.jetty.http2.client.http.internal.HTTPSessionListenerPromise;
import org.eclipse.jetty.http2.client.http.internal.HttpConnectionOverHTTP2;
import org.eclipse.jetty.http2.client.transport.internal.HTTPSessionListenerPromise;
import org.eclipse.jetty.http2.client.transport.internal.HttpConnectionOverHTTP2;
import org.eclipse.jetty.http2.frames.GoAwayFrame;
import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.EndPoint;
@ -56,7 +55,7 @@ public class HttpClientTransportOverHTTP2 extends AbstractHttpClientTransport
setConnectionPoolFactory(destination ->
{
HttpClient httpClient = getHttpClient();
return new MultiplexConnectionPool(destination, httpClient.getMaxConnectionsPerDestination(), destination, httpClient.getMaxRequestsQueuedPerDestination());
return new MultiplexConnectionPool(destination, httpClient.getMaxConnectionsPerDestination(), destination, 1);
});
}
@ -121,7 +120,7 @@ public class HttpClientTransportOverHTTP2 extends AbstractHttpClientTransport
public HttpDestination newHttpDestination(Origin origin)
{
SocketAddress address = origin.getAddress().getSocketAddress();
return new MultiplexHttpDestination(getHttpClient(), origin, getHTTP2Client().getClientConnector().isIntrinsicallySecure(address));
return new HttpDestination(getHttpClient(), origin, getHTTP2Client().getClientConnector().isIntrinsicallySecure(address));
}
@Override

View File

@ -11,7 +11,7 @@
// ========================================================================
//
package org.eclipse.jetty.http2.client.http.internal;
package org.eclipse.jetty.http2.client.transport.internal;
import org.eclipse.jetty.http2.internal.HTTP2Channel;
import org.eclipse.jetty.http2.internal.HTTP2Stream;

View File

@ -11,7 +11,7 @@
// ========================================================================
//
package org.eclipse.jetty.http2.client.http.internal;
package org.eclipse.jetty.http2.client.transport.internal;
import java.nio.channels.ClosedChannelException;
import java.util.Map;

View File

@ -11,7 +11,7 @@
// ========================================================================
//
package org.eclipse.jetty.http2.client.http.internal;
package org.eclipse.jetty.http2.client.transport.internal;
import org.eclipse.jetty.client.HttpChannel;
import org.eclipse.jetty.client.HttpDestination;

View File

@ -11,7 +11,7 @@
// ========================================================================
//
package org.eclipse.jetty.http2.client.http.internal;
package org.eclipse.jetty.http2.client.transport.internal;
import java.nio.channels.AsynchronousCloseException;
import java.util.Iterator;
@ -46,7 +46,7 @@ import org.eclipse.jetty.util.thread.Sweeper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HttpConnectionOverHTTP2 extends HttpConnection implements Sweeper.Sweepable, ConnectionPool.Multiplexable
public class HttpConnectionOverHTTP2 extends HttpConnection implements Sweeper.Sweepable, ConnectionPool.MaxMultiplexable
{
private static final Logger LOG = LoggerFactory.getLogger(HttpConnectionOverHTTP2.class);

View File

@ -11,7 +11,7 @@
// ========================================================================
//
package org.eclipse.jetty.http2.client.http.internal;
package org.eclipse.jetty.http2.client.transport.internal;
import java.io.IOException;
import java.nio.ByteBuffer;

View File

@ -11,7 +11,7 @@
// ========================================================================
//
package org.eclipse.jetty.http2.client.http.internal;
package org.eclipse.jetty.http2.client.transport.internal;
import java.nio.ByteBuffer;
import java.util.function.Supplier;

View File

@ -2,12 +2,12 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2</artifactId>
<artifactId>jetty-http2</artifactId>
<version>12.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>http2-client</artifactId>
<artifactId>jetty-http2-client</artifactId>
<name>Jetty Core :: HTTP2 :: Client</name>
<properties>
@ -31,7 +31,7 @@
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-common</artifactId>
<artifactId>jetty-http2-common</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>

View File

@ -2,12 +2,12 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2</artifactId>
<artifactId>jetty-http2</artifactId>
<version>12.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>http2-common</artifactId>
<artifactId>jetty-http2-common</artifactId>
<name>Jetty Core :: HTTP2 :: Common</name>
<properties>
@ -17,7 +17,7 @@
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-hpack</artifactId>
<artifactId>jetty-http2-hpack</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>

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