diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index d61a2c061cc7..1fc19f4958ec 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,5 +1,5 @@
blank_issues_enabled: true
contact_links:
- name: Jetty Security Reports
- url: https://eclipse.dev/jetty/security_reports.php
+ url: https://jetty.org/security.html
about: Please raise security issues here.
diff --git a/.github/ISSUE_TEMPLATE/issue-template.md b/.github/ISSUE_TEMPLATE/issue-template.md
index bded56c38831..5515ded1dc2f 100644
--- a/.github/ISSUE_TEMPLATE/issue-template.md
+++ b/.github/ISSUE_TEMPLATE/issue-template.md
@@ -18,7 +18,7 @@ labels: Bug
**OS type/version**
**Description**
-
+
**How to reproduce?**
diff --git a/.github/ISSUE_TEMPLATE/release-template.md b/.github/ISSUE_TEMPLATE/release-template.md
index a6751fecdbd7..b0aace9b047d 100644
--- a/.github/ISSUE_TEMPLATE/release-template.md
+++ b/.github/ISSUE_TEMPLATE/release-template.md
@@ -56,7 +56,7 @@ This release process will produce releases:
- [ ] Merge release branches back to main branches and delete release branches.
- [ ] Verify release existence in Maven Central by triggering the Jenkins builds of CometD.
- [ ] Update Jetty versions on the website ( follow instructions in [jetty-website](https://github.com/eclipse/jetty-website/blob/master/README.md) ).
- + [ ] Update (or check) [Download](https://eclipse.dev/jetty/download.php) page is updated.
+ + [ ] Update (or check) [Download](https://jetty.org/download.html) page is updated.
+ [ ] Update (or check) documentation page(s) are updated.
- [ ] Publish GitHub Releases.
- [ ] Prepare release announcement for mailing lists.
diff --git a/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/ArchitectureDocs.java b/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/ArchitectureDocs.java
index 721372f5c247..5edfd89fbf58 100644
--- a/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/ArchitectureDocs.java
+++ b/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/ArchitectureDocs.java
@@ -17,17 +17,29 @@
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
+import org.eclipse.jetty.util.thread.VirtualThreadPool;
@SuppressWarnings("unused")
public class ArchitectureDocs
{
- public void configureVirtualThreads()
+ public void queuedVirtualThreads()
{
- // tag::virtual[]
+ // tag::queuedVirtual[]
QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.setVirtualThreadsExecutor(Executors.newVirtualThreadPerTaskExecutor());
Server server = new Server(threadPool);
- // end::virtual[]
+ // end::queuedVirtual[]
+ }
+
+ public void virtualVirtualThreads()
+ {
+ // tag::virtualVirtual[]
+ VirtualThreadPool threadPool = new VirtualThreadPool();
+ // Limit the max number of current virtual threads.
+ threadPool.setMaxThreads(200);
+
+ Server server = new Server(threadPool);
+ // end::virtualVirtual[]
}
}
diff --git a/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java b/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java
index 031cd030220f..693e23aa4895 100644
--- a/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java
+++ b/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java
@@ -1049,6 +1049,31 @@ public void setConnectionPool() throws Exception
// end::setConnectionPool[]
}
+ public void preCreateConnections() throws Exception
+ {
+ // tag::preCreateConnections[]
+ HttpClient httpClient = new HttpClient();
+ httpClient.start();
+
+ // For HTTP/1.1, you need to explicitly configure to initialize connections.
+ if (httpClient.getTransport() instanceof HttpClientTransportOverHTTP http1)
+ http1.setInitializeConnections(true);
+
+ // Create a dummy request to the server you want to pre-create connections to.
+ Request request = httpClient.newRequest("https://host/");
+
+ // Resolve the destination for that request.
+ Destination destination = httpClient.resolveDestination(request);
+
+ // Pre-create, for example, half of the connections.
+ int preCreate = httpClient.getMaxConnectionsPerDestination() / 2;
+ CompletableFuture completable = destination.getConnectionPool().preCreateConnections(preCreate);
+
+ // Wait for the connections to be created.
+ completable.get(5, TimeUnit.SECONDS);
+ // end::preCreateConnections[]
+ }
+
public void unixDomain() throws Exception
{
// tag::unixDomain[]
diff --git a/documentation/jetty/modules/operations-guide/pages/modules/standard.adoc b/documentation/jetty/modules/operations-guide/pages/modules/standard.adoc
index 41b475fd1e44..d3992234c719 100644
--- a/documentation/jetty/modules/operations-guide/pages/modules/standard.adoc
+++ b/documentation/jetty/modules/operations-guide/pages/modules/standard.adoc
@@ -708,6 +708,34 @@ If you want to use virtual threads, introduced as a preview feature in Java 19 a
See also the xref:server/index.adoc#threadpool[section about configuring the thread pool].
+[[threadpool-all-virtual]]
+== Module `threadpool-all-virtual`
+
+The `threadpool-all-virtual` module allows you to configure the server-wide thread pool, similarly to what you can do with the <> Jetty module, so that all threads are virtual threads, introduced as an official feature since Java 21.
+
+CAUTION: Only use this module if you are using Java 21 or later.
+If you are using Java 19 or Java 20, use the <> Jetty module instead.
+
+The module properties to configure the thread pool are:
+
+----
+include::{jetty-home}/modules/threadpool-all-virtual.mod[tags=documentation]
+----
+
+The property `jetty.threadpool.maxThreads` limits, using a `Semaphore`, the number of current virtual threads in use.
+
+Limiting the number of current virtual threads helps to limit resource usage in applications, especially in case of load spikes.
+When an unlimited number of virtual threads is allowed, the server might be brought down due to resource (typically memory) exhaustion.
+
+[CAUTION]
+====
+Even when using virtual threads, Jetty uses non-blocking I/O, and dedicates a thread to each `java.nio.channels.Selector` to perform the `Selector.select()` operation.
+
+Currently (up to Java 22), calling `Selector.select()` from a virtual thread pins the carrier thread.
+
+When using the `threadpool-all-virtual` Jetty module, if you have `N` selectors, then `N` carrier threads will be pinned by the virtual threads calling `Selector.select()`, possibly making your system less efficient, and at worst locking up the entire system if there are no carrier threads available to run virtual threads.
+====
+
[[threadpool-virtual]]
== Module `threadpool-virtual`
diff --git a/documentation/jetty/modules/operations-guide/pages/server/index.adoc b/documentation/jetty/modules/operations-guide/pages/server/index.adoc
index f147d11d4013..00c66b05489a 100644
--- a/documentation/jetty/modules/operations-guide/pages/server/index.adoc
+++ b/documentation/jetty/modules/operations-guide/pages/server/index.adoc
@@ -328,32 +328,30 @@ Virtual threads have been introduced as a preview feature in Java 19 and Java 20
The xref:modules/standard.adoc#threadpool-virtual-preview[`threadpool-virtual-preview`] Jetty module provides support for virtual threads in Java 19 and Java 20, and it is mutually exclusive with the `threadpool` Jetty module.
-The xref:modules/standard.adoc#threadpool-virtual[`threadpool-virtual`] Jetty module provides support for virtual threads in Java 21 or later, and it is mutually exclusive with the `threadpool` Jetty module.
+When using Java 21, there are two Jetty modules available:
+
+* xref:modules/standard.adoc#threadpool-virtual[`threadpool-virtual`]
+* xref:modules/standard.adoc#threadpool-all-virtual[`threadpool-all-virtual`]
+
+Both are mutually exclusive with the `threadpool` Jetty module.
If you have already enabled the `threadpool` Jetty module, it is sufficient to remove it by removing the `$JETTY_BASE/start.d/threadpool.ini` file.
-When using Java 21 or later, you can enable the xref:modules/standard.adoc#threadpool-virtual[`threadpool-virtual`] module:
+The xref:modules/standard.adoc#threadpool-virtual[`threadpool-virtual`] Jetty module provides a mixed thread mode, where platform threads are used to run internal Jetty tasks, but application code is invoked using virtual threads.
+
+The xref:modules/standard.adoc#threadpool-all-virtual[`threadpool-all-virtual`] Jetty module provides a thread mode where all threads are virtual threads, including those used internally by Jetty.
+
+You can enable either module using:
----
$ java -jar $JETTY_HOME/start.jar --add-modules=threadpool-virtual,http
----
-After the command above, the `$JETTY_BASE` directory looks like this:
+or
-[source]
----
-$JETTY_BASE
-├── resources
-│ └── jetty-logging.properties
-└── start.d
- ├── http.ini
- └── threadpool-virtual.ini
+$ java -jar $JETTY_HOME/start.jar --add-modules=threadpool-all-virtual,http
----
-Now you can customize the `threadpool-virtual.ini` file to explicitly configure the thread pool and the virtual threads and then start Jetty:
-
-[jetty%nowrap]
-....
-[jetty]
-setupArgs=--add-modules=threadpool-virtual,http
-....
+After the command above, the `$JETTY_BASE/start.d/` directory will contain the corresponding `threadpool-virtual.ini` or `threadpool-all-virtual.ini` file.
+You can now explicitly configure the thread pool module properties inside the `+*.ini+` file and then start Jetty.
diff --git a/documentation/jetty/modules/programming-guide/pages/arch/threads.adoc b/documentation/jetty/modules/programming-guide/pages/arch/threads.adoc
index e8b7016643e0..1fb7dff1d2b7 100644
--- a/documentation/jetty/modules/programming-guide/pages/arch/threads.adoc
+++ b/documentation/jetty/modules/programming-guide/pages/arch/threads.adoc
@@ -235,11 +235,14 @@ Virtual threads have been introduced in Java 19 and Java 20 as a preview feature
NOTE: In Java versions where virtual threads are a preview feature, remember to add `+--enable-preview+` to the JVM command line options to use virtual threads.
+[[thread-pool-virtual-threads-queued]]
+==== Virtual Threads Support with `QueuedThreadPool`
+
`QueuedThreadPool` can be configured to use virtual threads by specifying the virtual threads `Executor`:
[,java,indent=0]
----
-include::code:example$src/main/java/org/eclipse/jetty/docs/programming/ArchitectureDocs.java[tags=virtual]
+include::code:example$src/main/java/org/eclipse/jetty/docs/programming/ArchitectureDocs.java[tags=queuedVirtual]
----
[CAUTION]
@@ -255,3 +258,17 @@ Enabling virtual threads in `QueuedThreadPool` will default the number of reserv
Defaulting the number of reserved threads to zero ensures that the <> is always used, which means that virtual threads will always be used for blocking tasks.
====
+
+[[thread-pool-virtual-threads-virtual]]
+==== Virtual Threads Support with `VirtualThreadPool`
+
+`VirtualThreadPool` is an alternative to `QueuedThreadPool` that creates only virtual threads (no platform threads).
+
+[,java,indent=0]
+----
+include::code:example$src/main/java/org/eclipse/jetty/docs/programming/ArchitectureDocs.java[tags=virtualVirtual]
+----
+
+Despite the name, `VirtualThreadPool` does not pool virtual threads, but allows you to impose a limit on the maximum number of current virtual threads, in order to limit resource consumption.
+
+Furthermore, you can configure it to track virtual threads so that a xref:troubleshooting/component-dump.adoc[Jetty component dump] will show all virtual threads, including those that are unmounted.
diff --git a/documentation/jetty/modules/programming-guide/pages/client/http.adoc b/documentation/jetty/modules/programming-guide/pages/client/http.adoc
index bb145a15fc9a..38fef9c2f889 100644
--- a/documentation/jetty/modules/programming-guide/pages/client/http.adoc
+++ b/documentation/jetty/modules/programming-guide/pages/client/http.adoc
@@ -158,7 +158,7 @@ Jetty's client library provides the following `ConnectionPool` implementations:
* `DuplexConnectionPool`, historically the first implementation, only used by the HTTP/1.1 transport.
* `MultiplexConnectionPool`, the generic implementation valid for any transport where connections are reused with a most recently used algorithm (that is, the connections most recently returned to the connection pool are the more likely to be used again).
* `RoundRobinConnectionPool`, similar to `MultiplexConnectionPool` but where connections are reused with a round-robin algorithm.
-* `RandomRobinConnectionPool`, similar to `MultiplexConnectionPool` but where connections are reused with an algorithm that chooses them randomly.
+* `RandomConnectionPool`, similar to `MultiplexConnectionPool` but where connections are reused with an algorithm that chooses them randomly.
The `ConnectionPool` implementation can be customized for each destination in by setting a `ConnectionPool.Factory` on the `HttpClientTransport`:
@@ -167,6 +167,34 @@ The `ConnectionPool` implementation can be customized for each destination in by
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java[tags=setConnectionPool]
----
+[[connection-pool-precreate-connections]]
+=== Pre-Creating Connections
+
+`ConnectionPool` offers the ability to pre-create connections by calling `ConnectionPool.preCreateConnections(int)`.
+
+Pre-creating the connections saves the time and processing spent to establish the TCP connection, performing the TLS handshake (if necessary) and, for HTTP/2 and HTTP/3, perform the initial protocol setup.
+This is particularly important for HTTP/2 because in the initial protocol setup the server informs the client of the maximum number of concurrent requests per connection (otherwise assumed to be just `1` by the client).
+
+The scenarios where pre-creating connections is useful are, for example:
+
+* Load testing, where you want to prepare the system with connections already created to avoid paying of cost of connection setup.
+* Proxying scenarios, often in conjunction with the use of `RoundRobinConnectionPool` or `RandomConnectionPool`, where the proxy creates early the connections to the backend servers.
+
+This is an example of how to pre-create connections:
+
+[,java,indent=0]
+----
+include::code:example$src/main/java/org/eclipse/jetty/docs/programming/client/http/HTTPClientDocs.java[tags=preCreateConnections]
+----
+
+[NOTE]
+====
+Pre-creating connections for secure HTTP/1.1 requires you to call `HttpClientTransportOverHTTP.setInitializeConnections(true)`, otherwise only the TCP connection is established, but the TLS handshake is not initiated.
+
+To initialize connections for secure HTTP/1.1, the client sends an initial `OPTIONS * HTTP/1.1` request to the server.
+The server must be able to handle this request without closing the connection (in particular it must not add the `Connection: close` header in the response).
+====
+
[[request-processing]]
== HttpClient Request Processing
diff --git a/jetty-core/jetty-alpn/jetty-alpn-server/src/main/config/etc/jetty-alpn.xml b/jetty-core/jetty-alpn/jetty-alpn-server/src/main/config/etc/jetty-alpn.xml
index b1cb065aff66..a5a49056c59e 100644
--- a/jetty-core/jetty-alpn/jetty-alpn-server/src/main/config/etc/jetty-alpn.xml
+++ b/jetty-core/jetty-alpn/jetty-alpn-server/src/main/config/etc/jetty-alpn.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-core/jetty-client/src/main/config/modules/client.mod b/jetty-core/jetty-client/src/main/config/modules/client.mod
index 1287200826d3..c1dfd8bb6856 100644
--- a/jetty-core/jetty-client/src/main/config/modules/client.mod
+++ b/jetty-core/jetty-client/src/main/config/modules/client.mod
@@ -1,8 +1,12 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
-Adds the Jetty HTTP client to the server classpath.
+Adds the Jetty HTTP client dependencies to the server classpath.
+
+[tags]
+client
[lib]
-lib/jetty-client-${jetty.version}.jar
lib/jetty-alpn-client-${jetty.version}.jar
+lib/jetty-alpn-java-client-${jetty.version}.jar
+lib/jetty-client-${jetty.version}.jar
diff --git a/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/transport/HttpClientConnectionFactory.java b/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/transport/HttpClientConnectionFactory.java
index c5e9f081a857..e33503fe3f49 100644
--- a/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/transport/HttpClientConnectionFactory.java
+++ b/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/transport/HttpClientConnectionFactory.java
@@ -26,20 +26,49 @@ public class HttpClientConnectionFactory implements ClientConnectionFactory
/**
* Representation of the {@code HTTP/1.1} application protocol used by {@link HttpClientTransportDynamic}.
*/
- public static final Info HTTP11 = new HTTP11(new HttpClientConnectionFactory());
+ public static final Info HTTP11 = new HTTP11();
+
+ private boolean initializeConnections;
+
+ /**
+ * @return whether newly created connections should be initialized with an {@code OPTIONS * HTTP/1.1} request
+ */
+ public boolean isInitializeConnections()
+ {
+ return initializeConnections;
+ }
+
+ /**
+ * @param initialize whether newly created connections should be initialized with an {@code OPTIONS * HTTP/1.1} request
+ */
+ public void setInitializeConnections(boolean initialize)
+ {
+ this.initializeConnections = initialize;
+ }
@Override
public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map context)
{
HttpConnectionOverHTTP connection = new HttpConnectionOverHTTP(endPoint, context);
+ connection.setInitialize(isInitializeConnections());
return customize(connection, context);
}
- private static class HTTP11 extends Info
+ /**
+ * Representation of the {@code HTTP/1.1} application protocol used by {@link HttpClientTransportDynamic}.
+ * Applications should prefer using the constant {@link HttpClientConnectionFactory#HTTP11}, unless they
+ * need to customize the associated {@link HttpClientConnectionFactory}.
+ */
+ public static class HTTP11 extends Info
{
private static final List protocols = List.of("http/1.1");
- private HTTP11(ClientConnectionFactory factory)
+ public HTTP11()
+ {
+ this(new HttpClientConnectionFactory());
+ }
+
+ public HTTP11(ClientConnectionFactory factory)
{
super(factory);
}
diff --git a/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/transport/HttpClientTransportOverHTTP.java b/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/transport/HttpClientTransportOverHTTP.java
index bab51d75dcaf..2ed1ad5fba6e 100644
--- a/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/transport/HttpClientTransportOverHTTP.java
+++ b/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/transport/HttpClientTransportOverHTTP.java
@@ -22,7 +22,6 @@
import org.eclipse.jetty.client.DuplexConnectionPool;
import org.eclipse.jetty.client.Origin;
import org.eclipse.jetty.client.Request;
-import org.eclipse.jetty.io.ClientConnectionFactory;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.ProcessorUtils;
@@ -37,7 +36,7 @@ public class HttpClientTransportOverHTTP extends AbstractConnectorHttpClientTran
public static final Origin.Protocol HTTP11 = new Origin.Protocol(List.of("http/1.1"), false);
private static final Logger LOG = LoggerFactory.getLogger(HttpClientTransportOverHTTP.class);
- private final ClientConnectionFactory factory = new HttpClientConnectionFactory();
+ private final HttpClientConnectionFactory factory = new HttpClientConnectionFactory();
private int headerCacheSize = 1024;
private boolean headerCacheCaseSensitive;
@@ -79,25 +78,54 @@ public org.eclipse.jetty.io.Connection newConnection(EndPoint endPoint, Map context)
{
@@ -159,12 +162,46 @@ public SendFailure send(HttpExchange exchange)
return delegate.send(exchange);
}
+ /**
+ * @return whether to initialize the connection with an {@code OPTIONS * HTTP/1.1} request.
+ */
+ public boolean isInitialize()
+ {
+ return initialize;
+ }
+
+ /**
+ * @param initialize whether to initialize the connection with an {@code OPTIONS * HTTP/1.1} request.
+ */
+ public void setInitialize(boolean initialize)
+ {
+ this.initialize = initialize;
+ }
+
@Override
public void onOpen()
{
super.onOpen();
fillInterested();
- promise.succeeded(this);
+ boolean initialize = isInitialize();
+ if (initialize)
+ {
+ Destination destination = getHttpDestination();
+ Request request = destination.getHttpClient().newRequest(destination.getOrigin().asString())
+ .method(HttpMethod.OPTIONS)
+ .path("*");
+ send(request, result ->
+ {
+ if (result.isSucceeded())
+ promise.succeeded(this);
+ else
+ promise.failed(result.getFailure());
+ });
+ }
+ else
+ {
+ promise.succeeded(this);
+ }
}
@Override
diff --git a/jetty-core/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionPoolTest.java b/jetty-core/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionPoolTest.java
index e03b46f293c4..7e62ae170a4c 100644
--- a/jetty-core/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionPoolTest.java
+++ b/jetty-core/jetty-client/src/test/java/org/eclipse/jetty/client/ConnectionPoolTest.java
@@ -703,7 +703,7 @@ public void testCountersSweepToStringThroughLifecycle(ConnectionPoolFactory fact
assertThat(connectionPool.toString(), not(nullValue()));
}
- private static class ConnectionPoolFactory
+ public static class ConnectionPoolFactory
{
private final String name;
private final ConnectionPool.Factory factory;
diff --git a/jetty-core/jetty-demos/jetty-demo-handler/src/main/config/modules/demo-handler.mod b/jetty-core/jetty-demos/jetty-demo-handler/src/main/config/modules/demo-handler.mod
index 966de59a45ef..302b633a34c9 100644
--- a/jetty-core/jetty-demos/jetty-demo-handler/src/main/config/modules/demo-handler.mod
+++ b/jetty-core/jetty-demos/jetty-demo-handler/src/main/config/modules/demo-handler.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Demo Handler
diff --git a/jetty-core/jetty-demos/jetty-demo-handler/src/main/config/modules/demo.d/demo-handler.xml b/jetty-core/jetty-demos/jetty-demo-handler/src/main/config/modules/demo.d/demo-handler.xml
index f3cef898b6d6..0f0f7c07521d 100644
--- a/jetty-core/jetty-demos/jetty-demo-handler/src/main/config/modules/demo.d/demo-handler.xml
+++ b/jetty-core/jetty-demos/jetty-demo-handler/src/main/config/modules/demo.d/demo-handler.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-core/jetty-deploy/src/main/config/etc/jetty-core-deploy.xml b/jetty-core/jetty-deploy/src/main/config/etc/jetty-core-deploy.xml
index 551fcc99b9aa..e4d6b0c4acad 100644
--- a/jetty-core/jetty-deploy/src/main/config/etc/jetty-core-deploy.xml
+++ b/jetty-core/jetty-deploy/src/main/config/etc/jetty-core-deploy.xml
@@ -1,4 +1,4 @@
-
+
diff --git a/jetty-core/jetty-deploy/src/main/config/etc/jetty-deploy.xml b/jetty-core/jetty-deploy/src/main/config/etc/jetty-deploy.xml
index 2ed9f8182d6b..02d9dc902096 100644
--- a/jetty-core/jetty-deploy/src/main/config/etc/jetty-deploy.xml
+++ b/jetty-core/jetty-deploy/src/main/config/etc/jetty-deploy.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java b/jetty-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java
index 37e7f7f6ff19..f68a8fa353af 100644
--- a/jetty-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java
+++ b/jetty-core/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/providers/ContextProvider.java
@@ -385,6 +385,10 @@ public ContextHandler createContextHandler(final App app) throws Exception
// Handle a context XML file
if (FileID.isXml(path))
{
+ ClassLoader coreContextClassLoader = Environment.CORE.equals(environment) ? findCoreContextClassLoader(path) : null;
+ if (coreContextClassLoader != null)
+ Thread.currentThread().setContextClassLoader(coreContextClassLoader);
+
context = applyXml(context, path, env, properties);
// Look for the contextHandler itself
@@ -401,13 +405,11 @@ else if (context instanceof Supplier> supplier)
throw new IllegalStateException("Unknown context type of " + context);
// Set the classloader if we have a coreContextClassLoader
- ClassLoader coreContextClassLoader = Environment.CORE.equals(environment) ? findCoreContextClassLoader(path) : null;
if (coreContextClassLoader != null)
contextHandler.setClassLoader(coreContextClassLoader);
return contextHandler;
}
-
// Otherwise it must be a directory or an archive
else if (!Files.isDirectory(path) && !FileID.isWebArchive(path))
{
diff --git a/jetty-core/jetty-deploy/src/test/resources/etc/core-context.xml b/jetty-core/jetty-deploy/src/test/resources/etc/core-context.xml
index 1eb453c75991..cccca5c2950c 100644
--- a/jetty-core/jetty-deploy/src/test/resources/etc/core-context.xml
+++ b/jetty-core/jetty-deploy/src/test/resources/etc/core-context.xml
@@ -12,7 +12,7 @@
-
+
/global
diff --git a/jetty-core/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml b/jetty-core/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml
index 7d4899bd9072..0b3431bd2225 100644
--- a/jetty-core/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml
+++ b/jetty-core/jetty-deploy/src/test/resources/jetty-deploymgr-contexts.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-core/jetty-deploy/src/test/resources/jetty-http.xml b/jetty-core/jetty-deploy/src/test/resources/jetty-http.xml
index aec2b1b98918..8ee14df91ae9 100644
--- a/jetty-core/jetty-deploy/src/test/resources/jetty-http.xml
+++ b/jetty-core/jetty-deploy/src/test/resources/jetty-http.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-core/jetty-deploy/src/test/resources/jetty.xml b/jetty-core/jetty-deploy/src/test/resources/jetty.xml
index e477b2820c7e..849410ab404a 100644
--- a/jetty-core/jetty-deploy/src/test/resources/jetty.xml
+++ b/jetty-core/jetty-deploy/src/test/resources/jetty.xml
@@ -1,9 +1,9 @@
-
+
-
+
diff --git a/jetty-core/jetty-deploy/src/test/resources/webapps/badapp/badapp.xml b/jetty-core/jetty-deploy/src/test/resources/webapps/badapp/badapp.xml
index 16e071f40ab8..a3ce9058a677 100644
--- a/jetty-core/jetty-deploy/src/test/resources/webapps/badapp/badapp.xml
+++ b/jetty-core/jetty-deploy/src/test/resources/webapps/badapp/badapp.xml
@@ -1,5 +1,5 @@
-
+
/badapp
diff --git a/jetty-core/jetty-deploy/src/test/resources/webapps/bar-core-context-alt.xml b/jetty-core/jetty-deploy/src/test/resources/webapps/bar-core-context-alt.xml
index 41787f99ed09..4aad41739bef 100644
--- a/jetty-core/jetty-deploy/src/test/resources/webapps/bar-core-context-alt.xml
+++ b/jetty-core/jetty-deploy/src/test/resources/webapps/bar-core-context-alt.xml
@@ -1,5 +1,5 @@
-
+
/bar
diff --git a/jetty-core/jetty-deploy/src/test/resources/webapps/bar-core-context.xml b/jetty-core/jetty-deploy/src/test/resources/webapps/bar-core-context.xml
index 8af6129f3b4c..72731f08c4d9 100644
--- a/jetty-core/jetty-deploy/src/test/resources/webapps/bar-core-context.xml
+++ b/jetty-core/jetty-deploy/src/test/resources/webapps/bar-core-context.xml
@@ -1,5 +1,5 @@
-
+
/bar
diff --git a/jetty-core/jetty-deploy/src/test/resources/webapps/foo.xml b/jetty-core/jetty-deploy/src/test/resources/webapps/foo.xml
index dfadf9a005a1..e8c94f70b642 100644
--- a/jetty-core/jetty-deploy/src/test/resources/webapps/foo.xml
+++ b/jetty-core/jetty-deploy/src/test/resources/webapps/foo.xml
@@ -1,5 +1,5 @@
-
+
/foo
diff --git a/jetty-core/jetty-deploy/src/test/resources/webapps/simple.xml b/jetty-core/jetty-deploy/src/test/resources/webapps/simple.xml
index a83ffeafa260..3aac3b002145 100644
--- a/jetty-core/jetty-deploy/src/test/resources/webapps/simple.xml
+++ b/jetty-core/jetty-deploy/src/test/resources/webapps/simple.xml
@@ -1,5 +1,5 @@
-
+
/simple
diff --git a/jetty-core/jetty-ee/src/main/config/modules/ee-webapp.mod b/jetty-core/jetty-ee/src/main/config/modules/ee-webapp.mod
index db2420cf4f29..4dea06e0eab3 100644
--- a/jetty-core/jetty-ee/src/main/config/modules/ee-webapp.mod
+++ b/jetty-core/jetty-ee/src/main/config/modules/ee-webapp.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
# tag::description[]
diff --git a/jetty-core/jetty-http2/jetty-http2-client-transport/src/main/config/modules/http2-client-transport.mod b/jetty-core/jetty-http2/jetty-http2-client-transport/src/main/config/modules/http2-client-transport.mod
new file mode 100644
index 000000000000..bee6003c5334
--- /dev/null
+++ b/jetty-core/jetty-http2/jetty-http2-client-transport/src/main/config/modules/http2-client-transport.mod
@@ -0,0 +1,16 @@
+[description]
+Adds the Jetty HTTP/2 client transport dependencies to the server classpath.
+
+[tags]
+client
+http2
+
+[depends]
+client
+http2-client
+
+[files]
+maven://org.eclipse.jetty.http2/jetty-http2-client-transport/${jetty.version}/jar|lib/http2/jetty-http2-client-transport-${jetty.version}.jar
+
+[lib]
+lib/http2/jetty-http2-client-transport-${jetty.version}.jar
diff --git a/jetty-core/jetty-http2/jetty-http2-client/src/main/config/modules/http2-client.mod b/jetty-core/jetty-http2/jetty-http2-client/src/main/config/modules/http2-client.mod
new file mode 100644
index 000000000000..b8734cd52efb
--- /dev/null
+++ b/jetty-core/jetty-http2/jetty-http2-client/src/main/config/modules/http2-client.mod
@@ -0,0 +1,18 @@
+[description]
+Adds the Jetty HTTP/2 client dependencies to the server classpath.
+
+[tags]
+client
+http2
+
+[files]
+maven://org.eclipse.jetty/jetty-alpn-client/${jetty.version}/jar|lib/jetty-alpn-client-${jetty.version}.jar
+maven://org.eclipse.jetty/jetty-alpn-java-client/${jetty.version}/jar|lib/jetty-alpn-java-client-${jetty.version}.jar
+maven://org.eclipse.jetty.http2/jetty-http2-client/${jetty.version}/jar|lib/http2/jetty-http2-client-${jetty.version}.jar
+
+[lib]
+lib/jetty-alpn-client-${jetty.version}.jar
+lib/jetty-alpn-java-client-${jetty.version}.jar
+lib/http2/jetty-http2-client-${jetty.version}.jar
+lib/http2/jetty-http2-common-${jetty.version}.jar
+lib/http2/jetty-http2-hpack-${jetty.version}.jar
diff --git a/jetty-core/jetty-http2/jetty-http2-server/src/main/config/etc/jetty-http2.xml b/jetty-core/jetty-http2/jetty-http2-server/src/main/config/etc/jetty-http2.xml
index 0b9fdc6c7b1d..a185f7fadca7 100644
--- a/jetty-core/jetty-http2/jetty-http2-server/src/main/config/etc/jetty-http2.xml
+++ b/jetty-core/jetty-http2/jetty-http2-server/src/main/config/etc/jetty-http2.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-core/jetty-http2/jetty-http2-server/src/main/config/etc/jetty-http2c.xml b/jetty-core/jetty-http2/jetty-http2-server/src/main/config/etc/jetty-http2c.xml
index 6d0ed5bd00fb..71020ac9c881 100644
--- a/jetty-core/jetty-http2/jetty-http2-server/src/main/config/etc/jetty-http2c.xml
+++ b/jetty-core/jetty-http2/jetty-http2-server/src/main/config/etc/jetty-http2c.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-core/jetty-http3/jetty-http3-server/src/main/config/etc/jetty-http3.xml b/jetty-core/jetty-http3/jetty-http3-server/src/main/config/etc/jetty-http3.xml
index 044b86ad909f..82e2ab4eea93 100644
--- a/jetty-core/jetty-http3/jetty-http3-server/src/main/config/etc/jetty-http3.xml
+++ b/jetty-core/jetty-http3/jetty-http3-server/src/main/config/etc/jetty-http3.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-core/jetty-jmx/src/main/config/etc/jetty-jmx-remote.xml b/jetty-core/jetty-jmx/src/main/config/etc/jetty-jmx-remote.xml
index aef61105a322..2f517dcfd378 100644
--- a/jetty-core/jetty-jmx/src/main/config/etc/jetty-jmx-remote.xml
+++ b/jetty-core/jetty-jmx/src/main/config/etc/jetty-jmx-remote.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-core/jetty-jmx/src/main/config/etc/jetty-jmx.xml b/jetty-core/jetty-jmx/src/main/config/etc/jetty-jmx.xml
index 2dfe691de241..008ad50b3ab9 100644
--- a/jetty-core/jetty-jmx/src/main/config/etc/jetty-jmx.xml
+++ b/jetty-core/jetty-jmx/src/main/config/etc/jetty-jmx.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-core/jetty-jmx/src/main/config/modules/jmx.d/jmx-remote-auth.xml b/jetty-core/jetty-jmx/src/main/config/modules/jmx.d/jmx-remote-auth.xml
index 6f1b65ef6fa1..adb2adaf2768 100644
--- a/jetty-core/jetty-jmx/src/main/config/modules/jmx.d/jmx-remote-auth.xml
+++ b/jetty-core/jetty-jmx/src/main/config/modules/jmx.d/jmx-remote-auth.xml
@@ -19,7 +19,7 @@
~
-->
-
+
[
diff --git a/jetty-core/jetty-jmx/src/main/config/modules/jmx.d/jmx-remote-ssl.xml b/jetty-core/jetty-jmx/src/main/config/modules/jmx.d/jmx-remote-ssl.xml
index 98c0dfc9eba2..78a79d82da27 100644
--- a/jetty-core/jetty-jmx/src/main/config/modules/jmx.d/jmx-remote-ssl.xml
+++ b/jetty-core/jetty-jmx/src/main/config/modules/jmx.d/jmx-remote-ssl.xml
@@ -19,7 +19,7 @@
~
-->
-
+
][
diff --git a/jetty-core/jetty-jndi/src/main/config/modules/jndi.mod b/jetty-core/jetty-jndi/src/main/config/modules/jndi.mod
index 117a02ca0c14..d4cf07a71a59 100644
--- a/jetty-core/jetty-jndi/src/main/config/modules/jndi.mod
+++ b/jetty-core/jetty-jndi/src/main/config/modules/jndi.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Adds the Jetty JNDI implementation to the classpath.
diff --git a/jetty-core/jetty-maven/src/main/java/org/eclipse/jetty/maven/AbstractHomeForker.java b/jetty-core/jetty-maven/src/main/java/org/eclipse/jetty/maven/AbstractHomeForker.java
index 1e2ce6a45f32..8fed99ce6d25 100644
--- a/jetty-core/jetty-maven/src/main/java/org/eclipse/jetty/maven/AbstractHomeForker.java
+++ b/jetty-core/jetty-maven/src/main/java/org/eclipse/jetty/maven/AbstractHomeForker.java
@@ -198,6 +198,15 @@ protected ProcessBuilder createCommand()
if (stopKey != null)
cmd.add("-DSTOP.KEY=" + stopKey);
+ //put any jetty properties onto the command line
+ if (jettyProperties != null)
+ {
+ for (Map.Entry e : jettyProperties.entrySet())
+ {
+ cmd.add(e.getKey() + "=" + e.getValue());
+ }
+ }
+
//set up enabled jetty modules
StringBuilder tmp = new StringBuilder();
tmp.append("--module=");
@@ -214,6 +223,7 @@ protected ProcessBuilder createCommand()
if (libExtJarFiles != null && !libExtJarFiles.isEmpty() && tmp.indexOf("ext") < 0)
tmp.append(",ext");
tmp.append("," + environment + "-maven");
+
cmd.add(tmp.toString());
//put any other jetty options onto the command line
@@ -222,15 +232,6 @@ protected ProcessBuilder createCommand()
Arrays.stream(jettyOptions.split(" ")).filter(a -> StringUtil.isNotBlank(a)).forEach((a) -> cmd.add(a.trim()));
}
- //put any jetty properties onto the command line
- if (jettyProperties != null)
- {
- for (Map.Entry e : jettyProperties.entrySet())
- {
- cmd.add(e.getKey() + "=" + e.getValue());
- }
- }
-
//existence of this file signals process started
cmd.add("jetty.token.file=" + tokenFile.getAbsolutePath().toString());
diff --git a/jetty-core/jetty-openid/src/main/config/modules/openid.mod b/jetty-core/jetty-openid/src/main/config/modules/openid.mod
index ddd36c8ec906..1f75f0478a23 100644
--- a/jetty-core/jetty-openid/src/main/config/modules/openid.mod
+++ b/jetty-core/jetty-openid/src/main/config/modules/openid.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Adds OpenId Connect authentication to the server.
diff --git a/jetty-core/jetty-plus/src/main/config/modules/plus.mod b/jetty-core/jetty-plus/src/main/config/modules/plus.mod
index 4813575eba36..fe87a55f5bc3 100644
--- a/jetty-core/jetty-plus/src/main/config/modules/plus.mod
+++ b/jetty-core/jetty-plus/src/main/config/modules/plus.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Adds the Jetty Plus JNDI support to the classpath.
diff --git a/jetty-core/jetty-rewrite/src/main/config/etc/jetty-rewrite-compactpath.xml b/jetty-core/jetty-rewrite/src/main/config/etc/jetty-rewrite-compactpath.xml
index 2eab21ff751a..68fedfc96cb6 100644
--- a/jetty-core/jetty-rewrite/src/main/config/etc/jetty-rewrite-compactpath.xml
+++ b/jetty-core/jetty-rewrite/src/main/config/etc/jetty-rewrite-compactpath.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-core/jetty-rewrite/src/main/config/etc/jetty-rewrite-customizer.xml b/jetty-core/jetty-rewrite/src/main/config/etc/jetty-rewrite-customizer.xml
index 2dfb8c9c76ab..84294a1f051f 100644
--- a/jetty-core/jetty-rewrite/src/main/config/etc/jetty-rewrite-customizer.xml
+++ b/jetty-core/jetty-rewrite/src/main/config/etc/jetty-rewrite-customizer.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-core/jetty-rewrite/src/main/config/etc/jetty-rewrite.xml b/jetty-core/jetty-rewrite/src/main/config/etc/jetty-rewrite.xml
index 9b0d0e3118d3..991a7597d234 100644
--- a/jetty-core/jetty-rewrite/src/main/config/etc/jetty-rewrite.xml
+++ b/jetty-core/jetty-rewrite/src/main/config/etc/jetty-rewrite.xml
@@ -1,4 +1,4 @@
-
+
diff --git a/jetty-core/jetty-rewrite/src/main/config/modules/rewrite-compactpath.mod b/jetty-core/jetty-rewrite/src/main/config/modules/rewrite-compactpath.mod
index d0b64c295cbb..7a6c1d84ecf6 100644
--- a/jetty-core/jetty-rewrite/src/main/config/modules/rewrite-compactpath.mod
+++ b/jetty-core/jetty-rewrite/src/main/config/modules/rewrite-compactpath.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Add a rule to the rewrite module to compact paths.
diff --git a/jetty-core/jetty-rewrite/src/main/config/modules/rewrite-customizer.mod b/jetty-core/jetty-rewrite/src/main/config/modules/rewrite-customizer.mod
index fced4946ee93..374867e45680 100644
--- a/jetty-core/jetty-rewrite/src/main/config/modules/rewrite-customizer.mod
+++ b/jetty-core/jetty-rewrite/src/main/config/modules/rewrite-customizer.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables a rewrite Rules container as a request customizer.
diff --git a/jetty-core/jetty-rewrite/src/main/config/modules/rewrite.mod b/jetty-core/jetty-rewrite/src/main/config/modules/rewrite.mod
index ba7e9815457a..8db323b256ff 100644
--- a/jetty-core/jetty-rewrite/src/main/config/modules/rewrite.mod
+++ b/jetty-core/jetty-rewrite/src/main/config/modules/rewrite.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Adds the RewriteHandler to the Handler chain.
diff --git a/jetty-core/jetty-rewrite/src/main/config/modules/rewrite/jetty-rewrite-rules.xml b/jetty-core/jetty-rewrite/src/main/config/modules/rewrite/jetty-rewrite-rules.xml
index 1bccfe945b1c..67d871a0defe 100644
--- a/jetty-core/jetty-rewrite/src/main/config/modules/rewrite/jetty-rewrite-rules.xml
+++ b/jetty-core/jetty-rewrite/src/main/config/modules/rewrite/jetty-rewrite-rules.xml
@@ -1,5 +1,5 @@
-
+
-
+
diff --git a/jetty-core/jetty-server/src/main/config/modules/acceptratelimit.mod b/jetty-core/jetty-server/src/main/config/modules/acceptratelimit.mod
index 1e2435f4f9cf..cf16c6c5a93b 100644
--- a/jetty-core/jetty-server/src/main/config/modules/acceptratelimit.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/acceptratelimit.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables a server-wide accept rate limit.
diff --git a/jetty-core/jetty-server/src/main/config/modules/bytebufferpool-quadratic.mod b/jetty-core/jetty-server/src/main/config/modules/bytebufferpool-quadratic.mod
index 962130af6c4a..58b93be6de75 100644
--- a/jetty-core/jetty-server/src/main/config/modules/bytebufferpool-quadratic.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/bytebufferpool-quadratic.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Configures the ByteBufferPool used by ServerConnectors.
diff --git a/jetty-core/jetty-server/src/main/config/modules/connectionlimit.mod b/jetty-core/jetty-server/src/main/config/modules/connectionlimit.mod
index 3c7b32d2041c..a6d489c0f805 100644
--- a/jetty-core/jetty-server/src/main/config/modules/connectionlimit.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/connectionlimit.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables a server-wide connection limit.
diff --git a/jetty-core/jetty-server/src/main/config/modules/cross-origin.mod b/jetty-core/jetty-server/src/main/config/modules/cross-origin.mod
index c9bf176b41f2..d9d4c4a8ce8e 100644
--- a/jetty-core/jetty-server/src/main/config/modules/cross-origin.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/cross-origin.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables CrossOriginHandler to support the CORS protocol and protect from cross-site request forgery (CSRF) attacks.
diff --git a/jetty-core/jetty-server/src/main/config/modules/customrequestlog.mod b/jetty-core/jetty-server/src/main/config/modules/customrequestlog.mod
index 710343ee54ec..e2b0178d50d3 100644
--- a/jetty-core/jetty-server/src/main/config/modules/customrequestlog.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/customrequestlog.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Deprecated name for requestlog using custom request logger.
diff --git a/jetty-core/jetty-server/src/main/config/modules/debug.mod b/jetty-core/jetty-server/src/main/config/modules/debug.mod
index 897dbaa2a4c4..b30cc8dde4c3 100644
--- a/jetty-core/jetty-server/src/main/config/modules/debug.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/debug.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables the DebugListener.
diff --git a/jetty-core/jetty-server/src/main/config/modules/debuglog.mod b/jetty-core/jetty-server/src/main/config/modules/debuglog.mod
index 1a0a3bb36fdd..de8ec60b7851 100644
--- a/jetty-core/jetty-server/src/main/config/modules/debuglog.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/debuglog.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Deprecated Debug Log using DebugHandle.
diff --git a/jetty-core/jetty-server/src/main/config/modules/ext.mod b/jetty-core/jetty-server/src/main/config/modules/ext.mod
index 6fc42b27cb8d..6e99b69621ee 100644
--- a/jetty-core/jetty-server/src/main/config/modules/ext.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/ext.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Adds the jar file from $JETTY_HOME/lib/ext and $JETTY_BASE/lib/ext to the server classpath.
diff --git a/jetty-core/jetty-server/src/main/config/modules/graceful.mod b/jetty-core/jetty-server/src/main/config/modules/graceful.mod
index 03a6d91b8e72..3dccd3c3896a 100644
--- a/jetty-core/jetty-server/src/main/config/modules/graceful.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/graceful.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables Graceful processing of requests
diff --git a/jetty-core/jetty-server/src/main/config/modules/gzip.mod b/jetty-core/jetty-server/src/main/config/modules/gzip.mod
index fc3a14a14de9..1fe563b62e7a 100644
--- a/jetty-core/jetty-server/src/main/config/modules/gzip.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/gzip.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables GzipHandler for dynamic gzip compression for the entire server.
diff --git a/jetty-core/jetty-server/src/main/config/modules/home-base-warning.mod b/jetty-core/jetty-server/src/main/config/modules/home-base-warning.mod
index e4ed15823bb2..828b6440995d 100644
--- a/jetty-core/jetty-server/src/main/config/modules/home-base-warning.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/home-base-warning.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Generates a warning that server has been run from $JETTY_HOME rather than from a $JETTY_BASE.
diff --git a/jetty-core/jetty-server/src/main/config/modules/https.mod b/jetty-core/jetty-server/src/main/config/modules/https.mod
index 59ae07ca0189..aa8ecfe64640 100644
--- a/jetty-core/jetty-server/src/main/config/modules/https.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/https.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Adds HTTPS protocol support to the TLS(SSL) Connector.
diff --git a/jetty-core/jetty-server/src/main/config/modules/inetaccess.mod b/jetty-core/jetty-server/src/main/config/modules/inetaccess.mod
index acd2ceacfe75..7f2f2cebea88 100644
--- a/jetty-core/jetty-server/src/main/config/modules/inetaccess.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/inetaccess.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables the InetAccessHandler.
diff --git a/jetty-core/jetty-server/src/main/config/modules/jaas.mod b/jetty-core/jetty-server/src/main/config/modules/jaas.mod
index 1f969842cd86..4bbc9b79512b 100644
--- a/jetty-core/jetty-server/src/main/config/modules/jaas.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/jaas.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables JAAS for deployed web applications.
diff --git a/jetty-core/jetty-server/src/main/config/modules/jdbc.mod b/jetty-core/jetty-server/src/main/config/modules/jdbc.mod
index 2177507f3815..9b1b1e56cd2e 100644
--- a/jetty-core/jetty-server/src/main/config/modules/jdbc.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/jdbc.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables the java.sql JPMS module.
diff --git a/jetty-core/jetty-server/src/main/config/modules/jvm.mod b/jetty-core/jetty-server/src/main/config/modules/jvm.mod
index 578f163b5786..7fe320304d4c 100644
--- a/jetty-core/jetty-server/src/main/config/modules/jvm.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/jvm.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Creates an ini template for setting JVM arguments (eg -Xmx ).
diff --git a/jetty-core/jetty-server/src/main/config/modules/lowresources.mod b/jetty-core/jetty-server/src/main/config/modules/lowresources.mod
index 6acebbfdcc5e..63794baffd9d 100644
--- a/jetty-core/jetty-server/src/main/config/modules/lowresources.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/lowresources.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables a low resource monitor on the server.
diff --git a/jetty-core/jetty-server/src/main/config/modules/proxy-protocol-ssl.mod b/jetty-core/jetty-server/src/main/config/modules/proxy-protocol-ssl.mod
index 8c0611c68c69..7b2d478720a3 100644
--- a/jetty-core/jetty-server/src/main/config/modules/proxy-protocol-ssl.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/proxy-protocol-ssl.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables the Proxy Protocol on the TLS(SSL) Connector.
diff --git a/jetty-core/jetty-server/src/main/config/modules/requestlog.mod b/jetty-core/jetty-server/src/main/config/modules/requestlog.mod
index bb5cb3ce95e4..959b83f44119 100644
--- a/jetty-core/jetty-server/src/main/config/modules/requestlog.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/requestlog.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Logs requests using CustomRequestLog and AsyncRequestLogWriter.
diff --git a/jetty-core/jetty-server/src/main/config/modules/resources.mod b/jetty-core/jetty-server/src/main/config/modules/resources.mod
index 9c503c554808..e5c6e6bce221 100644
--- a/jetty-core/jetty-server/src/main/config/modules/resources.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/resources.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
# tag::description[]
diff --git a/jetty-core/jetty-server/src/main/config/modules/secure-redirect.mod b/jetty-core/jetty-server/src/main/config/modules/secure-redirect.mod
index 80e47924cf3d..6704508255d5 100644
--- a/jetty-core/jetty-server/src/main/config/modules/secure-redirect.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/secure-redirect.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enable SecuredRedirectHandler to redirect all http requests to https on the secure port configured in the server.ini file.
diff --git a/jetty-core/jetty-server/src/main/config/modules/security.mod b/jetty-core/jetty-server/src/main/config/modules/security.mod
index f6bad5e49330..78d2e1d56e1b 100644
--- a/jetty-core/jetty-server/src/main/config/modules/security.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/security.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Adds core security handling to the classpath.
diff --git a/jetty-core/jetty-server/src/main/config/modules/session-cache-hash.mod b/jetty-core/jetty-server/src/main/config/modules/session-cache-hash.mod
index 79c4e753ec28..aaedd0585ede 100644
--- a/jetty-core/jetty-server/src/main/config/modules/session-cache-hash.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/session-cache-hash.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enable first level session cache.
diff --git a/jetty-core/jetty-server/src/main/config/modules/session-cache-null.mod b/jetty-core/jetty-server/src/main/config/modules/session-cache-null.mod
index 4e7af393f3b9..e7da2bbb42c9 100644
--- a/jetty-core/jetty-server/src/main/config/modules/session-cache-null.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/session-cache-null.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
A SessionCache that does not actually cache sessions.
diff --git a/jetty-core/jetty-server/src/main/config/modules/session-store-cache.mod b/jetty-core/jetty-server/src/main/config/modules/session-store-cache.mod
index 7485b70aa540..67bc582ab971 100644
--- a/jetty-core/jetty-server/src/main/config/modules/session-store-cache.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/session-store-cache.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables caching of SessionData in front of a SessionDataStore.
diff --git a/jetty-core/jetty-server/src/main/config/modules/session-store-file.mod b/jetty-core/jetty-server/src/main/config/modules/session-store-file.mod
index e00163a4883c..42f799fbdacb 100644
--- a/jetty-core/jetty-server/src/main/config/modules/session-store-file.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/session-store-file.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables session persistent storage in files.
diff --git a/jetty-core/jetty-server/src/main/config/modules/session-store-jdbc.mod b/jetty-core/jetty-server/src/main/config/modules/session-store-jdbc.mod
index 1ed5ef999d3e..ab4ea998fd9a 100644
--- a/jetty-core/jetty-server/src/main/config/modules/session-store-jdbc.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/session-store-jdbc.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables JDBC persistent/distributed session storage.
diff --git a/jetty-core/jetty-server/src/main/config/modules/sessions.mod b/jetty-core/jetty-server/src/main/config/modules/sessions.mod
index ade7f5396428..19adfb8a5183 100644
--- a/jetty-core/jetty-server/src/main/config/modules/sessions.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/sessions.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables session management.
diff --git a/jetty-core/jetty-server/src/main/config/modules/sessions/jdbc/datasource.mod b/jetty-core/jetty-server/src/main/config/modules/sessions/jdbc/datasource.mod
index e60eb16c4edc..ace61f3a77fa 100644
--- a/jetty-core/jetty-server/src/main/config/modules/sessions/jdbc/datasource.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/sessions/jdbc/datasource.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
JDBC Datasource connections for session storage.
diff --git a/jetty-core/jetty-server/src/main/config/modules/sessions/jdbc/driver.mod b/jetty-core/jetty-server/src/main/config/modules/sessions/jdbc/driver.mod
index 4d4af55f330d..880ca3355612 100644
--- a/jetty-core/jetty-server/src/main/config/modules/sessions/jdbc/driver.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/sessions/jdbc/driver.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
JDBC Driver connections for session storage.
diff --git a/jetty-core/jetty-server/src/main/config/modules/state.mod b/jetty-core/jetty-server/src/main/config/modules/state.mod
index aceeb233c1b7..405a28590010 100644
--- a/jetty-core/jetty-server/src/main/config/modules/state.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/state.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Creates and updates state file used by jetty.sh
diff --git a/jetty-core/jetty-server/src/main/config/modules/statistics.mod b/jetty-core/jetty-server/src/main/config/modules/statistics.mod
index 7eb8c22caf21..3009e97c076f 100644
--- a/jetty-core/jetty-server/src/main/config/modules/statistics.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/statistics.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables statistics collection for the server.
diff --git a/jetty-core/jetty-server/src/main/config/modules/threadpool-all-virtual.mod b/jetty-core/jetty-server/src/main/config/modules/threadpool-all-virtual.mod
index 1f9526b4f30e..388871b6b3e0 100644
--- a/jetty-core/jetty-server/src/main/config/modules/threadpool-all-virtual.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/threadpool-all-virtual.mod
@@ -13,7 +13,16 @@ etc/jetty-threadpool-all-virtual.xml
[ini-template]
# tag::documentation[]
-## Platform threads name prefix.
+## Virtual threads name prefix.
#jetty.threadPool.namePrefix=vtp
+## Maximum number of current virtual threads.
+#jetty.threadPool.maxThreads=200
+
+## Whether to track virtual threads so they appear
+## in the dump even if they are unmounted.
+#jetty.threadPool.tracking=false
+
+## Whether to output virtual thread's stack traces in the dump.
+#jetty.threadPool.detailedDump=false
# end::documentation[]
diff --git a/jetty-core/jetty-server/src/main/config/modules/threadpool-virtual.mod b/jetty-core/jetty-server/src/main/config/modules/threadpool-virtual.mod
index 88ab2a0c2749..ebc55200a6e3 100644
--- a/jetty-core/jetty-server/src/main/config/modules/threadpool-virtual.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/threadpool-virtual.mod
@@ -37,6 +37,10 @@ etc/jetty-threadpool-virtual.xml
## Virtual threads name prefix.
#jetty.threadPool.virtual.namePrefix=qtp-virtual-
-## Whether virtual threads inherits the values of inheritable thread locals.
-#jetty.threadPool.virtual.inheritInheritableThreadLocals=true
+## Max number of current virtual threads.
+#jetty.threadPool.virtual.maxThreads=200
+
+## Whether to track virtual threads so they appear
+## in the dump even if they are unmounted.
+#jetty.threadPool.virtual.tracking=false
# end::documentation[]
diff --git a/jetty-core/jetty-server/src/main/config/modules/well-known.mod b/jetty-core/jetty-server/src/main/config/modules/well-known.mod
index 370cc7fbdc6b..ab1aabb3e1ca 100644
--- a/jetty-core/jetty-server/src/main/config/modules/well-known.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/well-known.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Serve static files from a directory for the "/.well-known" context path.
diff --git a/jetty-core/jetty-server/src/main/config/modules/work.mod b/jetty-core/jetty-server/src/main/config/modules/work.mod
index 0299b7f92f50..c2076a0aec56 100644
--- a/jetty-core/jetty-server/src/main/config/modules/work.mod
+++ b/jetty-core/jetty-server/src/main/config/modules/work.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Creates the $JETTY_BASE/work directory as a persistent temp directory.
diff --git a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java
index 70360dac03c4..accc509c6f77 100644
--- a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java
+++ b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java
@@ -163,6 +163,7 @@ public HttpConfiguration(HttpConfiguration config)
_redirectUriCompliance = config._redirectUriCompliance;
_serverAuthority = config._serverAuthority;
_localAddress = config._localAddress;
+ _maxUnconsumedRequestContentReads = config._maxUnconsumedRequestContentReads;
}
/**
@@ -499,8 +500,9 @@ public void setFormEncodedMethods(String... methods)
/**
* @return the set of HTTP methods of requests that can be decoded as
- * {@code x-www-form-urlencoded} content.
+ * {@code application/x-www-form-urlencoded} content.
*/
+ @ManagedAttribute("The methods that support application/x-www-form-urlencoded content")
public Set getFormEncodedMethods()
{
return _formEncodedMethods.keySet();
@@ -585,6 +587,7 @@ public void setMinResponseDataRate(long bytesPerSecond)
_minResponseDataRate = bytesPerSecond;
}
+ @ManagedAttribute("The HTTP compliance mode")
public HttpCompliance getHttpCompliance()
{
return _httpCompliance;
@@ -595,6 +598,7 @@ public void setHttpCompliance(HttpCompliance httpCompliance)
_httpCompliance = httpCompliance;
}
+ @ManagedAttribute("The URI compliance mode")
public UriCompliance getUriCompliance()
{
return _uriCompliance;
@@ -622,6 +626,7 @@ public void setRedirectUriCompliance(UriCompliance uriCompliance)
* @return The CookieCompliance used for parsing request {@code Cookie} headers.
* @see #getResponseCookieCompliance()
*/
+ @ManagedAttribute("The HTTP request cookie compliance mode")
public CookieCompliance getRequestCookieCompliance()
{
return _requestCookieCompliance;
@@ -639,6 +644,7 @@ public void setRequestCookieCompliance(CookieCompliance cookieCompliance)
* @return The CookieCompliance used for generating response {@code Set-Cookie} headers
* @see #getRequestCookieCompliance()
*/
+ @ManagedAttribute("The HTTP response cookie compliance mode")
public CookieCompliance getResponseCookieCompliance()
{
return _responseCookieCompliance;
@@ -655,6 +661,7 @@ public void setResponseCookieCompliance(CookieCompliance cookieCompliance)
/**
* @return the {@link MultiPartCompliance} used for validating multipart form syntax.
*/
+ @ManagedAttribute("The multipart/form-data compliance mode")
public MultiPartCompliance getMultiPartCompliance()
{
return _multiPartCompliance;
@@ -765,7 +772,7 @@ public void setLocalAddress(SocketAddress localAddress)
*
* @return Returns the connection server authority (name/port) or null
*/
- @ManagedAttribute("The server authority if none provided by requests")
+ @ManagedAttribute("The server authority override")
public HostPort getServerAuthority()
{
return _serverAuthority;
@@ -833,6 +840,7 @@ public void dump(Appendable out, String indent) throws IOException
"requestHeaderSize=" + _requestHeaderSize,
"responseHeaderSize=" + _responseHeaderSize,
"headerCacheSize=" + _headerCacheSize,
+ "headerCacheCaseSensitive=" + _headerCacheCaseSensitive,
"secureScheme=" + _secureScheme,
"securePort=" + _securePort,
"idleTimeout=" + _idleTimeout,
@@ -842,12 +850,21 @@ public void dump(Appendable out, String indent) throws IOException
"delayDispatchUntilContent=" + _delayDispatchUntilContent,
"persistentConnectionsEnabled=" + _persistentConnectionsEnabled,
"maxErrorDispatches=" + _maxErrorDispatches,
+ "useInputDirectByteBuffers=" + _useInputDirectByteBuffers,
+ "useOutputDirectByteBuffers=" + _useOutputDirectByteBuffers,
"minRequestDataRate=" + _minRequestDataRate,
"minResponseDataRate=" + _minResponseDataRate,
+ "httpCompliance=" + _httpCompliance,
+ "uriCompliance=" + _uriCompliance,
+ "redirectUriCompliance=" + _redirectUriCompliance,
"requestCookieCompliance=" + _requestCookieCompliance,
"responseCookieCompliance=" + _responseCookieCompliance,
+ "multiPartCompliance=" + _multiPartCompliance,
"notifyRemoteAsyncErrors=" + _notifyRemoteAsyncErrors,
- "relativeRedirectAllowed=" + _relativeRedirectAllowed
+ "relativeRedirectAllowed=" + _relativeRedirectAllowed,
+ "serverAuthority=" + _serverAuthority,
+ "localAddress=" + _localAddress,
+ "maxUnconsumedRequestContentReads=" + _maxUnconsumedRequestContentReads
);
}
diff --git a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/QoSHandler.java b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/QoSHandler.java
index eb7442c62299..69722c13d408 100644
--- a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/QoSHandler.java
+++ b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/QoSHandler.java
@@ -51,8 +51,12 @@
* to the number configured via {@link #setMaxRequestCount(int)}.
* If more requests are received, they are suspended (that is, not
* forwarded to the child {@code Handler}) and stored in a priority
- * queue.
- * Priorities are determined via {@link #getPriority(Request)},
+ * queue.]
+ * The maximum number of suspended request can be set with
+ * {@link #setMaxSuspendedRequestCount(int)} to avoid out of memory errors.
+ * When this limit is reached, the request will fail fast
+ * with status code {@code 503} (not available).
+ * Priorities are determined via {@link #getPriority(Request)},
* that should return values between {@code 0} (the lowest priority)
* and positive numbers, typically in the range {@code 0-10}.
* When a request that is being processed completes, the suspended
@@ -82,6 +86,7 @@ public class QoSHandler extends ConditionalHandler.Abstract
private final Set priorities = new ConcurrentSkipListSet<>(Comparator.reverseOrder());
private CyclicTimeouts timeouts;
private int maxRequests;
+ private int maxSuspendedRequests = 1024;
private Duration maxSuspend = Duration.ZERO;
public QoSHandler()
@@ -119,6 +124,32 @@ public void setMaxRequestCount(int maxRequests)
this.maxRequests = maxRequests;
}
+ /**
+ * @return the max number of suspended requests
+ */
+ @ManagedAttribute(value = "The maximum number of suspended requests", readonly = true)
+ public int getMaxSuspendedRequestCount()
+ {
+ return maxSuspendedRequests;
+ }
+
+ /**
+ * Sets the max number of suspended requests.
+ * Once the max suspended request limit is reached,
+ * the request is failed with a HTTP status of
+ * {@code 503 Service unavailable}.
+ * A negative value indicate an unlimited number
+ * of suspended requests.
+ *
+ * @param maxSuspendedRequests the max number of suspended requests
+ */
+ public void setMaxSuspendedRequestCount(int maxSuspendedRequests)
+ {
+ if (isStarted())
+ throw new IllegalStateException("Cannot change maxSuspendedRequests: " + this);
+ this.maxSuspendedRequests = maxSuspendedRequests;
+ }
+
/**
* Get the max duration of time a request may stay suspended.
* @return the max duration of time a request may stay suspended
@@ -144,7 +175,7 @@ public void setMaxSuspend(Duration maxSuspend)
}
@ManagedAttribute("The number of suspended requests")
- public long getSuspendedRequestCount()
+ public int getSuspendedRequestCount()
{
int permits = state.get();
return Math.max(0, -permits);
@@ -194,6 +225,7 @@ private boolean process(Request request, Response response, Callback callback) t
LOG.debug("{} processing {}", this, request);
boolean expired = false;
+ boolean tooManyRequests = false;
// The read lock allows concurrency with resume(),
// which is the common case, but not with expire().
@@ -203,7 +235,15 @@ private boolean process(Request request, Response response, Callback callback) t
int permits = state.decrementAndGet();
if (permits < 0)
{
- if (request.getAttribute(EXPIRED_ATTRIBUTE_NAME) == null)
+ int maxSuspended = getMaxSuspendedRequestCount();
+ if (maxSuspended >= 0 && Math.abs(permits) > maxSuspended)
+ {
+ // Reached the limit of suspended requests,
+ // complete the request with 503 unavailable.
+ state.incrementAndGet();
+ tooManyRequests = true;
+ }
+ else if (request.getAttribute(EXPIRED_ATTRIBUTE_NAME) == null)
{
// Cover this race condition:
// T1 in this method may find no permits, so it will suspend the request.
@@ -228,11 +268,13 @@ private boolean process(Request request, Response response, Callback callback) t
lock.readLock().unlock();
}
- if (!expired)
- return handleWithPermit(request, response, callback);
+ if (expired || tooManyRequests)
+ {
+ notAvailable(response, callback);
+ return true;
+ }
- notAvailable(response, callback);
- return true;
+ return handleWithPermit(request, response, callback);
}
@Override
@@ -241,8 +283,10 @@ protected boolean onConditionsNotMet(Request request, Response response, Callbac
return nextHandler(request, response, callback);
}
- private static void notAvailable(Response response, Callback callback)
+ private void notAvailable(Response response, Callback callback)
{
+ if (LOG.isDebugEnabled())
+ LOG.debug("{} rejecting {}", this, response.getRequest());
response.setStatus(HttpStatus.SERVICE_UNAVAILABLE_503);
if (response.isCommitted())
callback.failed(new IllegalStateException("Response already committed"));
diff --git a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/QoSHandlerTest.java b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/QoSHandlerTest.java
index 25c66f469aae..76f67fd20952 100644
--- a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/QoSHandlerTest.java
+++ b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/QoSHandlerTest.java
@@ -17,6 +17,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
import org.eclipse.jetty.http.HttpStatus;
@@ -98,7 +99,7 @@ public boolean handle(Request request, Response response, Callback callback)
LocalConnector.LocalEndPoint endPoint = connector.executeRequest("""
GET /%d HTTP/1.1
Host: localhost
-
+
""".formatted(i));
endPoints.add(endPoint);
// Wait that the request arrives at the server.
@@ -109,7 +110,7 @@ public boolean handle(Request request, Response response, Callback callback)
LocalConnector.LocalEndPoint endPoint = connector.executeRequest("""
GET /%d HTTP/1.1
Host: localhost
-
+
""".formatted(maxRequests));
endPoints.add(endPoint);
@@ -164,7 +165,7 @@ public boolean handle(Request request, Response response, Callback callback)
LocalConnector.LocalEndPoint endPoint0 = connector.executeRequest("""
GET /0 HTTP/1.1
Host: localhost
-
+
""");
await().atMost(5, TimeUnit.SECONDS).until(callbacks::size, is(1));
@@ -172,7 +173,7 @@ public boolean handle(Request request, Response response, Callback callback)
LocalConnector.LocalEndPoint endPoint1 = connector.executeRequest("""
GET /1 HTTP/1.1
Host: localhost
-
+
""");
await().atMost(5, TimeUnit.SECONDS).until(qosHandler::getSuspendedRequestCount, is(1L));
@@ -194,7 +195,7 @@ public boolean handle(Request request, Response response, Callback callback)
LocalConnector.LocalEndPoint endPoint2 = connector.executeRequest("""
GET /2 HTTP/1.1
Host: localhost
-
+
""");
await().atMost(5, TimeUnit.SECONDS).until(callbacks::size, is(1));
callbacks.remove(0).succeeded();
@@ -233,7 +234,7 @@ public boolean handle(Request request, Response response, Callback callback)
LocalConnector.LocalEndPoint endPoint0 = connector.executeRequest("""
GET /0 HTTP/1.1
Host: localhost
-
+
""");
await().atMost(5, TimeUnit.SECONDS).until(callbacks::size, is(1));
@@ -242,7 +243,7 @@ public boolean handle(Request request, Response response, Callback callback)
GET /1 HTTP/1.1
Host: localhost
Priority: 0
-
+
""");
await().atMost(5, TimeUnit.SECONDS).until(callbacks::size, is(1));
@@ -251,7 +252,7 @@ public boolean handle(Request request, Response response, Callback callback)
GET /2 HTTP/1.1
Host: localhost
Priority: 1
-
+
""");
await().atMost(5, TimeUnit.SECONDS).until(callbacks::size, is(1));
@@ -320,7 +321,7 @@ public boolean handle(Request request, Response response, Callback callback)
try (LocalConnector.LocalEndPoint endPoint = connector.executeRequest("""
GET /%d/%d HTTP/1.1
Host: localhost
-
+
""".formatted(i, j)))
{
String text = endPoint.getResponse(false, parallelism * iterations * delay * 5, TimeUnit.MILLISECONDS);
@@ -360,7 +361,7 @@ public boolean handle(Request request, Response response, Callback callback)
LocalConnector.LocalEndPoint normalEndPoint = connector.executeRequest("""
GET /normal/request HTTP/1.1
Host: localhost
-
+
""");
await().atMost(5, TimeUnit.SECONDS).until(callbacks::size, is(1));
@@ -368,7 +369,7 @@ public boolean handle(Request request, Response response, Callback callback)
LocalConnector.LocalEndPoint anotherEndPoint = connector.executeRequest("""
GET /another/normal/request HTTP/1.1
Host: localhost
-
+
""");
await().atLeast(100, TimeUnit.MILLISECONDS).until(callbacks::size, is(1));
@@ -376,7 +377,7 @@ public boolean handle(Request request, Response response, Callback callback)
LocalConnector.LocalEndPoint specialEndPoint = connector.executeRequest("""
GET /special/info HTTP/1.1
Host: localhost
-
+
""");
// Wait that the request arrives at the server.
@@ -407,4 +408,79 @@ public boolean handle(Request request, Response response, Callback callback)
assertEquals(HttpStatus.OK_200, response.getStatus());
}
+ @Test
+ public void testMaxSuspendedRequests() throws Exception
+ {
+ int delay = 1000;
+ QoSHandler qosHandler = new QoSHandler();
+ qosHandler.setMaxRequestCount(2);
+ qosHandler.setMaxSuspendedRequestCount(2);
+ AtomicInteger handling = new AtomicInteger();
+ qosHandler.setHandler(new Handler.Abstract()
+ {
+ @Override
+ public boolean handle(Request request, Response response, Callback callback)
+ {
+ try
+ {
+ handling.incrementAndGet();
+ Thread.sleep(delay);
+ callback.succeeded();
+ }
+ catch (Throwable x)
+ {
+ callback.failed(x);
+ }
+ return true;
+ }
+ });
+ start(qosHandler);
+
+ List endPoints = new ArrayList<>();
+ // Send 2 requests that should pass through QoSHandler.
+ for (int i = 0; i < 2; i++)
+ {
+ LocalConnector.LocalEndPoint endPoint = connector.executeRequest("""
+ GET /pass/%d HTTP/1.1
+ Host: localhost
+
+ """.formatted(i));
+ endPoints.add(endPoint);
+ }
+ await().atMost(5, TimeUnit.SECONDS).until(handling::get, is(2));
+ // Send 2 requests that should be suspended by QoSHandler.
+ for (int i = 0; i < 2; i++)
+ {
+ LocalConnector.LocalEndPoint endPoint = connector.executeRequest("""
+ GET /suspend/%d HTTP/1.1
+ Host: localhost
+
+ """.formatted(i));
+ endPoints.add(endPoint);
+ }
+ await().atMost(5, TimeUnit.SECONDS).until(qosHandler::getSuspendedRequestCount, is(2));
+ // Send 2 requests that should be failed immediately by QoSHandler.
+ for (int i = 0; i < 2; i++)
+ {
+ HttpTester.Response response = HttpTester.parseResponse(connector.getResponse("""
+ GET /rejected/%d HTTP/1.1
+ Host: localhost
+
+ """.formatted(i)));
+ assertEquals(HttpStatus.SERVICE_UNAVAILABLE_503, response.getStatus());
+ }
+ // Wait for the other requests to finish normally.
+ endPoints.forEach(endPoint ->
+ {
+ try
+ {
+ HttpTester.Response response = HttpTester.parseResponse(endPoint.getResponse(false, 2 * delay, TimeUnit.MILLISECONDS));
+ assertEquals(HttpStatus.OK_200, response.getStatus());
+ }
+ catch (Exception x)
+ {
+ fail(x);
+ }
+ });
+ }
}
diff --git a/jetty-core/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java b/jetty-core/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java
index 6657fe4787da..93e679f6b44b 100644
--- a/jetty-core/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java
+++ b/jetty-core/jetty-start/src/main/java/org/eclipse/jetty/start/StartArgs.java
@@ -687,8 +687,9 @@ else if (properties.size() > 0)
// TODO module path
- for (Prop property : environment.getProperties())
- cmd.addArg(property.key, property.value);
+ Props props = environment.getProperties();
+ for (Prop property : props)
+ cmd.addArg(property.key, props.expand(property.value));
for (Path xmlFile : environment.getXmlFiles())
cmd.addArg(xmlFile.toAbsolutePath().toString());
diff --git a/jetty-core/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java b/jetty-core/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java
index 2b8d29468773..eac62584e6c9 100644
--- a/jetty-core/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java
+++ b/jetty-core/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java
@@ -14,7 +14,6 @@
package org.eclipse.jetty.start;
import java.io.ByteArrayOutputStream;
-import java.io.File;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -24,7 +23,6 @@
import java.util.List;
import org.eclipse.jetty.toolchain.test.MavenPaths;
-import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -67,7 +65,7 @@ public void testStopProcessing() throws Exception
public void testListConfig() throws Exception
{
List cmdLineArgs = new ArrayList<>();
- File testJettyHome = MavenTestingUtils.getTestResourceDir("dist-home");
+ Path testJettyHome = MavenPaths.findTestResourceDir("dist-home");
cmdLineArgs.add("user.dir=" + testJettyHome);
cmdLineArgs.add("-Duser.dir=foo"); // used to test "source" display on "Java Environment"
cmdLineArgs.add("jetty.home=" + testJettyHome);
@@ -99,8 +97,8 @@ public void testListConfig() throws Exception
public void testUnknownDistroCommand() throws Exception
{
List cmdLineArgs = new ArrayList<>();
- File testJettyHome = MavenTestingUtils.getTestResourceDir("dist-home");
- Path testJettyBase = MavenTestingUtils.getTargetTestingPath("base-example-unknown");
+ Path testJettyHome = MavenPaths.findTestResourceDir("dist-home");
+ Path testJettyBase = MavenPaths.targetTestDir("base-example-unknown");
FS.ensureDirectoryExists(testJettyBase);
Path zedIni = testJettyBase.resolve("start.d/zed.ini");
FS.ensureDirectoryExists(zedIni.getParent());
@@ -159,7 +157,7 @@ public void testJvmArgExpansion() throws Exception
{
List cmdLineArgs = new ArrayList<>();
- Path homePath = MavenTestingUtils.getTestResourcePathDir("dist-home").toRealPath();
+ Path homePath = MavenPaths.findTestResourceDir("dist-home");
cmdLineArgs.add("jetty.home=" + homePath);
cmdLineArgs.add("user.dir=" + homePath);
diff --git a/jetty-core/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyDump.java b/jetty-core/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyDump.java
index b7628290b70b..ab287a43f144 100644
--- a/jetty-core/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyDump.java
+++ b/jetty-core/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyDump.java
@@ -16,30 +16,35 @@
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
-import java.util.Enumeration;
+import java.util.Collections;
+import java.util.Objects;
import java.util.Properties;
+import java.util.function.Predicate;
public class PropertyDump
{
public static void main(String[] args)
{
System.out.printf("PropertyDump%n");
+
+ Predicate nameSelectionPredicate =
+ (name) ->
+ name.startsWith("test.") ||
+ name.startsWith("jetty.");
+
// As System Properties
Properties props = System.getProperties();
- Enumeration> names = props.propertyNames();
- while (names.hasMoreElements())
- {
- String name = (String)names.nextElement();
- // only interested in "test." prefixed properties
- if (name.startsWith("test."))
- {
- System.out.printf("System %s=%s%n", name, props.getProperty(name));
- }
- }
+ props.stringPropertyNames()
+ .stream()
+ .filter(nameSelectionPredicate)
+ .sorted()
+ .forEach((name) ->
+ System.out.printf("System %s=%s%n", name, props.getProperty(name)));
// As File Argument
for (String arg : args)
{
+ System.out.printf("Arg [%s]%n", arg);
if (arg.endsWith(".properties"))
{
Properties aprops = new Properties();
@@ -47,15 +52,13 @@ public static void main(String[] args)
try (FileReader reader = new FileReader(propFile))
{
aprops.load(reader);
- Enumeration> anames = aprops.propertyNames();
- while (anames.hasMoreElements())
- {
- String name = (String)anames.nextElement();
- if (name.startsWith("test."))
- {
- System.out.printf("%s %s=%s%n", propFile.getName(), name, aprops.getProperty(name));
- }
- }
+ Collections.list(aprops.propertyNames())
+ .stream()
+ .map(Objects::toString)
+ .filter(nameSelectionPredicate)
+ .sorted()
+ .forEach((name) ->
+ System.out.printf("%s %s=%s%n", propFile.getName(), name, aprops.getProperty(name)));
}
catch (IOException e)
{
diff --git a/jetty-core/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyPassingTest.java b/jetty-core/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyPassingTest.java
index 3e5bf9816d8f..5f609f36b1b6 100644
--- a/jetty-core/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyPassingTest.java
+++ b/jetty-core/jetty-start/src/test/java/org/eclipse/jetty/start/PropertyPassingTest.java
@@ -20,19 +20,26 @@
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.toolchain.test.IO;
-import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
+import org.eclipse.jetty.toolchain.test.MavenPaths;
+import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
+import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
+@ExtendWith(WorkDirExtension.class)
public class PropertyPassingTest
{
private static class ConsoleCapture implements Runnable
@@ -86,10 +93,12 @@ public ConsoleCapture start()
}
}
+ public WorkDir workDir;
+
@Test
public void testAsJvmArg() throws IOException, InterruptedException
{
- File bogusXml = MavenTestingUtils.getTestResourceFile("bogus.xml");
+ Path bogusXml = MavenPaths.findTestResourceFile("bogus.xml");
// Setup command line
List commands = new ArrayList<>();
@@ -100,7 +109,7 @@ public void testAsJvmArg() throws IOException, InterruptedException
// addDebug(commands);
commands.add("-Dtest.foo=bar"); // TESTING THIS
commands.add(getStartJarBin());
- commands.add(bogusXml.getAbsolutePath());
+ commands.add(bogusXml.toAbsolutePath().toString());
// Run command, collect output
String output = collectRunOutput(commands);
@@ -112,7 +121,7 @@ public void testAsJvmArg() throws IOException, InterruptedException
@Test
public void testAsCommandLineArg() throws IOException, InterruptedException
{
- File bogusXml = MavenTestingUtils.getTestResourceFile("bogus.xml");
+ Path bogusXml = MavenPaths.findTestResourceFile("bogus.xml");
// Setup command line
List commands = new ArrayList<>();
@@ -123,7 +132,7 @@ public void testAsCommandLineArg() throws IOException, InterruptedException
// addDebug(commands);
commands.add(getStartJarBin());
commands.add("test.foo=bar"); // TESTING THIS
- commands.add(bogusXml.getAbsolutePath());
+ commands.add(bogusXml.toAbsolutePath().toString());
// Run command, collect output
String output = collectRunOutput(commands);
@@ -135,7 +144,7 @@ public void testAsCommandLineArg() throws IOException, InterruptedException
@Test
public void testAsDashDCommandLineArg() throws IOException, InterruptedException
{
- File bogusXml = MavenTestingUtils.getTestResourceFile("bogus.xml");
+ Path bogusXml = MavenPaths.findTestResourceFile("bogus.xml");
// Setup command line
List commands = new ArrayList<>();
@@ -146,7 +155,7 @@ public void testAsDashDCommandLineArg() throws IOException, InterruptedException
// addDebug(commands);
commands.add(getStartJarBin());
commands.add("-Dtest.foo=bar"); // TESTING THIS
- commands.add(bogusXml.getAbsolutePath());
+ commands.add(bogusXml.toAbsolutePath().toString());
// Run command, collect output
String output = collectRunOutput(commands);
@@ -155,16 +164,143 @@ public void testAsDashDCommandLineArg() throws IOException, InterruptedException
assertThat(output, containsString("test.foo=bar"));
}
+ @Test
+ public void testExpandPropertyArg() throws IOException, InterruptedException
+ {
+ Path bogusXml = MavenPaths.findTestResourceFile("bogus.xml");
+
+ // Setup command line
+ List commands = new ArrayList<>();
+ commands.add(getJavaBin());
+ commands.add("-Dmain.class=" + PropertyDump.class.getName());
+ commands.add("-Dtest.dir=/opt/dists/jetty");
+ commands.add("-cp");
+ commands.add(getClassPath());
+ // addDebug(commands);
+ commands.add(getStartJarBin());
+ commands.add("test.config=${test.dir}/etc/config.ini"); // TESTING THIS
+ commands.add(bogusXml.toAbsolutePath().toString());
+
+ // Run command, collect output
+ String output = collectRunOutput(commands);
+
+ // Test for values
+ assertThat(output, containsString("test.config=/opt/dists/jetty/etc/config.ini"));
+ }
+
+ @Test
+ public void testExpandPropertyDArg() throws IOException, InterruptedException
+ {
+ Path bogusXml = MavenPaths.findTestResourceFile("bogus.xml");
+
+ // Setup command line
+ List commands = new ArrayList<>();
+ commands.add(getJavaBin());
+ commands.add("-Dmain.class=" + PropertyDump.class.getName());
+ commands.add("-Dtest.dir=/opt/dists/jetty");
+ commands.add("-cp");
+ commands.add(getClassPath());
+ // addDebug(commands);
+ commands.add(getStartJarBin());
+ commands.add("-Dtest.config=${test.dir}/etc/config.ini"); // TESTING THIS
+ commands.add(bogusXml.toAbsolutePath().toString());
+
+ // Run command, collect output
+ String output = collectRunOutput(commands);
+
+ // Test for values
+ assertThat(output, containsString("test.config=/opt/dists/jetty/etc/config.ini"));
+ }
+
+ @Test
+ public void testExpandPropertyStartIni() throws IOException, InterruptedException
+ {
+ Path bogusXml = MavenPaths.findTestResourceFile("bogus.xml");
+ Path base = workDir.getEmptyPathDir();
+ Path ini = base.resolve("start.d/config.ini");
+ FS.ensureDirectoryExists(ini.getParent());
+ String iniBody = """
+ # Enabling a single module (that does nothing) to let start.jar run
+ --module=empty
+ # TESTING THIS (it should expand the ${jetty.base} portion
+ test.config=${jetty.base}/etc/config.ini
+ """;
+ Files.writeString(ini, iniBody, StandardCharsets.UTF_8);
+
+ // Setup command line
+ List commands = new ArrayList<>();
+ commands.add(getJavaBin());
+ commands.add("-Dmain.class=" + PropertyDump.class.getName());
+ commands.add("-Djetty.base=" + base);
+ commands.add("-cp");
+ commands.add(getClassPath());
+ // addDebug(commands);
+ commands.add(getStartJarBin());
+ commands.add(bogusXml.toAbsolutePath().toString());
+
+ // Run command, collect output
+ String output = collectRunOutput(commands);
+
+ // Test for values
+ Path expectedPath = base.resolve("etc/config.ini");
+ assertThat(output, containsString("test.config=" + expectedPath));
+ }
+
+ @Test
+ public void testExpandEnvProperty() throws IOException, InterruptedException
+ {
+ Path bogusXml = MavenPaths.findTestResourceFile("bogus.xml");
+ Path base = workDir.getEmptyPathDir();
+ Path module = base.resolve("modules/env-config.mod");
+ FS.ensureDirectoryExists(module.getParent());
+ String moduleBody = """
+ [environment]
+ eex
+
+ [ini-template]
+ # configuration option
+ # test.config=${jetty.home}/etc/eex-config.ini
+ """;
+ Files.writeString(module, moduleBody, StandardCharsets.UTF_8);
+ Path ini = base.resolve("start.d/config.ini");
+ FS.ensureDirectoryExists(ini.getParent());
+ String iniBody = """
+ # Enabling a single module (that does nothing) to let start.jar run
+ --module=env-config
+ # TESTING THIS (it should expand the ${jetty.base} portion
+ test.config=${jetty.base}/etc/config.ini
+ """;
+ Files.writeString(ini, iniBody, StandardCharsets.UTF_8);
+
+ // Setup command line
+ List commands = new ArrayList<>();
+ commands.add(getJavaBin());
+ commands.add("-Dmain.class=" + PropertyDump.class.getName());
+ commands.add("-Djetty.base=" + base);
+ commands.add("-cp");
+ commands.add(getClassPath());
+ // addDebug(commands);
+ commands.add(getStartJarBin());
+ commands.add(bogusXml.toAbsolutePath().toString());
+
+ // Run command, collect output
+ String output = collectRunOutput(commands);
+
+ // Test for values
+ Path expectedPath = base.resolve("etc/config.ini");
+ assertThat(output, containsString("test.config=" + expectedPath));
+ }
+
private String getClassPath()
{
- StringBuilder cp = new StringBuilder();
- String pathSep = System.getProperty("path.separator");
- cp.append(MavenTestingUtils.getProjectDir("target/classes"));
- cp.append(pathSep);
- cp.append(MavenTestingUtils.getProjectDir("target/test-classes"));
- cp.append(pathSep);
- cp.append(MavenTestingUtils.getProjectDir("target/jetty-util"));
- return cp.toString();
+ return String.join(
+ File.pathSeparator,
+ List.of(
+ MavenPaths.projectBase().resolve("target/classes").toString(),
+ MavenPaths.projectBase().resolve("target/test-classes").toString(),
+ MavenPaths.projectBase().resolve("target/jetty-util").toString()
+ )
+ );
}
protected void addDebug(List commands)
@@ -180,11 +316,10 @@ private String collectRunOutput(List commands) throws IOException, Inter
{
cline.append(command).append(" ");
}
- System.out.println("Command line: " + cline);
ProcessBuilder builder = new ProcessBuilder(commands);
// Set PWD
- builder.directory(MavenTestingUtils.getTestResourceDir("empty.home"));
+ builder.directory(MavenPaths.findTestResourceDir("empty.home").toFile());
Process pid = builder.start();
ConsoleCapture stdOutPump = new ConsoleCapture("STDOUT", pid.getInputStream()).start();
@@ -193,6 +328,7 @@ private String collectRunOutput(List commands) throws IOException, Inter
int exitCode = pid.waitFor();
if (exitCode != 0)
{
+ System.out.println("Command line: " + cline);
System.out.printf("STDERR: [" + stdErrPump.getConsoleOutput() + "]%n");
System.out.printf("STDOUT: [" + stdOutPump.getConsoleOutput() + "]%n");
assertThat("Exit code", exitCode, is(0));
diff --git a/jetty-core/jetty-start/src/test/resources/dist-home/modules/main.mod b/jetty-core/jetty-start/src/test/resources/dist-home/modules/main.mod
index 8e398221e858..3d06d4efc22a 100644
--- a/jetty-core/jetty-start/src/test/resources/dist-home/modules/main.mod
+++ b/jetty-core/jetty-start/src/test/resources/dist-home/modules/main.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Example of a module
diff --git a/jetty-core/jetty-tests/jetty-test-client-transports/src/test/java/org/eclipse/jetty/test/client/transport/AbstractTest.java b/jetty-core/jetty-tests/jetty-test-client-transports/src/test/java/org/eclipse/jetty/test/client/transport/AbstractTest.java
index b51f938ea72f..8f4932f39fa8 100644
--- a/jetty-core/jetty-tests/jetty-test-client-transports/src/test/java/org/eclipse/jetty/test/client/transport/AbstractTest.java
+++ b/jetty-core/jetty-tests/jetty-test-client-transports/src/test/java/org/eclipse/jetty/test/client/transport/AbstractTest.java
@@ -290,6 +290,12 @@ protected SslContextFactory.Server newSslContextFactoryServer()
}
protected void startClient(Transport transport) throws Exception
+ {
+ prepareClient(transport);
+ client.start();
+ }
+
+ protected void prepareClient(Transport transport) throws Exception
{
QueuedThreadPool clientThreads = new QueuedThreadPool();
clientThreads.setName("client");
@@ -298,7 +304,6 @@ protected void startClient(Transport transport) throws Exception
client.setByteBufferPool(clientBufferPool);
client.setExecutor(clientThreads);
client.setSocketAddressResolver(new SocketAddressResolver.Sync());
- client.start();
}
public AbstractConnector newConnector(Transport transport, Server server)
diff --git a/jetty-core/jetty-tests/jetty-test-client-transports/src/test/java/org/eclipse/jetty/test/client/transport/ConnectionPoolTest.java b/jetty-core/jetty-tests/jetty-test-client-transports/src/test/java/org/eclipse/jetty/test/client/transport/ConnectionPoolTest.java
new file mode 100644
index 000000000000..a634883faea3
--- /dev/null
+++ b/jetty-core/jetty-tests/jetty-test-client-transports/src/test/java/org/eclipse/jetty/test/client/transport/ConnectionPoolTest.java
@@ -0,0 +1,104 @@
+//
+// ========================================================================
+// Copyright (c) 1995 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.test.client.transport;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.client.Destination;
+import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP;
+import org.eclipse.jetty.fcgi.server.internal.ServerFCGIConnection;
+import org.eclipse.jetty.http2.server.internal.HTTP2ServerConnection;
+import org.eclipse.jetty.io.Connection;
+import org.eclipse.jetty.io.ssl.SslConnection;
+import org.eclipse.jetty.quic.server.ServerQuicConnection;
+import org.eclipse.jetty.server.internal.HttpConnection;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.not;
+
+public class ConnectionPoolTest extends AbstractTest
+{
+ @ParameterizedTest
+ @MethodSource("transports")
+ public void testPreCreateConnections(Transport transport) throws Exception
+ {
+ prepareServer(transport, new EmptyServerHandler());
+ ConnectionListener serverConnections = new ConnectionListener();
+ connector.addBean(serverConnections);
+ server.start();
+
+ startClient(transport);
+ client.setMaxConnectionsPerDestination(8);
+ if (transport == Transport.HTTPS)
+ ((HttpClientTransportOverHTTP)client.getTransport()).setInitializeConnections(true);
+
+ var request = client.newRequest(newURI(transport));
+ Destination destination = client.resolveDestination(request);
+ destination.getConnectionPool().preCreateConnections(client.getMaxConnectionsPerDestination())
+ .get(5, TimeUnit.SECONDS);
+
+ // Verify that connections have been created.
+ List connections = switch (transport)
+ {
+ case HTTP, HTTPS -> serverConnections.filter(HttpConnection.class);
+ case H2C, H2 -> serverConnections.filter(HTTP2ServerConnection.class);
+ case H3 -> serverConnections.filter(ServerQuicConnection.class);
+ case FCGI -> serverConnections.filter(ServerFCGIConnection.class);
+ };
+ assertThat(connections, not(empty()));
+
+ // Verify that TLS was performed.
+ List sslConnections = switch (transport)
+ {
+ case HTTP, H2C, FCGI, H3 -> null;
+ case HTTPS, H2 -> serverConnections.filter(SslConnection.class);
+ };
+ if (sslConnections != null)
+ {
+ assertThat(sslConnections.size(), greaterThan(0));
+ sslConnections.forEach(c -> assertThat(c.getBytesIn(), greaterThan(0L)));
+ sslConnections.forEach(c -> assertThat(c.getBytesOut(), greaterThan(0L)));
+ }
+ }
+
+ private static class ConnectionListener implements Connection.Listener
+ {
+ private final List connections = new ArrayList<>();
+
+ @Override
+ public void onOpened(Connection connection)
+ {
+ connections.add(connection);
+ }
+
+ @Override
+ public void onClosed(Connection connection)
+ {
+ connections.remove(connection);
+ }
+
+ private List filter(Class extends Connection> klass)
+ {
+ return connections.stream()
+ .filter(klass::isInstance)
+ .toList();
+ }
+ }
+}
diff --git a/jetty-core/jetty-tests/jetty-test-http2-client-transport-provided-webapp/pom.xml b/jetty-core/jetty-tests/jetty-test-http2-client-transport-provided-webapp/pom.xml
new file mode 100644
index 000000000000..5d01a9f84896
--- /dev/null
+++ b/jetty-core/jetty-tests/jetty-test-http2-client-transport-provided-webapp/pom.xml
@@ -0,0 +1,30 @@
+
+
+ 4.0.0
+
+ org.eclipse.jetty
+ jetty-tests
+ 12.0.13-SNAPSHOT
+
+
+ jetty-test-http2-client-transport-provided-webapp
+ Core :: Tests :: HTTP/2 Client Transport Provided WebApp
+
+
+ true
+
+
+
+
+ org.eclipse.jetty
+ jetty-server
+ provided
+
+
+ org.eclipse.jetty.http2
+ jetty-http2-client-transport
+ provided
+
+
+
+
diff --git a/jetty-core/jetty-tests/jetty-test-http2-client-transport-provided-webapp/src/main/java/org/eclipse/jetty/test/http2/client/transport/provided/HTTP2ClientTransportProvidedHandler.java b/jetty-core/jetty-tests/jetty-test-http2-client-transport-provided-webapp/src/main/java/org/eclipse/jetty/test/http2/client/transport/provided/HTTP2ClientTransportProvidedHandler.java
new file mode 100644
index 000000000000..7b50bde8b9f3
--- /dev/null
+++ b/jetty-core/jetty-tests/jetty-test-http2-client-transport-provided-webapp/src/main/java/org/eclipse/jetty/test/http2/client/transport/provided/HTTP2ClientTransportProvidedHandler.java
@@ -0,0 +1,59 @@
+//
+// ========================================================================
+// Copyright (c) 1995 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.test.http2.client.transport.provided;
+
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.http2.client.HTTP2Client;
+import org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Response;
+import org.eclipse.jetty.util.Callback;
+
+public class HTTP2ClientTransportProvidedHandler extends Handler.Abstract
+{
+ private final HttpClient httpClient = new HttpClient(new HttpClientTransportOverHTTP2(new HTTP2Client()));
+
+ @Override
+ protected void doStart() throws Exception
+ {
+ addBean(httpClient);
+ super.doStart();
+ }
+
+ @Override
+ public boolean handle(Request request, Response response, Callback callback) throws Exception
+ {
+ // Verify that the HTTP2Client dependencies are provided by the server
+ // by making a request to an external server, as if this Handler was a proxy.
+
+ httpClient.newRequest("https://webtide.com/")
+ .timeout(15, TimeUnit.SECONDS)
+ .send(result ->
+ {
+ if (result.isSucceeded())
+ {
+ response.setStatus(result.getResponse().getStatus());
+ callback.succeeded();
+ }
+ else
+ {
+ callback.failed(result.getFailure());
+ }
+ });
+ return true;
+ }
+}
diff --git a/jetty-core/jetty-tests/pom.xml b/jetty-core/jetty-tests/pom.xml
index 4d84d2200c3f..52c44bf302bf 100644
--- a/jetty-core/jetty-tests/pom.xml
+++ b/jetty-core/jetty-tests/pom.xml
@@ -14,6 +14,7 @@
jetty-test-client-transports
jetty-test-jmx
+ jetty-test-http2-client-transport-provided-webapp
diff --git a/jetty-core/jetty-unixdomain-server/src/main/config/etc/jetty-unixdomain-http.xml b/jetty-core/jetty-unixdomain-server/src/main/config/etc/jetty-unixdomain-http.xml
index 7e7d8beda777..236563eecefa 100644
--- a/jetty-core/jetty-unixdomain-server/src/main/config/etc/jetty-unixdomain-http.xml
+++ b/jetty-core/jetty-unixdomain-server/src/main/config/etc/jetty-unixdomain-http.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-core/jetty-util/src/main/config/modules/console-capture.mod b/jetty-core/jetty-util/src/main/config/modules/console-capture.mod
index 24bb34984c05..0ad212be13c4 100644
--- a/jetty-core/jetty-util/src/main/config/modules/console-capture.mod
+++ b/jetty-core/jetty-util/src/main/config/modules/console-capture.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Redirects the JVM console stderr and stdout to a rolling log file.
diff --git a/jetty-core/jetty-util/src/main/config/modules/pid.mod b/jetty-core/jetty-util/src/main/config/modules/pid.mod
index 3e08fc545a9c..4b316327d08b 100644
--- a/jetty-core/jetty-util/src/main/config/modules/pid.mod
+++ b/jetty-core/jetty-util/src/main/config/modules/pid.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Creates the PID file for the Jetty process
diff --git a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/thread/VirtualThreadPool.java b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/thread/VirtualThreadPool.java
index bd90805b98da..09e4d2577c6c 100644
--- a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/thread/VirtualThreadPool.java
+++ b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/thread/VirtualThreadPool.java
@@ -16,6 +16,7 @@
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.Semaphore;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.VirtualThreads;
@@ -27,7 +28,10 @@
import org.slf4j.LoggerFactory;
/**
- * An implementation of {@link ThreadPool} interface that does not pool, but instead uses {@link VirtualThreads}.
+ * An implementation of {@link ThreadPool} interface that does not pool, but instead uses {@link VirtualThreads}.
+ * It is possible to specify the max number of concurrent virtual threads that can be spawned, to help limiting
+ * resource usage in applications, especially in case of load spikes, where an unlimited number of virtual threads
+ * may be spawned, compete for resources, and eventually bring the system down due to memory exhaustion.
*/
@ManagedObject("A thread non-pool for virtual threads")
public class VirtualThreadPool extends ContainerLifeCycle implements ThreadPool, Dumpable, TryExecutor, VirtualThreads.Configurable
@@ -35,12 +39,14 @@ public class VirtualThreadPool extends ContainerLifeCycle implements ThreadPool,
private static final Logger LOG = LoggerFactory.getLogger(VirtualThreadPool.class);
private final AutoLock.WithCondition _joinLock = new AutoLock.WithCondition();
- private String _name = null;
- private Executor _virtualExecutor;
- private Thread _main;
- private boolean _externalExecutor;
+ private String _name;
+ private int _maxThreads = 200;
private boolean _tracking;
private boolean _detailedDump;
+ private Thread _keepAlive;
+ private Executor _virtualExecutor;
+ private boolean _externalExecutor;
+ private Semaphore _semaphore;
public VirtualThreadPool()
{
@@ -71,12 +77,32 @@ public void setName(String name)
_name = name;
}
+ /**
+ * @return the maximum number of concurrent virtual threads
+ */
+ @ManagedAttribute("The max number of concurrent virtual threads")
+ public int getMaxThreads()
+ {
+ return _maxThreads;
+ }
+
+ /**
+ * @param maxThreads the maximum number of concurrent virtual threads
+ */
+ public void setMaxThreads(int maxThreads)
+ {
+ if (isRunning())
+ throw new IllegalStateException(getState());
+ _maxThreads = maxThreads;
+ }
+
/**
* Get if this pool is tracking virtual threads.
+ *
* @return {@code true} if the virtual threads will be tracked.
* @see TrackingExecutor
*/
- @ManagedAttribute("virtual threads are tracked")
+ @ManagedAttribute("Whether virtual threads are tracked")
public boolean isTracking()
{
return _tracking;
@@ -89,7 +115,7 @@ public void setTracking(boolean tracking)
_tracking = tracking;
}
- @ManagedAttribute("reports additional details in the dump")
+ @ManagedAttribute("Whether to report additional details in the dump")
public boolean isDetailedDump()
{
return _detailedDump;
@@ -101,11 +127,11 @@ public void setDetailedDump(boolean detailedDump)
if (_virtualExecutor instanceof TrackingExecutor trackingExecutor)
trackingExecutor.setDetailedDump(detailedDump);
}
-
+
@Override
protected void doStart() throws Exception
{
- _main = new Thread("jetty-virtual-thread-pool-keepalive")
+ _keepAlive = new Thread("jetty-virtual-thread-pool-keepalive")
{
@Override
public void run()
@@ -123,18 +149,24 @@ public void run()
}
}
};
- _main.start();
+ _keepAlive.start();
if (_virtualExecutor == null)
{
- _externalExecutor = false;
_virtualExecutor = Objects.requireNonNull(StringUtil.isBlank(_name)
? VirtualThreads.getDefaultVirtualThreadsExecutor()
: VirtualThreads.getNamedVirtualThreadsExecutor(_name));
}
if (_tracking && !(_virtualExecutor instanceof TrackingExecutor))
- _virtualExecutor = new TrackingExecutor(_virtualExecutor, _detailedDump);
+ _virtualExecutor = new TrackingExecutor(_virtualExecutor, isDetailedDump());
addBean(_virtualExecutor);
+
+ if (_maxThreads > 0)
+ {
+ _semaphore = new Semaphore(_maxThreads);
+ addBean(_semaphore);
+ }
+
super.doStart();
}
@@ -142,11 +174,12 @@ public void run()
protected void doStop() throws Exception
{
super.doStop();
+ removeBean(_semaphore);
+ _semaphore = null;
removeBean(_virtualExecutor);
if (!_externalExecutor)
_virtualExecutor = null;
- _main = null;
-
+ _keepAlive = null;
try (AutoLock.WithCondition l = _joinLock.lock())
{
l.signalAll();
@@ -208,7 +241,7 @@ public boolean tryExecute(Runnable task)
{
try
{
- _virtualExecutor.execute(task);
+ execute(task);
return true;
}
catch (RejectedExecutionException e)
@@ -221,6 +254,32 @@ public boolean tryExecute(Runnable task)
@Override
public void execute(Runnable task)
{
- _virtualExecutor.execute(task);
+ Runnable job = task;
+ if (_semaphore != null)
+ {
+ job = () ->
+ {
+ try
+ {
+ // The caller of execute(Runnable) cannot be blocked,
+ // as it is unknown whether it is a virtual thread.
+ // But this is a virtual thread, so acquiring a permit here
+ // blocks the virtual thread, but does not pin the carrier.
+ _semaphore.acquire();
+ task.run();
+ }
+ catch (InterruptedException x)
+ {
+ // Likely stopping this component, exit.
+ if (LOG.isDebugEnabled())
+ LOG.debug("interrupted while waiting for permit {}", task, x);
+ }
+ finally
+ {
+ _semaphore.release();
+ }
+ };
+ }
+ _virtualExecutor.execute(job);
}
}
diff --git a/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/thread/VirtualThreadPoolTest.java b/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/thread/VirtualThreadPoolTest.java
index 1f9ef396a77f..80683b7a8dc8 100644
--- a/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/thread/VirtualThreadPoolTest.java
+++ b/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/thread/VirtualThreadPoolTest.java
@@ -16,16 +16,19 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.jetty.util.StringUtil;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledForJreRange;
import org.junit.jupiter.api.condition.JRE;
+import static org.awaitility.Awaitility.await;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@DisabledForJreRange(max = JRE.JAVA_20)
@@ -146,6 +149,46 @@ public void testTrackingDump() throws Exception
}
}
+ @Test
+ public void testMaxThreads() throws Exception
+ {
+ VirtualThreadPool vtp = new VirtualThreadPool();
+ vtp.setMaxThreads(1);
+ vtp.start();
+
+ AtomicBoolean run1 = new AtomicBoolean();
+ CountDownLatch latch1 = new CountDownLatch(1);
+ vtp.execute(() ->
+ {
+ try
+ {
+ // Simulate a blocking call.
+ run1.set(true);
+ latch1.await();
+ }
+ catch (InterruptedException x)
+ {
+ throw new RuntimeException(x);
+ }
+ });
+
+ // Wait for the first task to acquire the only permit.
+ await().atMost(1, TimeUnit.SECONDS).until(run1::get);
+
+ // Try to submit another task, it should not
+ // be executed, and the caller must not block.
+ CountDownLatch latch2 = new CountDownLatch(1);
+ vtp.execute(latch2::countDown);
+ assertFalse(latch2.await(1, TimeUnit.SECONDS));
+
+ // Unblocking the first task allows the execution of the second task.
+ latch1.countDown();
+
+ assertTrue(latch2.await(5, TimeUnit.SECONDS));
+
+ vtp.stop();
+ }
+
public static int count(String str, String subStr)
{
if (StringUtil.isEmpty(str))
diff --git a/jetty-ee10/jetty-ee10-annotations/src/main/config/modules/ee10-annotations.mod b/jetty-ee10/jetty-ee10-annotations/src/main/config/modules/ee10-annotations.mod
index c3b24d3716f2..dbd7bdf86609 100644
--- a/jetty-ee10/jetty-ee10-annotations/src/main/config/modules/ee10-annotations.mod
+++ b/jetty-ee10/jetty-ee10-annotations/src/main/config/modules/ee10-annotations.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables Annotation scanning for deployed web applications.
diff --git a/jetty-ee10/jetty-ee10-apache-jsp/src/main/config/modules/ee10-apache-jsp.mod b/jetty-ee10/jetty-ee10-apache-jsp/src/main/config/modules/ee10-apache-jsp.mod
index e06a1bddb299..1c92cdcb3cc2 100644
--- a/jetty-ee10/jetty-ee10-apache-jsp/src/main/config/modules/ee10-apache-jsp.mod
+++ b/jetty-ee10/jetty-ee10-apache-jsp/src/main/config/modules/ee10-apache-jsp.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Enables use of the apache implementation of JSP.
diff --git a/jetty-ee10/jetty-ee10-cdi/src/main/config/modules/ee10-cdi-decorate.mod b/jetty-ee10/jetty-ee10-cdi/src/main/config/modules/ee10-cdi-decorate.mod
index a5d664bbf6e5..b27bce53cca2 100644
--- a/jetty-ee10/jetty-ee10-cdi/src/main/config/modules/ee10-cdi-decorate.mod
+++ b/jetty-ee10/jetty-ee10-cdi/src/main/config/modules/ee10-cdi-decorate.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Configures Jetty to use the "CdiDecoratingListener" as the default CDI mode.
diff --git a/jetty-ee10/jetty-ee10-cdi/src/main/config/modules/ee10-cdi-spi.mod b/jetty-ee10/jetty-ee10-cdi/src/main/config/modules/ee10-cdi-spi.mod
index 981e689feba9..f9d4cdb0e014 100644
--- a/jetty-ee10/jetty-ee10-cdi/src/main/config/modules/ee10-cdi-spi.mod
+++ b/jetty-ee10/jetty-ee10-cdi/src/main/config/modules/ee10-cdi-spi.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Configures Jetty to use the "CdiSpiDecorator" as the default CDI mode.
diff --git a/jetty-ee10/jetty-ee10-cdi/src/main/config/modules/ee10-cdi.mod b/jetty-ee10/jetty-ee10-cdi/src/main/config/modules/ee10-cdi.mod
index 94d490847a8c..800e2043186c 100644
--- a/jetty-ee10/jetty-ee10-cdi/src/main/config/modules/ee10-cdi.mod
+++ b/jetty-ee10/jetty-ee10-cdi/src/main/config/modules/ee10-cdi.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Provides integration of CDI within webapp to Jetty container object lifecycles.
diff --git a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-async-rest/jetty-ee10-demo-async-rest-webapp/src/main/config/modules/ee10-demo-async-rest.mod b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-async-rest/jetty-ee10-demo-async-rest-webapp/src/main/config/modules/ee10-demo-async-rest.mod
index d015f02487e6..8e2bdb270351 100644
--- a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-async-rest/jetty-ee10-demo-async-rest-webapp/src/main/config/modules/ee10-demo-async-rest.mod
+++ b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-async-rest/jetty-ee10-demo-async-rest-webapp/src/main/config/modules/ee10-demo-async-rest.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Demo Async Rest webapp
diff --git a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-async-rest/jetty-ee10-demo-async-rest-webapp/src/main/webapp/WEB-INF/jetty-web.xml b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-async-rest/jetty-ee10-demo-async-rest-webapp/src/main/webapp/WEB-INF/jetty-web.xml
index 993604c2427d..e15d79203dd4 100644
--- a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-async-rest/jetty-ee10-demo-async-rest-webapp/src/main/webapp/WEB-INF/jetty-web.xml
+++ b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-async-rest/jetty-ee10-demo-async-rest-webapp/src/main/webapp/WEB-INF/jetty-web.xml
@@ -1,5 +1,5 @@
-
+
-
+
diff --git a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-embedded/src/main/resources/exampleserver.xml b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-embedded/src/main/resources/exampleserver.xml
index b8056cdbecbc..10f6287cd790 100644
--- a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-embedded/src/main/resources/exampleserver.xml
+++ b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-embedded/src/main/resources/exampleserver.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-embedded/src/main/resources/fileserver.xml b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-embedded/src/main/resources/fileserver.xml
index 2fcadfe77b02..613c4136aa16 100644
--- a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-embedded/src/main/resources/fileserver.xml
+++ b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-embedded/src/main/resources/fileserver.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/config/modules/demo.d/ee10-demo-jaas.xml b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/config/modules/demo.d/ee10-demo-jaas.xml
index 1167c1494f6f..145fee70d562 100644
--- a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/config/modules/demo.d/ee10-demo-jaas.xml
+++ b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/config/modules/demo.d/ee10-demo-jaas.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/config/modules/ee10-demo-jaas.mod b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/config/modules/ee10-demo-jaas.mod
index c3d1976e4b25..e13f223a5e23 100644
--- a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/config/modules/ee10-demo-jaas.mod
+++ b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/config/modules/ee10-demo-jaas.mod
@@ -1,4 +1,4 @@
-# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
+# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/
[description]
Demo EE10 JAAS webapp
diff --git a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/webapp/WEB-INF/jetty-web.xml b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/webapp/WEB-INF/jetty-web.xml
index 794ff67798b7..0e1cec96bf1b 100644
--- a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/webapp/WEB-INF/jetty-web.xml
+++ b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/webapp/WEB-INF/jetty-web.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/webapp/index.html b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/webapp/index.html
index 72ba7989e9a0..02f71fa4c0d5 100644
--- a/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/webapp/index.html
+++ b/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp/src/main/webapp/index.html
@@ -36,7 +36,7 @@ Using the Demo