Merge remote-tracking branch 'origin/jetty-12.0.x' into jetty-12.0.x-ee9-ContextHandlerClassLoading
This commit is contained in:
commit
a67e48d1ee
|
@ -2,7 +2,7 @@
|
|||
// See https://github.com/asciidoctor/asciidoctor-intellij-plugin/wiki/Support-project-specific-configurations
|
||||
:ee-all: ee{8,9,10}
|
||||
:ee-current: ee10
|
||||
:ee-current-caps: EE10
|
||||
:ee-current-caps: EE 10
|
||||
:experimental:
|
||||
:imagesdir: images
|
||||
:jetty-home: ../../../../../../../jetty-home/target/jetty-home
|
||||
|
|
|
@ -18,9 +18,17 @@ You can deploy two types of web application resources with Jetty:
|
|||
|
||||
* *Standard Web Application Archives*, in the form of `+*.war+` files or web application directories, defined by the link:https://www.oracle.com/java/technologies/java-servlet-tec.html[Servlet specification].
|
||||
Their deployment is described in xref:og-begin-deploy-war[this section].
|
||||
* *Jetty context XML files*, that allow you to customize the deployment of standard web applications, and also allow you use Jetty components -- and possibly custom components written by you -- to assemble your web applications.
|
||||
* *Jetty context XML files*, that allow you to customize the deployment of standard web applications, and also allow you to use Jetty components -- and possibly custom components written by you -- to assemble your web applications.
|
||||
Their deployment is described in xref:og-deploy[this section].
|
||||
|
||||
Jetty supports the deployment of both standard web applications and Jetty context XML files in a specific _environment_.
|
||||
|
||||
In the following sections you can find simple examples of deployments of Jakarta {ee-current-caps} web applications.
|
||||
|
||||
However, Jetty supports simultaneous deployment of web applications each to a possibly different environment, for example an old Java EE 8 web application alongside a new Jakarta {ee-current-caps} web application.
|
||||
|
||||
Refer to the section about xref:og-deploy[deployment] for further information about how to deploy to different environments.
|
||||
|
||||
[[og-begin-deploy-war]]
|
||||
===== Deploying +*.war+ Files
|
||||
|
||||
|
@ -48,7 +56,12 @@ mywebapp.war
|
|||
|
||||
To deploy a standard web application, you need to enable the xref:og-module-eeN-deploy[`{ee-current}-deploy` module].
|
||||
|
||||
NOTE: The following examples assume you're deploying a Jakarta {ee-current-caps} application; for other versions of Jakarta EE, make sure to activate the corresponding `{ee-all}-deploy` module.
|
||||
[NOTE]
|
||||
====
|
||||
The following examples assume you're deploying a Jakarta {ee-current-caps} application; for other versions of Jakarta EE, make sure to activate the corresponding `{ee-all}-deploy` module.
|
||||
|
||||
Refer to the section about xref:og-deploy[deployment] for further information about how to deploy to different environments.
|
||||
====
|
||||
|
||||
[subs=attributes]
|
||||
----
|
||||
|
|
|
@ -14,12 +14,31 @@
|
|||
[[og-deploy]]
|
||||
=== Web Application Deployment
|
||||
|
||||
Most of the times you want to be able to customize the deployment of your web applications, for example by changing the `contextPath`, or by adding JNDI entries, or by configuring virtual hosts, etc.
|
||||
Most of the time you want to be able to customize the deployment of your web applications, for example by changing the `contextPath`, or by adding JNDI entries, or by configuring virtual hosts, etc.
|
||||
|
||||
The customization is performed by the xref:og-module-eeN-deploy[`{ee-all}-deploy` module] by processing xref:og-deploy-jetty[Jetty context XML files].
|
||||
Jetty supports the deployment of each web application to a specific _environment_.
|
||||
The available environments are:
|
||||
|
||||
* Java EE 8 -- Supports Servlet 4.0 (and associated specifications) in the `+javax.*+` packages.
|
||||
* Jakarta EE 9 -- Supports Servlet 5.0 (and associated specifications) in the `+jakarta.*+` packages.
|
||||
* Jakarta EE 10 -- Supports Servlet 6.0 (and associated specifications) in the `+jakarta.*+` packages.
|
||||
* Jetty core -- Supports web applications written against the Jetty `Handler` APIs, without any Servlet dependencies.
|
||||
|
||||
This means that you can simultaneously deploy an old Java EE 8 web application, say `old-ee8.war`, alongside a new Jakarta {ee-current-caps} web application, say `new-{ee-current}.war`, alongside a web application that only uses the Jetty `Handler` APIs, say `app-jetty.xml`.
|
||||
|
||||
The customization is performed by processing xref:og-deploy-jetty[Jetty context XML files].
|
||||
|
||||
The `deploy` module contains the `DeploymentManager` component that scans the `$JETTY_BASE/webapps` directory for changes, following the deployment rules described in xref:og-deploy-rules[this section].
|
||||
|
||||
For each specific environment there is a specific deploy module that you must enable:
|
||||
|
||||
* For Java EE 8, xref:og-module-eeN-deploy[`ee8-deploy`]
|
||||
* For Java EE 9, xref:og-module-eeN-deploy[`ee9-deploy`]
|
||||
* For Java {ee-current-caps}, xref:og-module-eeN-deploy[`{ee-current}-deploy`]
|
||||
* For Jetty core, xref:og-module-core-deploy[`core-deploy`]
|
||||
|
||||
Each of these modules provide the environment specific features, and depend on the `deploy` module that provides the scanning features.
|
||||
|
||||
include::deploy-hot-static.adoc[]
|
||||
include::deploy-rules.adoc[]
|
||||
include::deploy-jetty.adoc[]
|
||||
|
|
|
@ -21,12 +21,12 @@ The web application resources are served by Jetty from the files extracted in th
|
|||
If you do not want Jetty to extract the `+*.war+` files, you can disable this feature, for example:
|
||||
|
||||
.mywebapp.xml
|
||||
[source,xml,highlight=8]
|
||||
[source,xml,highlight=8,subs="verbatim,attributes"]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
|
||||
<Configure class="org.eclipse.jetty.{ee-current}.webapp.WebAppContext">
|
||||
<Set name="contextPath">/mywebapp</Set>
|
||||
<Set name="war">/opt/webapps/mywebapp.war</Set>
|
||||
<Set name="extractWAR">false</Set>
|
||||
|
|
|
@ -23,17 +23,17 @@ To deploy a web application using a Jetty context XML file, simply place the fil
|
|||
A simple Jetty context XML file, for example named `wiki.xml` is the following:
|
||||
|
||||
.wiki.xml
|
||||
[source,xml,subs=verbatim]
|
||||
[source,xml,subs="verbatim,attributes"]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext"> <1>
|
||||
<Configure class="org.eclipse.jetty.{ee-current}.webapp.WebAppContext"> <1>
|
||||
<Set name="contextPath">/wiki</Set> <2>
|
||||
<Set name="war">/opt/myapps/myapp.war</Set> <3>
|
||||
</Configure>
|
||||
----
|
||||
<1> Configures a link:{javadoc-url}/org/eclipse/jetty/webapp/WebAppContext.html[`WebAppContext`], which is the Jetty component that represents a standard Servlet web application.
|
||||
<1> Configures a link:{javadoc-url}/org/eclipse/jetty/{ee-current}/webapp/WebAppContext.html[`WebAppContext`], which is the Jetty component that represents a standard Servlet web application.
|
||||
<2> Specifies the web application `contextPath`, which may be different from the `+*.war+` file name.
|
||||
<3> Specifies the file system path of the `+*.war+` file.
|
||||
|
||||
|
@ -57,12 +57,12 @@ IMPORTANT: If you place both the Jetty context XML file _and_ the `+*.war+` file
|
|||
You can use the features of xref:og-xml[Jetty XML files] to avoid to hard-code file system paths or other configurations in your Jetty context XML files, for example by using system properties:
|
||||
|
||||
.wiki.xml
|
||||
[source,xml]
|
||||
[source,xml,subs="verbatim,attributes"]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
|
||||
<Configure class="org.eclipse.jetty.{ee-current}.webapp.WebAppContext">
|
||||
<Set name="contextPath">/wiki</Set>
|
||||
<Set name="war"><SystemProperty name="myapps.dir"/>/myapp.war</Set>
|
||||
</Configure>
|
||||
|
|
|
@ -18,12 +18,12 @@ A web application may _reference_ a JNDI entry, such as a JDBC `DataSource` from
|
|||
The JNDI entry must be _defined_ in a xref:og-jndi-xml[Jetty XML file], for example a context XML like so:
|
||||
|
||||
.mywebapp.xml
|
||||
[source,xml,subs=normal]
|
||||
[source,xml,subs="verbatim,attributes"]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<Configure id="wac" class="org.eclipse.jetty.ee9.webapp.WebAppContext">
|
||||
<Configure id="wac" class="org.eclipse.jetty.{ee-current}.webapp.WebAppContext">
|
||||
<Set name="contextPath">/mywebapp</Set>
|
||||
<Set name="war">/opt/webapps/mywebapp.war</Set>
|
||||
# <New class="org.eclipse.jetty.plus.jndi.Resource">
|
||||
|
@ -47,8 +47,8 @@ For more information and examples on how to use JNDI in Jetty, refer to the xref
|
|||
Class `com.mysql.cj.jdbc.MysqlConnectionPoolDataSource` is present in the MySQL JDBC driver file, `mysql-connector-java-<version>.jar`, which must be available on the server's classpath .
|
||||
|
||||
If the class is instead present _within_ the web application, then the JNDI entry must be declared in a `WEB-INF/jetty-env.xml` file - see the xref:og-jndi[JNDI] feature section for more information and examples.
|
||||
|
||||
====
|
||||
|
||||
// TODO: add a link to reference the section about how
|
||||
// to add a JDBC driver jar to the server classpath.
|
||||
|
||||
|
|
|
@ -19,12 +19,12 @@ This additional `web.xml` is processed _after_ the `+*.war+` file `web.xml`.
|
|||
This allows you to add host specific configuration or server specific configuration without having to extract the web application `web.xml`, modify it, and repackage it in the `+*.war+` file.
|
||||
|
||||
.mywebapp.xml
|
||||
[source,xml,highlight=8]
|
||||
[source,xml,highlight=8,subs="verbatim,attributes"]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
|
||||
<Configure class="org.eclipse.jetty.{ee-current}.webapp.WebAppContext">
|
||||
<Set name="contextPath">/mywebapp</Set>
|
||||
<Set name="war">/opt/webapps/mywebapp.war</Set>
|
||||
<Set name="overrideDescriptor">/opt/webapps/mywebapp-web.xml</Set>
|
||||
|
@ -39,8 +39,8 @@ The format of the additional `web.xml` is exactly the same as a standard `web.xm
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
|
||||
version="4.0">
|
||||
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
|
||||
version="6.0">
|
||||
<servlet>
|
||||
<servlet-name>my-servlet</servlet-name>
|
||||
<init-param>
|
||||
|
|
|
@ -20,19 +20,44 @@ _Updating_ a `+*.war+` file or a Jetty context XML file causes the `DeploymentMa
|
|||
|
||||
_Removing_ a `+*.war+` file, a `+*.war+` directory, a Jetty context XML file or a normal directory from `$JETTY_BASE/webapps` causes the `DeploymentManager` to undeploy the web application, which means that the Jetty context component representing the web application is stopped and removed from the Jetty server.
|
||||
|
||||
[[og-deploy-rules-context-path]]
|
||||
===== Context Path Resolution
|
||||
|
||||
When a file or directory is added to `$JETTY_BASE/webapps`, the `DeploymentManager` derives the web application `contextPath` from the file or directory name, with the following rules:
|
||||
|
||||
* If the directory name is, for example, `mywebapp/`, it is deployed as a standard web application if it contains a `WEB-INF/` subdirectory, otherwise it is deployed as a web application of static content.
|
||||
The `contextPath` would be `/mywebapp` (that is, the web application is reachable at `+http://localhost:8080/mywebapp/+`).
|
||||
* If the directory name is `ROOT`, case insensitive, the `contextPath` is `/` (that is, the web application is reachable at `+http://localhost:8080/+`).
|
||||
* If the directory name is `ROOT`, case-insensitive, the `contextPath` is `/` (that is, the web application is reachable at `+http://localhost:8080/+`).
|
||||
* If the directory name ends with `.d`, for example `config.d/`, it is ignored, although it may be referenced to configure other web applications (for example to store common files).
|
||||
* If the `+*.war+` file name is, for example, `mywebapp.war`, it is deployed as a standard web application with the context path `/mywebapp` (that is, the web application is reachable at `+http://localhost:8080/mywebapp/+`).
|
||||
* If the file name is `ROOT.war`, case insensitive, the `contextPath` is `/` (that is, the web application is reachable at `+http://localhost:8080/+`).
|
||||
* If the file name is `ROOT.war`, case-insensitive, the `contextPath` is `/` (that is, the web application is reachable at `+http://localhost:8080/+`).
|
||||
* If both the `mywebapp.war` file and the `mywebapp/` directory exist, only the file is deployed.
|
||||
This allows the directory with the same name to be the `+*.war+` file unpack location and avoid that the web application is deployed twice.
|
||||
* A xref:og-deploy-jetty[Jetty context XML file] named `mywebapp.xml` is deployed as a web application by processing the directives contained in the XML file itself, which must set the `contextPath`.
|
||||
* A xref:og-deploy-jetty[Jetty context XML file] named `mywebapp.xml` is deployed as a web application by processing the directives contained in the XML file itself, which must set the `contextPath`, which could be different from the name of the XML file.
|
||||
* If both `mywebapp.xml` and `mywebapp.war` exist, only the XML file is deployed.
|
||||
This allows the XML file to reference the `+*.war+` file and avoid that the web application is deployed twice.
|
||||
|
||||
[[og-deploy-rules-environment]]
|
||||
===== Environment Resolution
|
||||
|
||||
A web application is always deployed to a specific environment.
|
||||
|
||||
If you enabled only one specific deployer module, for example `{ee-current}-deploy`, then the web applications and the Jetty context XML files in `$JETTY_BASE/webapps` will be deployed to the `{ee-current}` environment.
|
||||
|
||||
You can enable multiple deployer modules if you need to deploy multiple web applications each to a specific environment.
|
||||
|
||||
For example, you have an `old-ee9.war` web application that you want to deploy to the Jakarta EE 9 environment, and a `new-{ee-current}.war` web application that you want to deploy to the Jakarta {ee-current-caps} environment.
|
||||
First, you must enable both the `ee9-deploy` and the `{ee-current}-deploy` modules.
|
||||
Then, you add a `+*.properties+` file with the same name of the web application, in the example above `$JETTY_BASE/webapps/old-ee9.properties`, with the following content:
|
||||
|
||||
[source,properties]
|
||||
====
|
||||
environment=ee9
|
||||
====
|
||||
|
||||
You may also add a `+*.properties+` file for `new-{ee-current}.war`, but it is not necessary because the most recent environment is used by default.
|
||||
// TODO: verify the statement above. For an ee8 and an ee9 webapp, is it true that ee9 will be used by default (or ee10 will)?
|
||||
|
||||
|
||||
// TODO: add section about the work directory from
|
||||
// old_docs/contexts/temporary-directories.adoc
|
||||
|
|
|
@ -53,12 +53,12 @@ For example if the non-ASCII domain name `www.√integral.com` is given to a bro
|
|||
|
||||
If you have a web application `mywebapp.war` you can configure its virtual hosts in this way:
|
||||
|
||||
[source,xml]
|
||||
[source,xml,subs="verbatim,attributes"]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
|
||||
<Configure class="org.eclipse.jetty.{ee-current}.webapp.WebAppContext">
|
||||
<Set name="contextPath">/mywebapp</Set>
|
||||
<Set name="war">/opt/webapps/mywebapp.war</Set>
|
||||
<Set name="virtualHosts">
|
||||
|
@ -98,12 +98,12 @@ You have `domain.war` that you want to deploy at `+http://domain.biz/+` and `hob
|
|||
To achieve this, you simply use the same context path of `/` for each of your webapps, while specifying different virtual hosts for each of your webapps:
|
||||
|
||||
.domain.xml
|
||||
[source,xml]
|
||||
[source,xml,subs="verbatim,attributes"]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
|
||||
<Configure class="org.eclipse.jetty.{ee-current}.webapp.WebAppContext">
|
||||
<Set name="contextPath">/</Set>
|
||||
<Set name="war">/opt/webapps/domain.war</Set>
|
||||
<Set name="virtualHosts">
|
||||
|
@ -115,12 +115,12 @@ To achieve this, you simply use the same context path of `/` for each of your we
|
|||
----
|
||||
|
||||
.hobby.xml
|
||||
[source,xml]
|
||||
[source,xml,subs="verbatim,attributes"]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
|
||||
<Configure class="org.eclipse.jetty.{ee-current}.webapp.WebAppContext">
|
||||
<Set name="contextPath">/</Set>
|
||||
<Set name="war">/opt/webapps/hobby.war</Set>
|
||||
<Set name="virtualHosts">
|
||||
|
@ -143,12 +143,12 @@ This configuration may be useful when Jetty sits behind a load balancer.
|
|||
In this case, you want to xref:og-protocols[configure multiple connectors], each with a different name, and then reference the connector name in the web application virtual host configuration:
|
||||
|
||||
.domain.xml
|
||||
[source,xml,highlight=10]
|
||||
[source,xml,highlight=10,subs="verbatim,attributes"]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
|
||||
<Configure class="org.eclipse.jetty.{ee-current}.webapp.WebAppContext">
|
||||
<Set name="contextPath">/</Set>
|
||||
<Set name="war">/opt/webapps/domain.war</Set>
|
||||
<Set name="virtualHosts">
|
||||
|
@ -160,12 +160,12 @@ In this case, you want to xref:og-protocols[configure multiple connectors], each
|
|||
----
|
||||
|
||||
.hobby.xml
|
||||
[source,xml,highlight=10]
|
||||
[source,xml,highlight=10,subs="verbatim,attributes"]
|
||||
----
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
|
||||
<Configure class="org.eclipse.jetty.{ee-current}.webapp.WebAppContext">
|
||||
<Set name="contextPath">/</Set>
|
||||
<Set name="war">/opt/webapps/hobby.war</Set>
|
||||
<Set name="virtualHosts">
|
||||
|
|
|
@ -11,16 +11,13 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
module org.eclipse.jetty.ee
|
||||
{
|
||||
requires org.slf4j;
|
||||
[[og-module-core-deploy]]
|
||||
===== Module `core-deploy`
|
||||
|
||||
requires transitive org.eclipse.jetty.io;
|
||||
requires transitive org.eclipse.jetty.security;
|
||||
include::{jetty-home}/modules/{ee-current}-deploy.mod[tags=description]
|
||||
|
||||
// Only required if using JMX.
|
||||
requires static org.eclipse.jetty.jmx;
|
||||
Deployment is managed via a `DeploymentManager` component that watches a directory for changes.
|
||||
See xref:og-deploy[how to deploy web applications] for more information.
|
||||
|
||||
exports org.eclipse.jetty.ee;
|
||||
exports org.eclipse.jetty.ee.security;
|
||||
}
|
||||
TODO
|
||||
// TODO see module-eeN-deploy.adoc
|
|
@ -17,6 +17,7 @@
|
|||
include::module-alpn.adoc[]
|
||||
include::module-bytebufferpool.adoc[]
|
||||
include::module-console-capture.adoc[]
|
||||
include::module-core-deploy.adoc[]
|
||||
include::module-eeN-deploy.adoc[]
|
||||
include::module-http.adoc[]
|
||||
include::module-http2.adoc[]
|
||||
|
|
|
@ -79,11 +79,6 @@
|
|||
<artifactId>jetty-deploy</artifactId>
|
||||
<version>12.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-ee</artifactId>
|
||||
<version>12.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
|
|
|
@ -315,6 +315,11 @@ public abstract class HttpConnection implements IConnection, Attachable
|
|||
return String.format("%s@%h", getClass().getSimpleName(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Enforces the total timeout for requests that have been sent.</p>
|
||||
* <p>The total timeout for exchanges that are in the destination queue
|
||||
* is enforced in {@link HttpDestination}.</p>
|
||||
*/
|
||||
private class RequestTimeouts extends CyclicTimeouts<HttpChannel>
|
||||
{
|
||||
private RequestTimeouts(Scheduler scheduler)
|
||||
|
@ -332,11 +337,14 @@ public abstract class HttpConnection implements IConnection, Attachable
|
|||
protected boolean onExpired(HttpChannel channel)
|
||||
{
|
||||
HttpExchange exchange = channel.getHttpExchange();
|
||||
if (exchange != null)
|
||||
{
|
||||
HttpRequest request = exchange.getRequest();
|
||||
request.abort(new TimeoutException("Total timeout " + request.getConversation().getTimeout() + " ms elapsed"));
|
||||
}
|
||||
// The expiration lost the race, as the
|
||||
// exchange may have just been completed.
|
||||
if (exchange == null)
|
||||
return false;
|
||||
HttpRequest request = exchange.getRequest();
|
||||
request.abort(new TimeoutException("Total timeout " + request.getConversation().getTimeout() + " ms elapsed"));
|
||||
// The implementation of the Iterator returned above may not support
|
||||
// removal, but the HttpChannel will be removed by request.abort().
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -550,7 +550,7 @@ public class HttpDestination extends ContainerLifeCycle implements Destination,
|
|||
}
|
||||
|
||||
/**
|
||||
* <p>Enforces the total timeout for for exchanges that are still in the queue.</p>
|
||||
* <p>Enforces the total timeout for exchanges that are still in the queue.</p>
|
||||
* <p>The total timeout for exchanges that are not in the destination queue
|
||||
* is enforced in {@link HttpConnection}.</p>
|
||||
*/
|
||||
|
@ -572,6 +572,8 @@ public class HttpDestination extends ContainerLifeCycle implements Destination,
|
|||
{
|
||||
HttpRequest request = exchange.getRequest();
|
||||
request.abort(new TimeoutException("Total timeout " + request.getConversation().getTimeout() + " ms elapsed"));
|
||||
// The implementation of the Iterator returned above does not support
|
||||
// removal, but the HttpExchange will be removed by request.abort().
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,10 +44,6 @@
|
|||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-ee</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
module org.eclipse.jetty.deploy
|
||||
{
|
||||
requires java.xml;
|
||||
requires org.eclipse.jetty.ee;
|
||||
requires org.eclipse.jetty.xml;
|
||||
requires org.eclipse.jetty.server;
|
||||
requires org.slf4j;
|
||||
|
|
|
@ -20,7 +20,7 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.eclipse.jetty.ee.Deployable;
|
||||
import org.eclipse.jetty.server.Deployable;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.eclipse.jetty.deploy.bindings.StandardUndeployer;
|
|||
import org.eclipse.jetty.deploy.graph.Edge;
|
||||
import org.eclipse.jetty.deploy.graph.Node;
|
||||
import org.eclipse.jetty.deploy.graph.Route;
|
||||
import org.eclipse.jetty.ee.Deployable;
|
||||
import org.eclipse.jetty.server.Deployable;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.util.ExceptionUtil;
|
||||
|
|
|
@ -32,7 +32,7 @@ import java.util.function.Supplier;
|
|||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.ee.Deployable;
|
||||
import org.eclipse.jetty.server.Deployable;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
|
|
|
@ -29,7 +29,7 @@ import java.util.stream.Collectors;
|
|||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.AppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.ee.Deployable;
|
||||
import org.eclipse.jetty.server.Deployable;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-core</artifactId>
|
||||
<version>12.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-ee</artifactId>
|
||||
<name>Core :: EE Utilities</name>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.ee</bundle-symbolic-name>
|
||||
<spotbugs.onlyAnalyze>org.eclipse.jetty.ee.*</spotbugs.onlyAnalyze>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>
|
||||
@{argLine} ${jetty.surefire.argLine} --add-reads org.eclipse.jetty.io=org.eclipse.jetty.logging
|
||||
</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-io</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-slf4j-impl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -192,8 +192,11 @@ public class JettyHttpExchangeDelegate extends HttpExchange
|
|||
@Override
|
||||
public void setStreams(InputStream i, OutputStream o)
|
||||
{
|
||||
_inputStream = i;
|
||||
_outputStream = o;
|
||||
assert _inputStream != null;
|
||||
if (i != null)
|
||||
_inputStream = i;
|
||||
if (o != null)
|
||||
_outputStream = o;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -592,6 +592,12 @@ public interface HttpCookie
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder sameSite(SameSite sameSite)
|
||||
{
|
||||
_attributes = lazyAttributePut(_attributes, SAME_SITE_ATTRIBUTE, sameSite.attributeValue);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an immutable {@link HttpCookie} instance.
|
||||
*/
|
||||
|
@ -878,7 +884,7 @@ public interface HttpCookie
|
|||
private static Map<String, String> lazyAttributePut(Map<String, String> attributes, String key, String value)
|
||||
{
|
||||
if (value == null)
|
||||
return attributes;
|
||||
return lazyAttributeRemove(attributes, key);
|
||||
if (attributes == null)
|
||||
attributes = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
attributes.put(key, value);
|
||||
|
|
|
@ -152,7 +152,7 @@ public class HttpField
|
|||
*/
|
||||
public boolean contains(String search)
|
||||
{
|
||||
return contains(_value, search);
|
||||
return contains(getValue(), search);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -337,7 +337,7 @@ public class HttpField
|
|||
return false;
|
||||
if (!_name.equalsIgnoreCase(field.getName()))
|
||||
return false;
|
||||
return Objects.equals(_value, field.getValue());
|
||||
return Objects.equals(getValue(), field.getValue());
|
||||
}
|
||||
|
||||
public HttpHeader getHeader()
|
||||
|
@ -347,12 +347,12 @@ public class HttpField
|
|||
|
||||
public int getIntValue()
|
||||
{
|
||||
return Integer.parseInt(_value);
|
||||
return Integer.parseInt(getValue());
|
||||
}
|
||||
|
||||
public long getLongValue()
|
||||
{
|
||||
return Long.parseLong(_value);
|
||||
return Long.parseLong(getValue());
|
||||
}
|
||||
|
||||
public String getLowerCaseName()
|
||||
|
@ -380,16 +380,17 @@ public class HttpField
|
|||
|
||||
public List<String> getValueList()
|
||||
{
|
||||
if (_value == null)
|
||||
String value = getValue();
|
||||
if (value == null)
|
||||
return null;
|
||||
QuotedCSV list = new QuotedCSV(false, _value);
|
||||
QuotedCSV list = new QuotedCSV(false, value);
|
||||
return list.getValues();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
int vhc = Objects.hashCode(_value);
|
||||
int vhc = Objects.hashCode(getValue());
|
||||
if (_header == null)
|
||||
return vhc ^ nameHashCode();
|
||||
return vhc ^ _header.hashCode();
|
||||
|
|
|
@ -2385,6 +2385,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements Session
|
|||
protected boolean onExpired(HTTP2Stream stream)
|
||||
{
|
||||
stream.onIdleTimeout(new TimeoutException("Idle timeout " + stream.getIdleTimeout() + " ms elapsed"));
|
||||
// The implementation of the Iterator returned above does not support
|
||||
// removal, but the HTTP2Stream will be removed by stream.onIdleTimeout().
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -311,10 +311,9 @@ public class HTTP2Stream implements Stream, Attachable, Closeable, Callback, Dum
|
|||
notifyIdleTimeout(this, timeout, Promise.from(timedOut ->
|
||||
{
|
||||
if (timedOut)
|
||||
{
|
||||
// Tell the other peer that we timed out.
|
||||
reset(new ResetFrame(getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
|
||||
}
|
||||
else
|
||||
notIdle();
|
||||
}, x -> reset(new ResetFrame(getId(), ErrorCode.INTERNAL_ERROR.code), Callback.NOOP)));
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
|||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
@Disabled // TODO: bug/race condition in HttpChannelState, where the last write callback is invoked _after_ complete().
|
||||
public class MaxConcurrentStreamsTest extends AbstractTest
|
||||
{
|
||||
private void start(int maxConcurrentStreams, Handler handler) throws Exception
|
||||
|
|
|
@ -46,7 +46,7 @@ public abstract class HTTP3Stream implements Stream, CyclicTimeouts.Expirable, A
|
|||
private CloseState closeState = CloseState.NOT_CLOSED;
|
||||
private FrameState frameState = FrameState.INITIAL;
|
||||
private long idleTimeout;
|
||||
private long expireNanoTime;
|
||||
private long expireNanoTime = Long.MAX_VALUE;
|
||||
private Object attachment;
|
||||
private boolean dataDemand;
|
||||
private boolean dataStalled;
|
||||
|
@ -129,6 +129,8 @@ public abstract class HTTP3Stream implements Stream, CyclicTimeouts.Expirable, A
|
|||
{
|
||||
if (timedOut)
|
||||
endPoint.close(HTTP3ErrorCode.REQUEST_CANCELLED_ERROR.code(), timeout);
|
||||
else
|
||||
notIdle();
|
||||
promise.succeeded(timedOut);
|
||||
}, promise::failed));
|
||||
}
|
||||
|
|
|
@ -125,8 +125,14 @@ public abstract class HTTP3StreamConnection extends AbstractConnection
|
|||
case FRAME ->
|
||||
{
|
||||
action.getAndSet(null).run();
|
||||
// Do not release the buffer here to avoid races with
|
||||
// user-spawned threads that may call Stream.read().
|
||||
// Do not release the buffer before the stream started closing
|
||||
// to avoid races with user-spawned threads that may call Stream.read().
|
||||
if (remotelyClosed)
|
||||
{
|
||||
// The last frame may have caused a write that we need to flush.
|
||||
getEndPoint().getQuicSession().flush();
|
||||
tryReleaseBuffer(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -190,7 +196,7 @@ public abstract class HTTP3StreamConnection extends AbstractConnection
|
|||
}
|
||||
|
||||
if (!parser.isDataMode())
|
||||
throw new IllegalStateException();
|
||||
continue;
|
||||
|
||||
if (stream.hasDemandOrStall())
|
||||
{
|
||||
|
@ -213,9 +219,6 @@ public abstract class HTTP3StreamConnection extends AbstractConnection
|
|||
// From now on it's the application that drives
|
||||
// demand, reads, parse+fill and fill interest.
|
||||
return;
|
||||
|
||||
// TODO: do we loop here?
|
||||
// There might be a trailer, loop around.
|
||||
}
|
||||
default -> throw new IllegalStateException("unknown message parser result: " + result);
|
||||
}
|
||||
|
|
|
@ -65,6 +65,10 @@ public abstract class CyclicTimeouts<T extends CyclicTimeouts.Expirable> impleme
|
|||
* <p>This method may be invoked multiple times, and even concurrently,
|
||||
* for the same expirable entity and therefore the expiration of the
|
||||
* entity, if any, should be an idempotent action.</p>
|
||||
* <p>When {@code false} is returned, the implementation should adjust
|
||||
* the {@link Expirable} expiration, so that a call to
|
||||
* {@link Expirable#getExpireNanoTime()} after this method has returned
|
||||
* yields a new expiration nanoTime.</p>
|
||||
*
|
||||
* @param expirable the entity that is expired
|
||||
* @return whether the entity should be removed from the iterator via {@link Iterator#remove()}
|
||||
|
@ -78,11 +82,10 @@ public abstract class CyclicTimeouts<T extends CyclicTimeouts.Expirable> impleme
|
|||
|
||||
long now = NanoTime.now();
|
||||
long earliest = Long.MAX_VALUE;
|
||||
// Reset the earliest timeout so we can expire again.
|
||||
// A concurrent call to schedule(long) may lose an
|
||||
// earliest value, but the corresponding entity will
|
||||
// be seen during the iteration below.
|
||||
earliestTimeout.set(earliest);
|
||||
// Move the earliest timeout far in the future, so we can expire again.
|
||||
// A concurrent call to schedule(long) may lose an earliest value, but
|
||||
// the corresponding entity will be seen during the iteration below.
|
||||
earliestTimeout.set(now + Long.MAX_VALUE);
|
||||
|
||||
Iterator<T> iterator = iterator();
|
||||
if (iterator == null)
|
||||
|
@ -98,23 +101,26 @@ public abstract class CyclicTimeouts<T extends CyclicTimeouts.Expirable> impleme
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Entity {} expires in {} ms for {}", expirable, NanoTime.millisElapsed(now, expiresAt), this);
|
||||
|
||||
if (expiresAt == -1)
|
||||
continue;
|
||||
|
||||
if (NanoTime.isBeforeOrSame(expiresAt, now))
|
||||
{
|
||||
boolean remove = onExpired(expirable);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Entity {} expired, remove={} for {}", expirable, remove, this);
|
||||
if (remove)
|
||||
{
|
||||
iterator.remove();
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
long newExpiresAt = expirable.getExpireNanoTime();
|
||||
if (newExpiresAt == expiresAt)
|
||||
continue;
|
||||
expiresAt = newExpiresAt;
|
||||
}
|
||||
|
||||
earliest = Math.min(earliest, NanoTime.elapsed(now, expiresAt));
|
||||
}
|
||||
|
||||
if (earliest < Long.MAX_VALUE)
|
||||
if (earliest != Long.MAX_VALUE)
|
||||
schedule(now + earliest);
|
||||
}
|
||||
|
||||
|
@ -126,7 +132,7 @@ public abstract class CyclicTimeouts<T extends CyclicTimeouts.Expirable> impleme
|
|||
public void schedule(T expirable)
|
||||
{
|
||||
long expiresAt = expirable.getExpireNanoTime();
|
||||
if (expiresAt < Long.MAX_VALUE)
|
||||
if (expiresAt != Long.MAX_VALUE)
|
||||
schedule(expiresAt);
|
||||
}
|
||||
|
||||
|
|
|
@ -139,6 +139,23 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump
|
|||
executor.execute(task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total number of keys from each selector.
|
||||
*
|
||||
* @return total number of selector keys
|
||||
*/
|
||||
@ManagedAttribute(value = "Total number of keys in all selectors", readonly = true)
|
||||
public int getTotalKeys()
|
||||
{
|
||||
int keys = 0;
|
||||
for (final ManagedSelector selector : _selectors)
|
||||
{
|
||||
keys += selector.getTotalKeys();
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the number of selectors in use
|
||||
*/
|
||||
|
@ -506,4 +523,10 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump
|
|||
{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x[keys=%d]", getClass().getSimpleName(), hashCode(), getTotalKeys());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.util.Collection;
|
|||
import java.util.Objects;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicMarkableReference;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
@ -38,10 +39,15 @@ import org.eclipse.jetty.util.Pool;
|
|||
*/
|
||||
public class QueuedPool<P> implements Pool<P>
|
||||
{
|
||||
// All code that uses these three fields is fully thread-safe.
|
||||
private final int maxSize;
|
||||
private final Queue<Entry<P>> queue = new ConcurrentLinkedQueue<>();
|
||||
private final AtomicInteger queueSize = new AtomicInteger();
|
||||
|
||||
// This lock protects the 'terminated' field.
|
||||
// Only the 'terminated' field is protected by the RW lock,
|
||||
// the other fields are totally ignored w.r.t the scope of this lock;
|
||||
// so when the read lock or the write lock is needed solely depends
|
||||
// on what is being done to the 'terminated' field.
|
||||
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
|
||||
private boolean terminated;
|
||||
|
||||
|
@ -56,7 +62,7 @@ public class QueuedPool<P> implements Pool<P>
|
|||
rwLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
if (terminated || queue.size() == maxSize)
|
||||
if (terminated || queueSize.get() == maxSize)
|
||||
return null;
|
||||
return new QueuedEntry<>(this);
|
||||
}
|
||||
|
@ -71,10 +77,16 @@ public class QueuedPool<P> implements Pool<P>
|
|||
rwLock.readLock().lock();
|
||||
try
|
||||
{
|
||||
if (terminated || queue.size() == maxSize)
|
||||
return false;
|
||||
queue.add(entry);
|
||||
return true;
|
||||
while (true)
|
||||
{
|
||||
int size = queueSize.get();
|
||||
if (terminated || size == maxSize)
|
||||
return false;
|
||||
if (!queueSize.compareAndSet(size, size + 1))
|
||||
continue;
|
||||
queue.add(entry);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -92,7 +104,10 @@ public class QueuedPool<P> implements Pool<P>
|
|||
return null;
|
||||
QueuedEntry<P> entry = (QueuedEntry<P>)queue.poll();
|
||||
if (entry != null)
|
||||
{
|
||||
queueSize.decrementAndGet();
|
||||
entry.acquire();
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
finally
|
||||
|
@ -121,9 +136,15 @@ public class QueuedPool<P> implements Pool<P>
|
|||
rwLock.writeLock().lock();
|
||||
try
|
||||
{
|
||||
// Once 'terminated' has been set to true, no entry can be
|
||||
// added nor removed from the queue; the setting to true
|
||||
// as well as the copy and the clearing of the queue MUST be
|
||||
// atomic otherwise we may not return the exact list of entries
|
||||
// that remained in the pool when terminate() was called.
|
||||
terminated = true;
|
||||
Collection<Entry<P>> copy = new ArrayList<>(queue);
|
||||
queue.clear();
|
||||
queueSize.set(0);
|
||||
return copy;
|
||||
}
|
||||
finally
|
||||
|
@ -135,7 +156,7 @@ public class QueuedPool<P> implements Pool<P>
|
|||
@Override
|
||||
public int size()
|
||||
{
|
||||
return queue.size();
|
||||
return queueSize.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -41,7 +41,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
public class CyclicTimeoutsTest
|
||||
{
|
||||
private Scheduler scheduler;
|
||||
private CyclicTimeouts<ConstantExpirable> timeouts;
|
||||
private CyclicTimeouts<CyclicTimeouts.Expirable> timeouts;
|
||||
|
||||
@BeforeEach
|
||||
public void prepare()
|
||||
|
@ -65,14 +65,14 @@ public class CyclicTimeoutsTest
|
|||
timeouts = new CyclicTimeouts<>(scheduler)
|
||||
{
|
||||
@Override
|
||||
protected Iterator<ConstantExpirable> iterator()
|
||||
protected Iterator<CyclicTimeouts.Expirable> iterator()
|
||||
{
|
||||
latch.countDown();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onExpired(ConstantExpirable expirable)
|
||||
protected boolean onExpired(CyclicTimeouts.Expirable expirable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -93,14 +93,14 @@ public class CyclicTimeoutsTest
|
|||
timeouts = new CyclicTimeouts<>(scheduler)
|
||||
{
|
||||
@Override
|
||||
protected Iterator<ConstantExpirable> iterator()
|
||||
protected Iterator<CyclicTimeouts.Expirable> iterator()
|
||||
{
|
||||
iteratorLatch.countDown();
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onExpired(ConstantExpirable expirable)
|
||||
protected boolean onExpired(CyclicTimeouts.Expirable expirable)
|
||||
{
|
||||
expiredLatch.countDown();
|
||||
return false;
|
||||
|
@ -118,22 +118,22 @@ public class CyclicTimeoutsTest
|
|||
public void testIterateAndExpire(boolean remove) throws Exception
|
||||
{
|
||||
ConstantExpirable zero = ConstantExpirable.ofDelay(0, TimeUnit.SECONDS);
|
||||
ConstantExpirable one = ConstantExpirable.ofDelay(1, TimeUnit.SECONDS);
|
||||
Collection<ConstantExpirable> collection = new ArrayList<>();
|
||||
DynamicExpirable one = new DynamicExpirable(NanoTime.now() + TimeUnit.SECONDS.toNanos(1));
|
||||
Collection<CyclicTimeouts.Expirable> collection = new ArrayList<>();
|
||||
collection.add(one);
|
||||
AtomicInteger iterations = new AtomicInteger();
|
||||
CountDownLatch expiredLatch = new CountDownLatch(1);
|
||||
timeouts = new CyclicTimeouts<>(scheduler)
|
||||
{
|
||||
@Override
|
||||
protected Iterator<ConstantExpirable> iterator()
|
||||
protected Iterator<CyclicTimeouts.Expirable> iterator()
|
||||
{
|
||||
iterations.incrementAndGet();
|
||||
return collection.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onExpired(ConstantExpirable expirable)
|
||||
protected boolean onExpired(CyclicTimeouts.Expirable expirable)
|
||||
{
|
||||
assertSame(one, expirable);
|
||||
expiredLatch.countDown();
|
||||
|
@ -169,22 +169,22 @@ public class CyclicTimeoutsTest
|
|||
long delayMs = 2000;
|
||||
ConstantExpirable two = ConstantExpirable.ofDelay(delayMs, TimeUnit.MILLISECONDS);
|
||||
ConstantExpirable overtake = ConstantExpirable.ofDelay(delayMs / 2, TimeUnit.MILLISECONDS);
|
||||
Collection<ConstantExpirable> collection = new ArrayList<>();
|
||||
Collection<CyclicTimeouts.Expirable> collection = new ArrayList<>();
|
||||
collection.add(two);
|
||||
CountDownLatch expiredLatch = new CountDownLatch(2);
|
||||
List<ConstantExpirable> expired = new ArrayList<>();
|
||||
List<CyclicTimeouts.Expirable> expired = new ArrayList<>();
|
||||
timeouts = new CyclicTimeouts<>(scheduler)
|
||||
{
|
||||
private final AtomicBoolean overtakeScheduled = new AtomicBoolean();
|
||||
|
||||
@Override
|
||||
protected Iterator<ConstantExpirable> iterator()
|
||||
protected Iterator<CyclicTimeouts.Expirable> iterator()
|
||||
{
|
||||
return collection.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onExpired(ConstantExpirable expirable)
|
||||
protected boolean onExpired(CyclicTimeouts.Expirable expirable)
|
||||
{
|
||||
expired.add(expirable);
|
||||
expiredLatch.countDown();
|
||||
|
@ -220,6 +220,39 @@ public class CyclicTimeoutsTest
|
|||
assertSame(two, expired.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDynamicExpirableEntityIsNotifiedMultipleTimes() throws Exception
|
||||
{
|
||||
long delay = 500;
|
||||
DynamicExpirable entity = new DynamicExpirable(NanoTime.now() + TimeUnit.MILLISECONDS.toNanos(delay));
|
||||
List<CyclicTimeouts.Expirable> entities = List.of(entity);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(2);
|
||||
timeouts = new CyclicTimeouts<>(scheduler)
|
||||
{
|
||||
@Override
|
||||
protected Iterator<CyclicTimeouts.Expirable> iterator()
|
||||
{
|
||||
return entities.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onExpired(CyclicTimeouts.Expirable expirable)
|
||||
{
|
||||
assertSame(entity, expirable);
|
||||
// Postpone expiration.
|
||||
entity.expireNanoTime = NanoTime.now() + TimeUnit.MILLISECONDS.toNanos(delay);
|
||||
latch.countDown();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Trigger the initial call to iterator().
|
||||
timeouts.schedule(entities.get(0));
|
||||
|
||||
assertTrue(latch.await(3 * delay, TimeUnit.MILLISECONDS), latch.toString());
|
||||
}
|
||||
|
||||
private static class ConstantExpirable implements CyclicTimeouts.Expirable
|
||||
{
|
||||
private static ConstantExpirable noExpire()
|
||||
|
@ -259,4 +292,26 @@ public class CyclicTimeoutsTest
|
|||
return String.format("%s@%x[%sms]", getClass().getSimpleName(), hashCode(), asString);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DynamicExpirable implements CyclicTimeouts.Expirable
|
||||
{
|
||||
private long expireNanoTime;
|
||||
|
||||
public DynamicExpirable(long expireNanoTime)
|
||||
{
|
||||
this.expireNanoTime = expireNanoTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getExpireNanoTime()
|
||||
{
|
||||
return expireNanoTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x[%dms]", getClass().getSimpleName(), hashCode(), NanoTime.millisUntil(expireNanoTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,10 +46,6 @@
|
|||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-ee</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-deploy</artifactId>
|
||||
|
|
|
@ -20,7 +20,7 @@ import java.util.Objects;
|
|||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.AppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.ee.Deployable;
|
||||
import org.eclipse.jetty.server.Deployable;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
|
|
@ -25,8 +25,8 @@ import java.util.Objects;
|
|||
import org.eclipse.jetty.deploy.App;
|
||||
import org.eclipse.jetty.deploy.AppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.ee.Deployable;
|
||||
import org.eclipse.jetty.osgi.util.BundleFileLocatorHelperFactory;
|
||||
import org.eclipse.jetty.server.Deployable;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
|
|
|
@ -133,6 +133,8 @@ public class ServerQuicConnection extends QuicConnection
|
|||
protected boolean onExpired(ServerQuicSession session)
|
||||
{
|
||||
session.onIdleTimeout();
|
||||
// The implementation of the Iterator returned above does not support
|
||||
// removal, but the session will be removed by session.onIdleTimeout().
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ import org.eclipse.jetty.util.thread.Scheduler;
|
|||
public class ServerQuicSession extends QuicSession implements CyclicTimeouts.Expirable
|
||||
{
|
||||
private final Connector connector;
|
||||
private long expireNanoTime;
|
||||
private long expireNanoTime = Long.MAX_VALUE;
|
||||
|
||||
protected ServerQuicSession(Executor executor, Scheduler scheduler, ByteBufferPool bufferPool, QuicheConnection quicheConnection, QuicConnection connection, SocketAddress remoteAddress, Connector connector)
|
||||
{
|
||||
|
@ -103,6 +103,15 @@ public class ServerQuicSession extends QuicSession implements CyclicTimeouts.Exp
|
|||
getQuicConnection().schedule(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onIdleTimeout()
|
||||
{
|
||||
boolean result = super.onIdleTimeout();
|
||||
if (!result)
|
||||
notIdle();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Runnable process(SocketAddress remoteAddress, ByteBuffer cipherBufferIn) throws IOException
|
||||
{
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.eclipse.jetty.util.Callback;
|
|||
* cycles. Authentication might not yet be checked or it might be checked
|
||||
* and failed, checked and deferred or succeeded.
|
||||
*/
|
||||
public interface AuthenticationState
|
||||
public interface AuthenticationState extends Request.AuthenticationState
|
||||
{
|
||||
/**
|
||||
* Get the authentication state of a request
|
||||
|
@ -41,8 +41,8 @@ public interface AuthenticationState
|
|||
*/
|
||||
static AuthenticationState getAuthenticationState(Request request)
|
||||
{
|
||||
Object auth = request.getAttribute(AuthenticationState.class.getName());
|
||||
return auth instanceof AuthenticationState authenticationState ? authenticationState : null;
|
||||
Request.AuthenticationState state = Request.getAuthenticationState(request);
|
||||
return state instanceof AuthenticationState authenticationState ? authenticationState : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,7 +52,7 @@ public interface AuthenticationState
|
|||
*/
|
||||
static void setAuthenticationState(Request request, AuthenticationState authenticationState)
|
||||
{
|
||||
request.setAttribute(AuthenticationState.class.getName(), authenticationState);
|
||||
Request.setAuthenticationState(request, authenticationState);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -193,6 +193,15 @@ public interface AuthenticationState
|
|||
*/
|
||||
UserIdentity getUserIdentity();
|
||||
|
||||
@Override
|
||||
default Principal getUserPrincipal()
|
||||
{
|
||||
UserIdentity user = getUserIdentity();
|
||||
if (user != null)
|
||||
return user.getUserPrincipal();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param role The role to check.
|
||||
* @return True if the user is in the passed role
|
||||
|
|
|
@ -19,7 +19,6 @@ lib/jetty-server-${jetty.version}.jar
|
|||
lib/jetty-xml-${jetty.version}.jar
|
||||
lib/jetty-util-${jetty.version}.jar
|
||||
lib/jetty-io-${jetty.version}.jar
|
||||
lib/jetty-ee-${jetty.version}.jar
|
||||
|
||||
[xml]
|
||||
etc/jetty.xml
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.server;
|
||||
|
||||
/**
|
||||
* @deprecated {@link org.eclipse.jetty.util.component.ClassLoaderDump}
|
||||
*/
|
||||
@Deprecated
|
||||
public class ClassLoaderDump extends org.eclipse.jetty.util.component.ClassLoaderDump
|
||||
{
|
||||
public ClassLoaderDump(ClassLoader loader)
|
||||
{
|
||||
super(loader);
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ package org.eclipse.jetty.server;
|
|||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -33,6 +34,7 @@ import org.eclipse.jetty.http.HttpFields;
|
|||
import org.eclipse.jetty.http.QuotedCSV;
|
||||
import org.eclipse.jetty.http.pathmap.PathMappings;
|
||||
import org.eclipse.jetty.util.DateCache;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
|
@ -73,21 +75,18 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* <th>Format String</th>
|
||||
* <th>Description</th>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>X</td>
|
||||
* <td>
|
||||
* <p>The X character.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%%</td>
|
||||
* <td>
|
||||
* <p>The percent character.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{format}a</td>
|
||||
* <td>
|
||||
|
@ -99,7 +98,6 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* the end-user and the server.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{format}p</td>
|
||||
* <td>
|
||||
|
@ -111,7 +109,6 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* the end-user and the server.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{CLF}I</td>
|
||||
* <td>
|
||||
|
@ -121,7 +118,6 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* when no bytes are present.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{CLF}O</td>
|
||||
* <td>
|
||||
|
@ -131,7 +127,6 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* when no bytes are present.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{CLF}S</td>
|
||||
* <td>
|
||||
|
@ -141,7 +136,6 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* when no bytes are present.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{VARNAME}C</td>
|
||||
* <td>
|
||||
|
@ -151,42 +145,36 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* When the parameter is missing, all request cookies will be logged.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%D</td>
|
||||
* <td>
|
||||
* <p>The time taken to serve the request, in microseconds.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{VARNAME}e</td>
|
||||
* <td>
|
||||
* <p>The value of the environment variable VARNAME.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%f</td>
|
||||
* <td>
|
||||
* <p>The file system path of the requested resource.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%H</td>
|
||||
* <td>
|
||||
* <p>The name and version of the request protocol, such as "HTTP/1.1".</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{VARNAME}i</td>
|
||||
* <td>
|
||||
* <p>The value of the VARNAME request header.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%k</td>
|
||||
* <td>
|
||||
|
@ -195,28 +183,24 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* yields the value 1, the second request on the same connection yields the value 2, etc.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%m</td>
|
||||
* <td>
|
||||
* <p>The HTTP request method.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{VARNAME}o</td>
|
||||
* <td>
|
||||
* <p>The value of the VARNAME response header.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%q</td>
|
||||
* <td>
|
||||
* <p>The query string, prepended with a ? if a query string exists, otherwise an empty string.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <!-- TODO ATTRIBUTE LOGGING -->
|
||||
* <tr>
|
||||
* <td>%r</td>
|
||||
|
@ -224,22 +208,19 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* <p>First line of an HTTP/1.1 request (or equivalent information for HTTP/2 or later).</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%R</td>
|
||||
* <td>
|
||||
* <p>The name of the Handler or Servlet generating the response (if any).</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <tr>
|
||||
* <td>%s</td>
|
||||
* <td>
|
||||
* <p>The HTTP response status code.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <tr>
|
||||
* <td>%{format|timeZone|locale}t</td>
|
||||
* <td>
|
||||
* <p>The time at which the request was received.</p>
|
||||
|
@ -257,7 +238,6 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* </dl>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{UNIT}T</td>
|
||||
* <td>
|
||||
|
@ -267,7 +247,6 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* <code>%{us}T</code> is identical to {@code %D}.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{d}u</td>
|
||||
* <td>
|
||||
|
@ -277,15 +256,13 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* When the parameter value is "d", deferred authentication will also be checked.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%U</td>
|
||||
* <td>
|
||||
* <p>The URL path requested, not including any query string.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <tr>
|
||||
* <td>%X</td>
|
||||
* <td>
|
||||
* <p>The connection status when response is completed:</p>
|
||||
|
@ -299,14 +276,12 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
* </dl>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{VARNAME}ti</td>
|
||||
* <td>
|
||||
* <p>The value of the VARNAME request trailer.</p>
|
||||
* </td>
|
||||
* </tr>
|
||||
*
|
||||
* <tr>
|
||||
* <td>%{VARNAME}to</td>
|
||||
* <td>
|
||||
|
@ -319,12 +294,19 @@ import static java.lang.invoke.MethodType.methodType;
|
|||
@ManagedObject("Custom format request log")
|
||||
public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
||||
{
|
||||
/**
|
||||
* Record holding extra detail for logging
|
||||
* @param handlerName The name of the entity that handled the request
|
||||
* @param realPath The real path on the filesystem represented by the request
|
||||
*/
|
||||
public record LogDetail(String handlerName, String realPath)
|
||||
{
|
||||
}
|
||||
|
||||
public static final String DEFAULT_DATE_FORMAT = "dd/MMM/yyyy:HH:mm:ss ZZZ";
|
||||
public static final String NCSA_FORMAT = "%{client}a - %u %t \"%r\" %s %O";
|
||||
public static final String EXTENDED_NCSA_FORMAT = NCSA_FORMAT + " \"%{Referer}i\" \"%{User-Agent}i\"";
|
||||
public static final String HANDLER_NAME = CustomRequestLog.class.getName() + ".handlerName";
|
||||
public static final String REAL_PATH = CustomRequestLog.class.getName() + ".realPath";
|
||||
public static final String USER_NAME = CustomRequestLog.class.getName() + ".userPrincipal";
|
||||
public static final String LOG_DETAIL = CustomRequestLog.class.getName() + ".logDetail";
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CustomRequestLog.class);
|
||||
private static final ThreadLocal<StringBuilder> _buffers = ThreadLocal.withInitial(() -> new StringBuilder(256));
|
||||
|
||||
|
@ -620,81 +602,42 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
MethodType logTypeArg = methodType(void.class, String.class, StringBuilder.class, Request.class, Response.class);
|
||||
|
||||
//TODO should we throw IllegalArgumentExceptions when given arguments for codes which do not take them
|
||||
MethodHandle specificHandle;
|
||||
switch (code)
|
||||
MethodHandle specificHandle = switch (code)
|
||||
{
|
||||
case "%":
|
||||
{
|
||||
specificHandle = dropArguments(dropArguments(append.bindTo("%"), 1, Request.class), 2, Response.class);
|
||||
break;
|
||||
}
|
||||
|
||||
case "a":
|
||||
case "%" -> dropArguments(dropArguments(append.bindTo("%"), 1, Request.class), 2, Response.class);
|
||||
case "a" ->
|
||||
{
|
||||
if (StringUtil.isEmpty(arg))
|
||||
arg = "server";
|
||||
|
||||
String method;
|
||||
switch (arg)
|
||||
String method = switch (arg)
|
||||
{
|
||||
case "server":
|
||||
method = "logServerHost";
|
||||
break;
|
||||
case "server" -> "logServerHost";
|
||||
case "client" -> "logClientHost";
|
||||
case "local" -> "logLocalHost";
|
||||
case "remote" -> "logRemoteHost";
|
||||
default -> throw new IllegalArgumentException("Invalid arg for %a");
|
||||
};
|
||||
|
||||
case "client":
|
||||
method = "logClientHost";
|
||||
break;
|
||||
|
||||
case "local":
|
||||
method = "logLocalHost";
|
||||
break;
|
||||
|
||||
case "remote":
|
||||
method = "logRemoteHost";
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid arg for %a");
|
||||
}
|
||||
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, method, logType);
|
||||
break;
|
||||
yield lookup.findStatic(CustomRequestLog.class, method, logType);
|
||||
}
|
||||
|
||||
case "p":
|
||||
case "p" ->
|
||||
{
|
||||
if (StringUtil.isEmpty(arg))
|
||||
arg = "server";
|
||||
|
||||
String method;
|
||||
switch (arg)
|
||||
String method = switch (arg)
|
||||
{
|
||||
case "server" -> "logServerPort";
|
||||
case "client" -> "logClientPort";
|
||||
case "local" -> "logLocalPort";
|
||||
case "remote" -> "logRemotePort";
|
||||
default -> throw new IllegalArgumentException("Invalid arg for %p");
|
||||
};
|
||||
|
||||
case "server":
|
||||
method = "logServerPort";
|
||||
break;
|
||||
|
||||
case "client":
|
||||
method = "logClientPort";
|
||||
break;
|
||||
|
||||
case "local":
|
||||
method = "logLocalPort";
|
||||
break;
|
||||
|
||||
case "remote":
|
||||
method = "logRemotePort";
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid arg for %p");
|
||||
}
|
||||
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, method, logType);
|
||||
break;
|
||||
yield lookup.findStatic(CustomRequestLog.class, method, logType);
|
||||
}
|
||||
|
||||
case "I":
|
||||
case "I" ->
|
||||
{
|
||||
String method;
|
||||
if (StringUtil.isEmpty(arg))
|
||||
|
@ -704,11 +647,9 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
else
|
||||
throw new IllegalArgumentException("Invalid argument for %I");
|
||||
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, method, logType);
|
||||
break;
|
||||
yield lookup.findStatic(CustomRequestLog.class, method, logType);
|
||||
}
|
||||
|
||||
case "O":
|
||||
case "O" ->
|
||||
{
|
||||
String method;
|
||||
if (StringUtil.isEmpty(arg))
|
||||
|
@ -718,11 +659,9 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
else
|
||||
throw new IllegalArgumentException("Invalid argument for %O");
|
||||
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, method, logType);
|
||||
break;
|
||||
yield lookup.findStatic(CustomRequestLog.class, method, logType);
|
||||
}
|
||||
|
||||
case "S":
|
||||
case "S" ->
|
||||
{
|
||||
String method;
|
||||
if (StringUtil.isEmpty(arg))
|
||||
|
@ -732,109 +671,49 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
else
|
||||
throw new IllegalArgumentException("Invalid argument for %S");
|
||||
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, method, logType);
|
||||
break;
|
||||
yield lookup.findStatic(CustomRequestLog.class, method, logType);
|
||||
}
|
||||
|
||||
case "C":
|
||||
case "C" ->
|
||||
{
|
||||
if (StringUtil.isEmpty(arg))
|
||||
{
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logRequestCookies", logType);
|
||||
yield lookup.findStatic(CustomRequestLog.class, "logRequestCookies", logType);
|
||||
}
|
||||
else
|
||||
{
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logRequestCookie", logTypeArg);
|
||||
specificHandle = specificHandle.bindTo(arg);
|
||||
yield lookup.findStatic(CustomRequestLog.class, "logRequestCookie", logTypeArg).bindTo(arg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "D":
|
||||
{
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logLatencyMicroseconds", logType);
|
||||
break;
|
||||
}
|
||||
|
||||
case "e":
|
||||
case "D" -> lookup.findStatic(CustomRequestLog.class, "logLatencyMicroseconds", logType);
|
||||
case "e" ->
|
||||
{
|
||||
if (StringUtil.isEmpty(arg))
|
||||
throw new IllegalArgumentException("No arg for %e");
|
||||
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logEnvironmentVar", logTypeArg);
|
||||
specificHandle = specificHandle.bindTo(arg);
|
||||
break;
|
||||
yield lookup.findStatic(CustomRequestLog.class, "logEnvironmentVar", logTypeArg).bindTo(arg);
|
||||
}
|
||||
|
||||
case "f":
|
||||
{
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logFilename", logType);
|
||||
break;
|
||||
}
|
||||
|
||||
case "H":
|
||||
{
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logRequestProtocol", logType);
|
||||
break;
|
||||
}
|
||||
|
||||
case "i":
|
||||
case "f" -> lookup.findStatic(CustomRequestLog.class, "logFilename", logType);
|
||||
case "H" -> lookup.findStatic(CustomRequestLog.class, "logRequestProtocol", logType);
|
||||
case "i" ->
|
||||
{
|
||||
if (StringUtil.isEmpty(arg))
|
||||
throw new IllegalArgumentException("No arg for %i");
|
||||
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logRequestHeader", logTypeArg);
|
||||
specificHandle = specificHandle.bindTo(arg);
|
||||
break;
|
||||
yield lookup.findStatic(CustomRequestLog.class, "logRequestHeader", logTypeArg).bindTo(arg);
|
||||
}
|
||||
|
||||
case "k":
|
||||
{
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logKeepAliveRequests", logType);
|
||||
break;
|
||||
}
|
||||
|
||||
case "m":
|
||||
{
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logRequestMethod", logType);
|
||||
break;
|
||||
}
|
||||
|
||||
case "o":
|
||||
case "k" -> lookup.findStatic(CustomRequestLog.class, "logKeepAliveRequests", logType);
|
||||
case "m" -> lookup.findStatic(CustomRequestLog.class, "logRequestMethod", logType);
|
||||
case "o" ->
|
||||
{
|
||||
if (StringUtil.isEmpty(arg))
|
||||
throw new IllegalArgumentException("No arg for %o");
|
||||
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logResponseHeader", logTypeArg);
|
||||
specificHandle = specificHandle.bindTo(arg);
|
||||
break;
|
||||
yield lookup.findStatic(CustomRequestLog.class, "logResponseHeader", logTypeArg).bindTo(arg);
|
||||
}
|
||||
|
||||
case "q":
|
||||
{
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logQueryString", logType);
|
||||
break;
|
||||
}
|
||||
|
||||
case "r":
|
||||
{
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logRequestFirstLine", logType);
|
||||
break;
|
||||
}
|
||||
|
||||
case "R":
|
||||
{
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logRequestHandler", logType);
|
||||
break;
|
||||
}
|
||||
|
||||
case "s":
|
||||
{
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logResponseStatus", logType);
|
||||
break;
|
||||
}
|
||||
|
||||
case "t":
|
||||
case "q" -> lookup.findStatic(CustomRequestLog.class, "logQueryString", logType);
|
||||
case "r" -> lookup.findStatic(CustomRequestLog.class, "logRequestFirstLine", logType);
|
||||
case "R" -> lookup.findStatic(CustomRequestLog.class, "logRequestHandler", logType);
|
||||
case "s" -> lookup.findStatic(CustomRequestLog.class, "logResponseStatus", logType);
|
||||
case "t" ->
|
||||
{
|
||||
String format = DEFAULT_DATE_FORMAT;
|
||||
TimeZone timeZone = TimeZone.getTimeZone("GMT");
|
||||
|
@ -845,60 +724,43 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
String[] args = arg.split("\\|");
|
||||
switch (args.length)
|
||||
{
|
||||
case 1:
|
||||
format = args[0];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 1 -> format = args[0];
|
||||
case 2 ->
|
||||
{
|
||||
format = args[0];
|
||||
timeZone = TimeZone.getTimeZone(args[1]);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
}
|
||||
case 3 ->
|
||||
{
|
||||
format = args[0];
|
||||
timeZone = TimeZone.getTimeZone(args[1]);
|
||||
locale = Locale.forLanguageTag(args[2]);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Too many \"|\" characters in %t");
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Too many \"|\" characters in %t");
|
||||
}
|
||||
}
|
||||
|
||||
DateCache logDateCache = new DateCache(format, locale, timeZone);
|
||||
|
||||
MethodType logTypeDateCache = methodType(void.class, DateCache.class, StringBuilder.class, Request.class, Response.class);
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logRequestTime", logTypeDateCache);
|
||||
specificHandle = specificHandle.bindTo(logDateCache);
|
||||
break;
|
||||
yield lookup.findStatic(CustomRequestLog.class, "logRequestTime", logTypeDateCache).bindTo(logDateCache);
|
||||
}
|
||||
|
||||
case "T":
|
||||
case "T" ->
|
||||
{
|
||||
if (arg == null)
|
||||
arg = "s";
|
||||
|
||||
String method;
|
||||
switch (arg)
|
||||
String method = switch (arg)
|
||||
{
|
||||
case "s":
|
||||
method = "logLatencySeconds";
|
||||
break;
|
||||
case "us":
|
||||
method = "logLatencyMicroseconds";
|
||||
break;
|
||||
case "ms":
|
||||
method = "logLatencyMilliseconds";
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid arg for %T");
|
||||
}
|
||||
case "s" -> "logLatencySeconds";
|
||||
case "us" -> "logLatencyMicroseconds";
|
||||
case "ms" -> "logLatencyMilliseconds";
|
||||
default -> throw new IllegalArgumentException("Invalid arg for %T");
|
||||
};
|
||||
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, method, logType);
|
||||
break;
|
||||
yield lookup.findStatic(CustomRequestLog.class, method, logType);
|
||||
}
|
||||
|
||||
case "u":
|
||||
case "u" ->
|
||||
{
|
||||
String method;
|
||||
if (StringUtil.isEmpty(arg))
|
||||
|
@ -908,45 +770,26 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
else
|
||||
throw new IllegalArgumentException("Invalid arg for %u: " + arg);
|
||||
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, method, logType);
|
||||
break;
|
||||
yield lookup.findStatic(CustomRequestLog.class, method, logType);
|
||||
}
|
||||
|
||||
case "U":
|
||||
{
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logUrlRequestPath", logType);
|
||||
break;
|
||||
}
|
||||
|
||||
case "X":
|
||||
{
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logConnectionStatus", logType);
|
||||
break;
|
||||
}
|
||||
|
||||
case "ti":
|
||||
case "U" -> lookup.findStatic(CustomRequestLog.class, "logUrlRequestPath", logType);
|
||||
case "X" -> lookup.findStatic(CustomRequestLog.class, "logConnectionStatus", logType);
|
||||
case "ti" ->
|
||||
{
|
||||
if (StringUtil.isEmpty(arg))
|
||||
throw new IllegalArgumentException("No arg for %ti");
|
||||
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logRequestTrailer", logTypeArg);
|
||||
specificHandle = specificHandle.bindTo(arg);
|
||||
break;
|
||||
yield lookup.findStatic(CustomRequestLog.class, "logRequestTrailer", logTypeArg).bindTo(arg);
|
||||
}
|
||||
|
||||
case "to":
|
||||
case "to" ->
|
||||
{
|
||||
if (StringUtil.isEmpty(arg))
|
||||
throw new IllegalArgumentException("No arg for %to");
|
||||
|
||||
specificHandle = lookup.findStatic(CustomRequestLog.class, "logResponseTrailer", logTypeArg);
|
||||
specificHandle = specificHandle.bindTo(arg);
|
||||
break;
|
||||
yield lookup.findStatic(CustomRequestLog.class, "logResponseTrailer", logTypeArg).bindTo(arg);
|
||||
}
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported code %" + code);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported code %" + code);
|
||||
};
|
||||
|
||||
if (modifiers != null && !modifiers.isEmpty())
|
||||
{
|
||||
|
@ -1132,8 +975,8 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
@SuppressWarnings("unused")
|
||||
private static void logFilename(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
String realPath = (String)request.getAttribute(REAL_PATH);
|
||||
if (realPath == null)
|
||||
LogDetail logDetail = (LogDetail)request.getAttribute(LOG_DETAIL);
|
||||
if (logDetail == null || logDetail.realPath == null)
|
||||
{
|
||||
Context context = request.getContext();
|
||||
Resource baseResource = context.getBaseResource();
|
||||
|
@ -1149,7 +992,7 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
}
|
||||
else
|
||||
{
|
||||
b.append(realPath);
|
||||
b.append(logDetail.realPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1206,7 +1049,8 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
@SuppressWarnings("unused")
|
||||
private static void logRequestHandler(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
append(b, (String)request.getAttribute(HANDLER_NAME));
|
||||
LogDetail logDetail = (LogDetail)request.getAttribute(LOG_DETAIL);
|
||||
append(b, logDetail == null ? null : logDetail.handlerName);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -1243,14 +1087,15 @@ public class CustomRequestLog extends ContainerLifeCycle implements RequestLog
|
|||
|
||||
private static void logLatency(StringBuilder b, Request request, TimeUnit unit)
|
||||
{
|
||||
long latency = System.currentTimeMillis() - request.getTimeStamp();
|
||||
b.append(unit.convert(latency, TimeUnit.MILLISECONDS));
|
||||
b.append(unit.convert(NanoTime.since(request.getNanoTime()), TimeUnit.NANOSECONDS));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static void logRequestAuthentication(StringBuilder b, Request request, Response response)
|
||||
{
|
||||
append(b, (String)request.getAttribute(USER_NAME));
|
||||
Request.AuthenticationState authenticationState = Request.getAuthenticationState(request);
|
||||
Principal userPrincipal = authenticationState == null ? null : authenticationState.getUserPrincipal();
|
||||
append(b, userPrincipal == null ? null : userPrincipal.getName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee;
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
|
@ -19,6 +19,10 @@ import java.util.function.Predicate;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Interface that can be implemented by ContextHandlers within Environments to allow configuration
|
||||
* to be passed from the DeploymentManager without dependencies on the Deployment module itself.
|
||||
*/
|
||||
public interface Deployable
|
||||
{
|
||||
Pattern EE_ENVIRONMENT_NAME_PATTERN = Pattern.compile("ee(\\d*)");
|
|
@ -1,279 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.server;
|
||||
|
||||
/**
|
||||
* A HttpChannel.Listener that holds a collection of
|
||||
* other HttpChannel.Listener instances that are efficiently
|
||||
* invoked without iteration.
|
||||
* @see AbstractConnector
|
||||
*/
|
||||
@Deprecated // TODO update or remove
|
||||
public class HttpChannelListeners // TODO ??? implements HttpChannel.Listener
|
||||
{
|
||||
/* TODO
|
||||
static final Logger LOG = LoggerFactory.getLogger(HttpChannelListeners.class);
|
||||
public static HttpChannel.Listener NOOP = new HttpChannel.Listener() {};
|
||||
|
||||
private final NotifyRequest onRequestBegin;
|
||||
private final NotifyRequest onBeforeDispatch;
|
||||
private final NotifyFailure onDispatchFailure;
|
||||
private final NotifyRequest onAfterDispatch;
|
||||
private final NotifyContent onRequestContent;
|
||||
private final NotifyRequest onRequestContentEnd;
|
||||
private final NotifyRequest onRequestTrailers;
|
||||
private final NotifyRequest onRequestEnd;
|
||||
private final NotifyFailure onRequestFailure;
|
||||
private final NotifyRequest onResponseBegin;
|
||||
private final NotifyRequest onResponseCommit;
|
||||
private final NotifyContent onResponseContent;
|
||||
private final NotifyRequest onResponseEnd;
|
||||
private final NotifyFailure onResponseFailure;
|
||||
private final NotifyRequest onComplete;
|
||||
|
||||
public HttpChannelListeners(Collection<HttpChannel.Listener> listeners)
|
||||
{
|
||||
try
|
||||
{
|
||||
NotifyRequest onRequestBegin = NotifyRequest.NOOP;
|
||||
NotifyRequest onBeforeDispatch = NotifyRequest.NOOP;
|
||||
NotifyFailure onDispatchFailure = NotifyFailure.NOOP;
|
||||
NotifyRequest onAfterDispatch = NotifyRequest.NOOP;
|
||||
NotifyContent onRequestContent = NotifyContent.NOOP;
|
||||
NotifyRequest onRequestContentEnd = NotifyRequest.NOOP;
|
||||
NotifyRequest onRequestTrailers = NotifyRequest.NOOP;
|
||||
NotifyRequest onRequestEnd = NotifyRequest.NOOP;
|
||||
NotifyFailure onRequestFailure = NotifyFailure.NOOP;
|
||||
NotifyRequest onResponseBegin = NotifyRequest.NOOP;
|
||||
NotifyRequest onResponseCommit = NotifyRequest.NOOP;
|
||||
NotifyContent onResponseContent = NotifyContent.NOOP;
|
||||
NotifyRequest onResponseEnd = NotifyRequest.NOOP;
|
||||
NotifyFailure onResponseFailure = NotifyFailure.NOOP;
|
||||
NotifyRequest onComplete = NotifyRequest.NOOP;
|
||||
|
||||
for (HttpChannel.Listener listener : listeners)
|
||||
{
|
||||
if (!listener.getClass().getMethod("onRequestBegin", Request.class).isDefault())
|
||||
onRequestBegin = combine(onRequestBegin, listener::onRequestBegin);
|
||||
if (!listener.getClass().getMethod("onBeforeDispatch", Request.class).isDefault())
|
||||
onBeforeDispatch = combine(onBeforeDispatch, listener::onBeforeDispatch);
|
||||
if (!listener.getClass().getMethod("onDispatchFailure", Request.class, Throwable.class).isDefault())
|
||||
onDispatchFailure = combine(onDispatchFailure, listener::onDispatchFailure);
|
||||
if (!listener.getClass().getMethod("onAfterDispatch", Request.class).isDefault())
|
||||
onAfterDispatch = combine(onAfterDispatch, listener::onAfterDispatch);
|
||||
if (!listener.getClass().getMethod("onRequestContent", Request.class, ByteBuffer.class).isDefault())
|
||||
onRequestContent = combine(onRequestContent, listener::onRequestContent);
|
||||
if (!listener.getClass().getMethod("onRequestContentEnd", Request.class).isDefault())
|
||||
onRequestContentEnd = combine(onRequestContentEnd, listener::onRequestContentEnd);
|
||||
if (!listener.getClass().getMethod("onRequestTrailers", Request.class).isDefault())
|
||||
onRequestTrailers = combine(onRequestTrailers, listener::onRequestTrailers);
|
||||
if (!listener.getClass().getMethod("onRequestEnd", Request.class).isDefault())
|
||||
onRequestEnd = combine(onRequestEnd, listener::onRequestEnd);
|
||||
if (!listener.getClass().getMethod("onRequestFailure", Request.class, Throwable.class).isDefault())
|
||||
onRequestFailure = combine(onRequestFailure, listener::onRequestFailure);
|
||||
if (!listener.getClass().getMethod("onResponseBegin", Request.class).isDefault())
|
||||
onResponseBegin = combine(onResponseBegin, listener::onResponseBegin);
|
||||
if (!listener.getClass().getMethod("onResponseCommit", Request.class).isDefault())
|
||||
onResponseCommit = combine(onResponseCommit, listener::onResponseCommit);
|
||||
if (!listener.getClass().getMethod("onResponseContent", Request.class, ByteBuffer.class).isDefault())
|
||||
onResponseContent = combine(onResponseContent, listener::onResponseContent);
|
||||
if (!listener.getClass().getMethod("onResponseEnd", Request.class).isDefault())
|
||||
onResponseEnd = combine(onResponseEnd, listener::onResponseEnd);
|
||||
if (!listener.getClass().getMethod("onResponseFailure", Request.class, Throwable.class).isDefault())
|
||||
onResponseFailure = combine(onResponseFailure, listener::onResponseFailure);
|
||||
if (!listener.getClass().getMethod("onComplete", Request.class).isDefault())
|
||||
onComplete = combine(onComplete, listener::onComplete);
|
||||
}
|
||||
|
||||
this.onRequestBegin = onRequestBegin;
|
||||
this.onBeforeDispatch = onBeforeDispatch;
|
||||
this.onDispatchFailure = onDispatchFailure;
|
||||
this.onAfterDispatch = onAfterDispatch;
|
||||
this.onRequestContent = onRequestContent;
|
||||
this.onRequestContentEnd = onRequestContentEnd;
|
||||
this.onRequestTrailers = onRequestTrailers;
|
||||
this.onRequestEnd = onRequestEnd;
|
||||
this.onRequestFailure = onRequestFailure;
|
||||
this.onResponseBegin = onResponseBegin;
|
||||
this.onResponseCommit = onResponseCommit;
|
||||
this.onResponseContent = onResponseContent;
|
||||
this.onResponseEnd = onResponseEnd;
|
||||
this.onResponseFailure = onResponseFailure;
|
||||
this.onComplete = onComplete;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestBegin(Request request)
|
||||
{
|
||||
onRequestBegin.onRequest(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBeforeDispatch(Request request)
|
||||
{
|
||||
onBeforeDispatch.onRequest(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDispatchFailure(Request request, Throwable failure)
|
||||
{
|
||||
onDispatchFailure.onFailure(request, failure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAfterDispatch(Request request)
|
||||
{
|
||||
onAfterDispatch.onRequest(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestContent(Request request, ByteBuffer content)
|
||||
{
|
||||
onRequestContent.onContent(request, content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestContentEnd(Request request)
|
||||
{
|
||||
onRequestContentEnd.onRequest(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestTrailers(Request request)
|
||||
{
|
||||
onRequestTrailers.onRequest(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestEnd(Request request)
|
||||
{
|
||||
onRequestEnd.onRequest(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestFailure(Request request, Throwable failure)
|
||||
{
|
||||
onRequestFailure.onFailure(request, failure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponseBegin(Request request)
|
||||
{
|
||||
onResponseBegin.onRequest(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponseCommit(Request request)
|
||||
{
|
||||
onResponseCommit.onRequest(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponseContent(Request request, ByteBuffer content)
|
||||
{
|
||||
onResponseContent.onContent(request, content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponseEnd(Request request)
|
||||
{
|
||||
onResponseEnd.onRequest(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponseFailure(Request request, Throwable failure)
|
||||
{
|
||||
onResponseFailure.onFailure(request, failure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(Request request)
|
||||
{
|
||||
onComplete.onRequest(request);
|
||||
}
|
||||
|
||||
private interface NotifyRequest
|
||||
{
|
||||
void onRequest(Request request);
|
||||
|
||||
NotifyRequest NOOP = request ->
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
private interface NotifyFailure
|
||||
{
|
||||
void onFailure(Request request, Throwable failure);
|
||||
|
||||
NotifyFailure NOOP = (request, failure) ->
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
private interface NotifyContent
|
||||
{
|
||||
void onContent(Request request, ByteBuffer content);
|
||||
|
||||
NotifyContent NOOP = (request, content) ->
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
private static NotifyRequest combine(NotifyRequest first, NotifyRequest second)
|
||||
{
|
||||
if (first == NotifyRequest.NOOP)
|
||||
return second;
|
||||
if (second == NotifyRequest.NOOP)
|
||||
return first;
|
||||
return request ->
|
||||
{
|
||||
first.onRequest(request);
|
||||
second.onRequest(request);
|
||||
};
|
||||
}
|
||||
|
||||
private static NotifyFailure combine(NotifyFailure first, NotifyFailure second)
|
||||
{
|
||||
if (first == NotifyFailure.NOOP)
|
||||
return second;
|
||||
if (second == NotifyFailure.NOOP)
|
||||
return first;
|
||||
return (request, throwable) ->
|
||||
{
|
||||
first.onFailure(request, throwable);
|
||||
second.onFailure(request, throwable);
|
||||
};
|
||||
}
|
||||
|
||||
private static NotifyContent combine(NotifyContent first, NotifyContent second)
|
||||
{
|
||||
if (first == NotifyContent.NOOP)
|
||||
return (request, content) -> second.onContent(request, content.slice());
|
||||
if (second == NotifyContent.NOOP)
|
||||
return (request, content) -> first.onContent(request, content.slice());
|
||||
return (request, content) ->
|
||||
{
|
||||
content = content.slice();
|
||||
first.onContent(request, content);
|
||||
second.onContent(request, content);
|
||||
};
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
|
@ -19,11 +19,13 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.http.CookieCompliance;
|
||||
import org.eclipse.jetty.http.HttpCookie;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.QuotedCSVParser;
|
||||
import org.eclipse.jetty.http.Syntax;
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.util.Index;
|
||||
|
@ -404,6 +406,52 @@ public final class HttpCookieUtils
|
|||
return oldPath.equals(newPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link HttpHeader#SET_COOKIE} field as a {@link HttpCookie}, either
|
||||
* by optimally checking for a {@link SetCookieHttpField} or by parsing
|
||||
* the value with {@link #parseSetCookie(String)}.
|
||||
* @param field The field
|
||||
* @return The field value as a {@link HttpCookie} or null if the field
|
||||
* is not a {@link HttpHeader#SET_COOKIE} or cannot be parsed.
|
||||
*/
|
||||
public static HttpCookie getSetCookie(HttpField field)
|
||||
{
|
||||
if (field == null || field.getHeader() != HttpHeader.SET_COOKIE)
|
||||
return null;
|
||||
if (field instanceof SetCookieHttpField setCookieHttpField)
|
||||
return setCookieHttpField.getHttpCookie();
|
||||
return parseSetCookie(field.getValue());
|
||||
}
|
||||
|
||||
public static HttpCookie parseSetCookie(String value)
|
||||
{
|
||||
AtomicReference<HttpCookie.Builder> builder = new AtomicReference<>();
|
||||
new QuotedCSVParser(false)
|
||||
{
|
||||
@Override
|
||||
protected void parsedParam(StringBuffer buffer, int valueLength, int paramName, int paramValue)
|
||||
{
|
||||
String name = buffer.substring(paramName, paramValue - 1);
|
||||
String value = buffer.substring(paramValue);
|
||||
HttpCookie.Builder b = builder.get();
|
||||
if (b == null)
|
||||
{
|
||||
b = HttpCookie.build(name, value);
|
||||
builder.set(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
b.attribute(name, value);
|
||||
}
|
||||
}
|
||||
}.addValue(value);
|
||||
|
||||
HttpCookie.Builder b = builder.get();
|
||||
if (b == null)
|
||||
return null;
|
||||
return b.build();
|
||||
}
|
||||
|
||||
private static void quoteIfNeededAndAppend(String text, StringBuilder builder)
|
||||
{
|
||||
if (isQuoteNeeded(text))
|
||||
|
@ -416,19 +464,32 @@ public final class HttpCookieUtils
|
|||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link HttpField} that holds an {@link HttpHeader#SET_COOKIE} as a
|
||||
* {@link HttpCookie} instance, delaying any value generation until
|
||||
* {@link #getValue()} is called.
|
||||
*/
|
||||
public static class SetCookieHttpField extends HttpField
|
||||
{
|
||||
private final HttpCookie _cookie;
|
||||
private final CookieCompliance _compliance;
|
||||
|
||||
public SetCookieHttpField(HttpCookie cookie, CookieCompliance compliance)
|
||||
{
|
||||
super(HttpHeader.SET_COOKIE, getSetCookie(cookie, compliance));
|
||||
super(HttpHeader.SET_COOKIE, HttpHeader.SET_COOKIE.asString(), null);
|
||||
this._cookie = cookie;
|
||||
_compliance = compliance;
|
||||
}
|
||||
|
||||
public HttpCookie getHttpCookie()
|
||||
{
|
||||
return _cookie;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue()
|
||||
{
|
||||
return getSetCookie(_cookie, _compliance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.net.InetSocketAddress;
|
|||
import java.net.SocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.Principal;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Function;
|
||||
|
@ -743,4 +744,39 @@ public interface Request extends Attributes, Content.Source
|
|||
.path(URIUtil.addPaths(getContextPath(request), newEncodedPathInContext))
|
||||
.asImmutable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param request The request to enquire.
|
||||
* @return the minimal {@link AuthenticationState} of the request, or null if no authentication in process.
|
||||
*/
|
||||
static AuthenticationState getAuthenticationState(Request request)
|
||||
{
|
||||
if (request.getAttribute(AuthenticationState.class.getName()) instanceof AuthenticationState authenticationState)
|
||||
return authenticationState;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param request The request to enquire.
|
||||
* @param state the {@link AuthenticationState} of the request, or null if no authentication in process.
|
||||
*/
|
||||
static void setAuthenticationState(Request request, AuthenticationState state)
|
||||
{
|
||||
request.setAttribute(AuthenticationState.class.getName(), state);
|
||||
}
|
||||
|
||||
/**
|
||||
* A minimal Authentication interface, primarily used for logging. It is implemented by the
|
||||
* {@code jetty-security} module's {@code AuthenticationState} to provide full authentication services.
|
||||
*/
|
||||
interface AuthenticationState
|
||||
{
|
||||
/**
|
||||
* @return The authenticated user {@link Principal}, or null if the Authentication is in a non-authenticated state.
|
||||
*/
|
||||
default Principal getUserPrincipal()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@ import org.eclipse.jetty.util.Uptime;
|
|||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.Name;
|
||||
import org.eclipse.jetty.util.component.AttributeContainerMap;
|
||||
import org.eclipse.jetty.util.component.ClassLoaderDump;
|
||||
import org.eclipse.jetty.util.component.DumpableAttributes;
|
||||
import org.eclipse.jetty.util.component.DumpableCollection;
|
||||
import org.eclipse.jetty.util.component.Environment;
|
||||
import org.eclipse.jetty.util.component.Graceful;
|
||||
|
@ -804,8 +806,10 @@ public class Server extends Handler.Wrapper implements Attributes
|
|||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
dumpObjects(out, indent, new org.eclipse.jetty.util.component.ClassLoaderDump(this.getClass().getClassLoader()),
|
||||
dumpObjects(out, indent,
|
||||
new ClassLoaderDump(this.getClass().getClassLoader()),
|
||||
new DumpableCollection("environments", Environment.getAll()),
|
||||
new DumpableAttributes("attributes", _attributes),
|
||||
FileSystemPool.INSTANCE);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ import java.util.EventListener;
|
|||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -53,8 +52,7 @@ import org.eclipse.jetty.util.TypeUtil;
|
|||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.component.ClassLoaderDump;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.component.Graceful;
|
||||
import org.eclipse.jetty.util.component.DumpableAttributes;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
|
@ -63,14 +61,8 @@ import org.eclipse.jetty.util.thread.Invocable;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ContextHandler extends Handler.Wrapper implements Attributes, Graceful, AliasCheck
|
||||
public class ContextHandler extends Handler.Wrapper implements Attributes, AliasCheck
|
||||
{
|
||||
// TODO where should the alias checking go?
|
||||
// TODO add protected paths to ServletContextHandler?
|
||||
// TODO what about ObjectFactory stuff
|
||||
// TODO what about a Context logger?
|
||||
// TODO init param stuff to ServletContextHandler
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ContextHandler.class);
|
||||
private static final ThreadLocal<Context> __context = new ThreadLocal<>();
|
||||
|
||||
|
@ -147,10 +139,9 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace
|
|||
public enum Availability
|
||||
{
|
||||
STOPPED, // stopped and can't be made unavailable nor shutdown
|
||||
STARTING, // starting inside of doStart. It may go to any of the next states.
|
||||
STARTING, // starting inside doStart. It may go to any of the next states.
|
||||
AVAILABLE, // running normally
|
||||
UNAVAILABLE, // Either a startup error or explicit call to setAvailable(false)
|
||||
SHUTDOWN, // graceful shutdown
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -281,8 +272,8 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace
|
|||
{
|
||||
dumpObjects(out, indent,
|
||||
new ClassLoaderDump(getClassLoader()),
|
||||
Dumpable.named("context " + this, _context),
|
||||
Dumpable.named("handler attributes " + this, _persistentAttributes));
|
||||
new DumpableAttributes("handler attributes", _persistentAttributes),
|
||||
new DumpableAttributes("attributes", _context));
|
||||
}
|
||||
|
||||
@ManagedAttribute(value = "Context")
|
||||
|
@ -583,29 +574,6 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this context is shutting down
|
||||
*/
|
||||
@ManagedAttribute("true for graceful shutdown, which allows existing requests to complete")
|
||||
public boolean isShutdown()
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set shutdown status. This field allows for graceful shutdown of a context. A started context may be put into non accepting state so that existing
|
||||
* requests can complete, but no new requests are accepted.
|
||||
*/
|
||||
@Override
|
||||
public CompletableFuture<Void> shutdown()
|
||||
{
|
||||
// TODO
|
||||
CompletableFuture<Void> completableFuture = new CompletableFuture<>();
|
||||
completableFuture.complete(null);
|
||||
return completableFuture;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false if this context is unavailable (sends 503)
|
||||
*/
|
||||
|
@ -651,15 +619,16 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace
|
|||
Availability availability = _availability.get();
|
||||
switch (availability)
|
||||
{
|
||||
case STARTING:
|
||||
case AVAILABLE:
|
||||
if (!_availability.compareAndSet(availability, Availability.UNAVAILABLE))
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case STARTING, AVAILABLE ->
|
||||
{
|
||||
if (_availability.compareAndSet(availability, Availability.UNAVAILABLE))
|
||||
return;
|
||||
}
|
||||
default ->
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1160,14 +1129,6 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace
|
|||
return (H)ContextHandler.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String name)
|
||||
{
|
||||
// TODO the Attributes.Layer is a little different to previous
|
||||
// behaviour. We need to verify if that is OK
|
||||
return super.getAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Request.Handler getErrorHandler()
|
||||
{
|
||||
|
|
|
@ -21,6 +21,8 @@ import org.eclipse.jetty.server.Handler;
|
|||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.CountingCallback;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.component.Graceful;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -32,17 +34,17 @@ public class GracefulHandler extends Handler.Wrapper implements Graceful
|
|||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(GracefulHandler.class);
|
||||
|
||||
private final LongAdder dispatchedStats = new LongAdder();
|
||||
private final Shutdown shutdown;
|
||||
private final LongAdder _requests = new LongAdder();
|
||||
private final Shutdown _shutdown;
|
||||
|
||||
public GracefulHandler()
|
||||
{
|
||||
shutdown = new Shutdown(this)
|
||||
_shutdown = new Shutdown(this)
|
||||
{
|
||||
@Override
|
||||
public boolean isShutdownDone()
|
||||
{
|
||||
long count = dispatchedStats.sum();
|
||||
long count = getCurrentRequestCount();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("isShutdownDone: count {}", count);
|
||||
return count == 0;
|
||||
|
@ -50,6 +52,12 @@ public class GracefulHandler extends Handler.Wrapper implements Graceful
|
|||
};
|
||||
}
|
||||
|
||||
@ManagedAttribute("number of requests being currently handled")
|
||||
public long getCurrentRequestCount()
|
||||
{
|
||||
return _requests.sum();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag indicating that Graceful shutdown has been initiated.
|
||||
*
|
||||
|
@ -59,7 +67,7 @@ public class GracefulHandler extends Handler.Wrapper implements Graceful
|
|||
@Override
|
||||
public boolean isShutdown()
|
||||
{
|
||||
return shutdown.isShutdown();
|
||||
return _shutdown.isShutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -86,18 +94,18 @@ public class GracefulHandler extends Handler.Wrapper implements Graceful
|
|||
{
|
||||
boolean handled = super.handle(request, response, shutdownCallback);
|
||||
if (!handled)
|
||||
shutdownCallback.decrement();
|
||||
shutdownCallback.completed();
|
||||
return handled;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
shutdownCallback.decrement();
|
||||
throw t;
|
||||
Response.writeError(request, response, shutdownCallback, t);
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (isShutdown())
|
||||
shutdown.check();
|
||||
_shutdown.check();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,43 +114,28 @@ public class GracefulHandler extends Handler.Wrapper implements Graceful
|
|||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Shutdown requested");
|
||||
return shutdown.shutdown();
|
||||
return _shutdown.shutdown();
|
||||
}
|
||||
|
||||
private class ShutdownTrackingCallback extends Callback.Nested
|
||||
private class ShutdownTrackingCallback extends CountingCallback
|
||||
{
|
||||
final Request request;
|
||||
final Response response;
|
||||
|
||||
public ShutdownTrackingCallback(Request request, Response response, Callback callback)
|
||||
{
|
||||
super(callback);
|
||||
super(callback, 1);
|
||||
this.request = request;
|
||||
this.response = response;
|
||||
dispatchedStats.increment();
|
||||
}
|
||||
|
||||
public void decrement()
|
||||
{
|
||||
dispatchedStats.decrement();
|
||||
_requests.increment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
public void completed()
|
||||
{
|
||||
decrement();
|
||||
super.failed(x);
|
||||
_requests.decrement();
|
||||
if (isShutdown())
|
||||
shutdown.check();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
decrement();
|
||||
super.succeeded();
|
||||
if (isShutdown())
|
||||
shutdown.check();
|
||||
_shutdown.check();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,22 +13,16 @@
|
|||
|
||||
package org.eclipse.jetty.server.internal;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpHeaderValue;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
// TODO: review whether it needs to override these many methods, as it may be enough to override iterator().
|
||||
public class ResponseHttpFields implements HttpFields.Mutable
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ResponseHttpFields.class);
|
||||
|
@ -85,52 +79,12 @@ public class ResponseHttpFields implements HttpFields.Mutable
|
|||
return _fields.asImmutable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable add(String name, String value)
|
||||
{
|
||||
return _committed.get() ? this : _fields.add(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable add(HttpHeader header, HttpHeaderValue value)
|
||||
{
|
||||
return _fields.add(header, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable add(HttpHeader header, String value)
|
||||
{
|
||||
return _committed.get() ? this : _fields.add(header, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable add(HttpField field)
|
||||
{
|
||||
return _committed.get() ? this : _fields.add(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable add(HttpFields fields)
|
||||
{
|
||||
return _committed.get() ? this : _fields.add(fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable addCSV(HttpHeader header, String... values)
|
||||
{
|
||||
return _committed.get() ? this : _fields.addCSV(header, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable addCSV(String name, String... values)
|
||||
{
|
||||
return _committed.get() ? this : _fields.addCSV(name, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable addDateField(String name, long date)
|
||||
{
|
||||
return _committed.get() ? this : _fields.addDateField(name, date);
|
||||
if (field != null && !_committed.get())
|
||||
_fields.add(field);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -231,109 +185,27 @@ public class ResponseHttpFields implements HttpFields.Mutable
|
|||
}
|
||||
|
||||
@Override
|
||||
public void set(HttpField httpField)
|
||||
public void set(HttpField field)
|
||||
{
|
||||
if (_committed.get())
|
||||
throw new UnsupportedOperationException("Read Only");
|
||||
i.set(httpField);
|
||||
if (field == null)
|
||||
i.remove();
|
||||
else
|
||||
i.set(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(HttpField httpField)
|
||||
public void add(HttpField field)
|
||||
{
|
||||
if (_committed.get())
|
||||
throw new UnsupportedOperationException("Read Only");
|
||||
i.add(httpField);
|
||||
if (field != null)
|
||||
i.add(field);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable put(HttpField field)
|
||||
{
|
||||
return _committed.get() ? this : _fields.put(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable put(String name, String value)
|
||||
{
|
||||
return _committed.get() ? this : _fields.put(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable put(HttpHeader header, HttpHeaderValue value)
|
||||
{
|
||||
return _committed.get() ? this : _fields.put(header, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable put(HttpHeader header, String value)
|
||||
{
|
||||
return _committed.get() ? this : _fields.put(header, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable put(String name, List<String> list)
|
||||
{
|
||||
return _committed.get() ? this : _fields.put(name, list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable putDate(HttpHeader name, long date)
|
||||
{
|
||||
return _committed.get() ? this : _fields.putDate(name, date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable putDate(String name, long date)
|
||||
{
|
||||
return _committed.get() ? this : _fields.putDate(name, date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable put(HttpHeader header, long value)
|
||||
{
|
||||
return _committed.get() ? this : _fields.put(header, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable put(String name, long value)
|
||||
{
|
||||
return _committed.get() ? this : _fields.put(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void computeField(HttpHeader header, BiFunction<HttpHeader, List<HttpField>, HttpField> computeFn)
|
||||
{
|
||||
if (!_committed.get())
|
||||
_fields.computeField(header, computeFn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void computeField(String name, BiFunction<String, List<HttpField>, HttpField> computeFn)
|
||||
{
|
||||
if (!_committed.get())
|
||||
_fields.computeField(name, computeFn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable remove(HttpHeader name)
|
||||
{
|
||||
return _committed.get() ? this : _fields.remove(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable remove(EnumSet<HttpHeader> fields)
|
||||
{
|
||||
return _committed.get() ? this : _fields.remove(fields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mutable remove(String name)
|
||||
{
|
||||
return _committed.get() ? this : _fields.remove(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.eclipse.jetty.io.QuietException;
|
|||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.DateCache;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -570,14 +571,14 @@ public class CustomRequestLogTest
|
|||
@ValueSource(strings = {"us", "ms", "s"})
|
||||
public void testLogLatency(String unit) throws Exception
|
||||
{
|
||||
long delay = 1000;
|
||||
long delay = 1500;
|
||||
AtomicLong requestTimeRef = new AtomicLong();
|
||||
start("%{" + unit + "}T", new SimpleHandler()
|
||||
{
|
||||
@Override
|
||||
public boolean handle(Request request, Response response, Callback callback) throws Exception
|
||||
{
|
||||
requestTimeRef.set(request.getTimeStamp());
|
||||
requestTimeRef.set(request.getNanoTime());
|
||||
Thread.sleep(delay);
|
||||
callback.succeeded();
|
||||
return true;
|
||||
|
@ -596,12 +597,13 @@ public class CustomRequestLogTest
|
|||
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
String log = _logs.poll(5, TimeUnit.SECONDS);
|
||||
assertNotNull(log);
|
||||
long lowerBound = requestTimeRef.get();
|
||||
long upperBound = System.currentTimeMillis();
|
||||
|
||||
long lowerBound = delay / 2;
|
||||
long upperBound = TimeUnit.MICROSECONDS.convert(NanoTime.since(requestTimeRef.get()), TimeUnit.NANOSECONDS);
|
||||
|
||||
long measuredDuration = Long.parseLong(log);
|
||||
long durationLowerBound = timeUnit.convert(delay, TimeUnit.MILLISECONDS);
|
||||
long durationUpperBound = timeUnit.convert(upperBound - lowerBound, TimeUnit.MILLISECONDS);
|
||||
long durationLowerBound = timeUnit.convert(lowerBound, TimeUnit.MILLISECONDS);
|
||||
long durationUpperBound = timeUnit.convert(upperBound, TimeUnit.MILLISECONDS);
|
||||
|
||||
assertThat(measuredDuration, greaterThanOrEqualTo(durationLowerBound));
|
||||
assertThat(measuredDuration, lessThanOrEqualTo(durationUpperBound));
|
||||
|
|
|
@ -52,12 +52,11 @@ public class GracefulHandlerTest
|
|||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(GracefulHandlerTest.class);
|
||||
private Server server;
|
||||
private ServerConnector connector;
|
||||
|
||||
public Server createServer(Handler handler) throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new ServerConnector(server, 1, 1);
|
||||
ServerConnector connector = new ServerConnector(server, 1, 1);
|
||||
connector.setIdleTimeout(10000);
|
||||
connector.setShutdownIdleTimeout(1000);
|
||||
connector.setPort(0);
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.eclipse.jetty.http.MimeTypes;
|
|||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.NanoTime;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -158,7 +159,6 @@ public class LargeHeaderTest
|
|||
output.flush();
|
||||
|
||||
String rawResponse = readResponse(client, 1, input);
|
||||
System.err.println(rawResponse);
|
||||
assertThat(rawResponse, containsString(" 500 "));
|
||||
}
|
||||
}
|
||||
|
@ -284,7 +284,11 @@ public class LargeHeaderTest
|
|||
output.write(rawRequest.formatted(count).getBytes(UTF_8));
|
||||
output.flush();
|
||||
|
||||
long start = NanoTime.now();
|
||||
String rawResponse = readResponse(client, count, input);
|
||||
if (NanoTime.secondsSince(start) >= 1)
|
||||
LOG.warn("X-Count: {} - Slow Response", count);
|
||||
|
||||
if (rawResponse.isEmpty())
|
||||
{
|
||||
LOG.warn("X-Count: {} - Empty Raw Response", count);
|
||||
|
|
|
@ -13,9 +13,15 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.util.ListIterator;
|
||||
|
||||
import org.eclipse.jetty.http.HttpCookie;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.HttpTester;
|
||||
import org.eclipse.jetty.io.Content;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
@ -23,6 +29,7 @@ import org.junit.jupiter.api.BeforeEach;
|
|||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
@ -53,7 +60,7 @@ public class ResponseTest
|
|||
server.setHandler(new Handler.Abstract()
|
||||
{
|
||||
@Override
|
||||
public boolean handle(Request request, Response response, Callback callback) throws Exception
|
||||
public boolean handle(Request request, Response response, Callback callback)
|
||||
{
|
||||
Response.sendRedirect(request, response, callback, "/somewhere/else");
|
||||
return true;
|
||||
|
@ -89,7 +96,7 @@ public class ResponseTest
|
|||
server.setHandler(new Handler.Abstract()
|
||||
{
|
||||
@Override
|
||||
public boolean handle(Request request, Response response, Callback callback) throws Exception
|
||||
public boolean handle(Request request, Response response, Callback callback)
|
||||
{
|
||||
Response.sendRedirect(request, response, callback, "/somewhere/else");
|
||||
return true;
|
||||
|
@ -123,7 +130,7 @@ public class ResponseTest
|
|||
server.setHandler(new Handler.Abstract()
|
||||
{
|
||||
@Override
|
||||
public boolean handle(Request request, Response response, Callback callback) throws Exception
|
||||
public boolean handle(Request request, Response response, Callback callback)
|
||||
{
|
||||
Response.sendRedirect(request, response, callback, "/somewhere/else");
|
||||
return true;
|
||||
|
@ -159,7 +166,7 @@ public class ResponseTest
|
|||
server.setHandler(new Handler.Abstract()
|
||||
{
|
||||
@Override
|
||||
public boolean handle(Request request, Response response, Callback callback) throws Exception
|
||||
public boolean handle(Request request, Response response, Callback callback)
|
||||
{
|
||||
Response.sendRedirect(request, response, callback, "/somewhere/else");
|
||||
return true;
|
||||
|
@ -186,4 +193,58 @@ public class ResponseTest
|
|||
assertEquals(HttpStatus.SEE_OTHER_303, response.getStatus());
|
||||
assertThat(response.get(HttpHeader.LOCATION), is("/somewhere/else"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpCookieProcessing() throws Exception
|
||||
{
|
||||
server.setHandler(new Handler.Abstract()
|
||||
{
|
||||
@Override
|
||||
public boolean handle(Request request, Response response, Callback callback)
|
||||
{
|
||||
request.addHttpStreamWrapper(httpStream -> new HttpStream.Wrapper(httpStream)
|
||||
{
|
||||
@Override
|
||||
public void prepareResponse(HttpFields.Mutable headers)
|
||||
{
|
||||
super.prepareResponse(headers);
|
||||
for (ListIterator<HttpField> i = headers.listIterator(); i.hasNext();)
|
||||
{
|
||||
HttpField field = i.next();
|
||||
if (field.getHeader() != HttpHeader.SET_COOKIE)
|
||||
continue;
|
||||
|
||||
HttpCookie cookie = HttpCookieUtils.getSetCookie(field);
|
||||
if (cookie == null)
|
||||
continue;
|
||||
|
||||
i.set(new HttpCookieUtils.SetCookieHttpField(
|
||||
HttpCookie.build(cookie)
|
||||
.domain("customized")
|
||||
.sameSite(HttpCookie.SameSite.LAX)
|
||||
.build(),
|
||||
request.getConnectionMetaData().getHttpConfiguration().getResponseCookieCompliance()));
|
||||
}
|
||||
}
|
||||
});
|
||||
response.setStatus(200);
|
||||
Response.addCookie(response, HttpCookie.from("name", "test1"));
|
||||
response.getHeaders().add(HttpHeader.SET_COOKIE, "other=test2; Domain=wrong; SameSite=wrong; Attr=x");
|
||||
Content.Sink.write(response, true, "OK", callback);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
server.start();
|
||||
|
||||
String request = """
|
||||
POST /path HTTP/1.0\r
|
||||
Host: hostname\r
|
||||
\r
|
||||
""";
|
||||
HttpTester.Response response = HttpTester.parseResponse(connector.getResponse(request));
|
||||
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
assertThat(response.getValuesList(HttpHeader.SET_COOKIE), containsInAnyOrder(
|
||||
"name=test1; Domain=customized; SameSite=Lax",
|
||||
"other=test2; Domain=customized; SameSite=Lax; Attr=x"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,20 +19,27 @@ import java.io.Writer;
|
|||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.awaitility.Awaitility;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.HttpTester;
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.http.MetaData;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.io.Content;
|
||||
import org.eclipse.jetty.io.QuietException;
|
||||
import org.eclipse.jetty.logging.StacklessLogging;
|
||||
import org.eclipse.jetty.server.ConnectionMetaData;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
|
@ -40,6 +47,7 @@ import org.eclipse.jetty.server.Context;
|
|||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.HttpChannel;
|
||||
import org.eclipse.jetty.server.HttpStream;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.MockConnectionMetaData;
|
||||
import org.eclipse.jetty.server.MockConnector;
|
||||
import org.eclipse.jetty.server.MockHttpStream;
|
||||
|
@ -52,6 +60,8 @@ import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
|||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.component.Graceful;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -891,4 +901,215 @@ public class ContextHandlerTest
|
|||
assertThat(r, sameInstance(request));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGraceful() throws Exception
|
||||
{
|
||||
// This is really just another test of GracefulHandler, but good to check it works inside of ContextHandler
|
||||
|
||||
CountDownLatch latch0 = new CountDownLatch(1);
|
||||
CountDownLatch latch1 = new CountDownLatch(1);
|
||||
|
||||
CountDownLatch requests = new CountDownLatch(7);
|
||||
|
||||
Handler handler = new Handler.Abstract()
|
||||
{
|
||||
@Override
|
||||
public boolean handle(Request request, Response response, Callback callback) throws Exception
|
||||
{
|
||||
requests.countDown();
|
||||
switch (request.getContext().getPathInContext(request.getHttpURI().getCanonicalPath()))
|
||||
{
|
||||
case "/ignore0" ->
|
||||
{
|
||||
try
|
||||
{
|
||||
latch0.await();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
case "/ignore1" ->
|
||||
{
|
||||
try
|
||||
{
|
||||
latch1.await();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
case "/ok0" ->
|
||||
{
|
||||
try
|
||||
{
|
||||
latch0.await();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
case "/ok1" ->
|
||||
{
|
||||
try
|
||||
{
|
||||
latch1.await();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
case "/fail0" ->
|
||||
{
|
||||
try
|
||||
{
|
||||
latch0.await();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
throw new QuietException.Exception("expected0");
|
||||
}
|
||||
|
||||
case "/fail1" ->
|
||||
{
|
||||
try
|
||||
{
|
||||
latch1.await();
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
callback.failed(new QuietException.Exception("expected1"));
|
||||
}
|
||||
|
||||
default ->
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
response.setStatus(HttpStatus.OK_200);
|
||||
callback.succeeded();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
_contextHandler.setHandler(handler);
|
||||
GracefulHandler gracefulHandler = new GracefulHandler();
|
||||
_contextHandler.insertHandler(gracefulHandler);
|
||||
LocalConnector connector = new LocalConnector(_server);
|
||||
_server.addConnector(connector);
|
||||
_server.start();
|
||||
|
||||
HttpTester.Response response = HttpTester.parseResponse(connector.getResponse("GET /ctx/ HTTP/1.0\r\n\r\n"));
|
||||
assertThat(response.getStatus(), is(HttpStatus.OK_200));
|
||||
|
||||
List<LocalConnector.LocalEndPoint> endPoints = new ArrayList<>();
|
||||
for (String target : new String[] {"/ignore", "/ok", "/fail"})
|
||||
{
|
||||
for (int batch = 0; batch <= 1; batch++)
|
||||
{
|
||||
LocalConnector.LocalEndPoint endPoint = connector.executeRequest("GET /ctx%s%d HTTP/1.0\r\n\r\n".formatted(target, batch));
|
||||
endPoints.add(endPoint);
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue(requests.await(10, TimeUnit.SECONDS));
|
||||
assertThat(gracefulHandler.getCurrentRequestCount(), is(6L));
|
||||
|
||||
CompletableFuture<Void> shutdown = Graceful.shutdown(_contextHandler);
|
||||
assertFalse(shutdown.isDone());
|
||||
assertThat(gracefulHandler.getCurrentRequestCount(), is(6L));
|
||||
|
||||
response = HttpTester.parseResponse(connector.getResponse("GET /ctx/ HTTP/1.0\r\n\r\n"));
|
||||
assertThat(response.getStatus(), is(HttpStatus.SERVICE_UNAVAILABLE_503));
|
||||
|
||||
latch0.countDown();
|
||||
|
||||
response = HttpTester.parseResponse(endPoints.get(0).getResponse());
|
||||
assertThat(response.getStatus(), is(HttpStatus.NOT_FOUND_404));
|
||||
response = HttpTester.parseResponse(endPoints.get(2).getResponse());
|
||||
assertThat(response.getStatus(), is(HttpStatus.OK_200));
|
||||
response = HttpTester.parseResponse(endPoints.get(4).getResponse());
|
||||
assertThat(response.getStatus(), is(HttpStatus.INTERNAL_SERVER_ERROR_500));
|
||||
|
||||
assertFalse(shutdown.isDone());
|
||||
Awaitility.waitAtMost(10, TimeUnit.SECONDS).until(() -> gracefulHandler.getCurrentRequestCount() == 3L);
|
||||
assertThat(gracefulHandler.getCurrentRequestCount(), is(3L));
|
||||
|
||||
latch1.countDown();
|
||||
|
||||
response = HttpTester.parseResponse(endPoints.get(1).getResponse());
|
||||
assertThat(response.getStatus(), is(HttpStatus.NOT_FOUND_404));
|
||||
response = HttpTester.parseResponse(endPoints.get(3).getResponse());
|
||||
assertThat(response.getStatus(), is(HttpStatus.OK_200));
|
||||
response = HttpTester.parseResponse(endPoints.get(5).getResponse());
|
||||
assertThat(response.getStatus(), is(HttpStatus.INTERNAL_SERVER_ERROR_500));
|
||||
|
||||
shutdown.get(10, TimeUnit.SECONDS);
|
||||
assertTrue(shutdown.isDone());
|
||||
assertThat(gracefulHandler.getCurrentRequestCount(), is(0L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContextDump() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
ContextHandler contextHandler = new ContextHandler("/ctx");
|
||||
server.setHandler(contextHandler);
|
||||
contextHandler.setHandler(new Handler.Abstract()
|
||||
{
|
||||
@Override
|
||||
public boolean handle(Request request, Response response, Callback callback) throws Exception
|
||||
{
|
||||
callback.succeeded();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "TestHandler";
|
||||
}
|
||||
});
|
||||
|
||||
contextHandler.setAttribute("name", "hidden");
|
||||
contextHandler.setAttribute("persistent1", "value1");
|
||||
contextHandler.setAttribute("persistent2", Dumpable.named("named", "value2"));
|
||||
|
||||
server.start();
|
||||
|
||||
contextHandler.getContext().setAttribute("name", "override");
|
||||
contextHandler.getContext().setAttribute("transient1", "value1");
|
||||
contextHandler.getContext().setAttribute("transient2", Dumpable.named("named", "value2"));
|
||||
|
||||
String dump = contextHandler.dump().replaceAll("\\r?\\n", "\n");
|
||||
assertThat(dump, containsString("oejsh.ContextHandler@"));
|
||||
String expected = """
|
||||
+> No ClassLoader
|
||||
+> handler attributes size=3
|
||||
| +> name: hidden
|
||||
| +> persistent1: value1
|
||||
| +> persistent2: named: value2
|
||||
+> attributes size=5
|
||||
+> name: override
|
||||
+> persistent1: value1
|
||||
+> persistent2: named: value2
|
||||
+> transient1: value1
|
||||
+> transient2: named: value2
|
||||
""";
|
||||
assertThat(dump, containsString(expected));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@ public abstract class AbstractSessionDataStoreTest
|
|||
|
||||
//create the SessionDataStore
|
||||
_sessionIdManager = new DefaultSessionIdManager(_server);
|
||||
_sessionIdManager.setWorkerName("");
|
||||
_server.addBean(_sessionIdManager, true);
|
||||
|
||||
_sessionManager = new TestableSessionManager();
|
||||
|
|
|
@ -54,7 +54,6 @@ public class JdbcTestHelper
|
|||
public static final String LAST_SAVE_COL = "lstime";
|
||||
public static final String MAP_COL = "mo";
|
||||
public static final String MAX_IDLE_COL = "mi";
|
||||
public static final String TABLE = "mysessions";
|
||||
public static final String ID_COL = "mysessionid";
|
||||
public static final String ACCESS_COL = "atime";
|
||||
public static final String CONTEXT_COL = "cpath";
|
||||
|
@ -94,12 +93,12 @@ public class JdbcTestHelper
|
|||
}
|
||||
}
|
||||
|
||||
public static void shutdown(String connectionUrl)
|
||||
public static void shutdown(String sessionTableName)
|
||||
throws Exception
|
||||
{
|
||||
try (Connection connection = getConnection())
|
||||
{
|
||||
connection.prepareStatement("truncate table " + TABLE).executeUpdate();
|
||||
connection.prepareStatement("truncate table " + sessionTableName).executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,24 +129,24 @@ public class JdbcTestHelper
|
|||
/**
|
||||
* @return a fresh JDBCSessionDataStoreFactory
|
||||
*/
|
||||
public static SessionDataStoreFactory newSessionDataStoreFactory()
|
||||
public static SessionDataStoreFactory newSessionDataStoreFactory(String sessionTableName)
|
||||
{
|
||||
return newSessionDataStoreFactory(buildDatabaseAdaptor());
|
||||
return newSessionDataStoreFactory(buildDatabaseAdaptor(), sessionTableName);
|
||||
}
|
||||
|
||||
public static SessionDataStoreFactory newSessionDataStoreFactory(DatabaseAdaptor da)
|
||||
public static SessionDataStoreFactory newSessionDataStoreFactory(DatabaseAdaptor da, String sessionTableName)
|
||||
{
|
||||
JDBCSessionDataStoreFactory factory = new JDBCSessionDataStoreFactory();
|
||||
factory.setDatabaseAdaptor(da);
|
||||
JDBCSessionDataStore.SessionTableSchema sessionTableSchema = newSessionTableSchema();
|
||||
JDBCSessionDataStore.SessionTableSchema sessionTableSchema = newSessionTableSchema(sessionTableName);
|
||||
factory.setSessionTableSchema(sessionTableSchema);
|
||||
return factory;
|
||||
}
|
||||
|
||||
public static JDBCSessionDataStore.SessionTableSchema newSessionTableSchema()
|
||||
public static JDBCSessionDataStore.SessionTableSchema newSessionTableSchema(String sessionTableName)
|
||||
{
|
||||
JDBCSessionDataStore.SessionTableSchema sessionTableSchema = new JDBCSessionDataStore.SessionTableSchema();
|
||||
sessionTableSchema.setTableName(TABLE);
|
||||
sessionTableSchema.setTableName(sessionTableName);
|
||||
sessionTableSchema.setIdColumn(ID_COL);
|
||||
sessionTableSchema.setAccessTimeColumn(ACCESS_COL);
|
||||
sessionTableSchema.setContextPathColumn(CONTEXT_COL);
|
||||
|
@ -162,10 +161,10 @@ public class JdbcTestHelper
|
|||
return sessionTableSchema;
|
||||
}
|
||||
|
||||
public static void prepareTables() throws SQLException
|
||||
public static void prepareTables(String sessionTableName) throws SQLException
|
||||
{
|
||||
DatabaseAdaptor da = buildDatabaseAdaptor();
|
||||
JDBCSessionDataStore.SessionTableSchema sessionTableSchema = newSessionTableSchema();
|
||||
JDBCSessionDataStore.SessionTableSchema sessionTableSchema = newSessionTableSchema(sessionTableName);
|
||||
sessionTableSchema.setDatabaseAdaptor(da);
|
||||
sessionTableSchema.prepareTables();
|
||||
}
|
||||
|
@ -199,13 +198,13 @@ public class JdbcTestHelper
|
|||
}
|
||||
}
|
||||
|
||||
public static boolean existsInSessionTable(String id, boolean verbose)
|
||||
public static boolean existsInSessionTable(String id, boolean verbose, String sessionTableName)
|
||||
throws Exception
|
||||
{
|
||||
try (Connection con = getConnection())
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement("select * from " +
|
||||
TABLE +
|
||||
sessionTableName +
|
||||
" where " + ID_COL + " = ?");
|
||||
statement.setString(1, id);
|
||||
ResultSet result = statement.executeQuery();
|
||||
|
@ -225,7 +224,7 @@ public class JdbcTestHelper
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static boolean checkSessionPersisted(SessionData data)
|
||||
public static boolean checkSessionPersisted(SessionData data, String sessionTableName)
|
||||
throws Exception
|
||||
{
|
||||
PreparedStatement statement = null;
|
||||
|
@ -233,7 +232,7 @@ public class JdbcTestHelper
|
|||
try (Connection con = getConnection())
|
||||
{
|
||||
statement = con.prepareStatement(
|
||||
"select * from " + TABLE +
|
||||
"select * from " + sessionTableName +
|
||||
" where " + ID_COL + " = ? and " + CONTEXT_COL +
|
||||
" = ? and virtualHost = ?");
|
||||
statement.setString(1, data.getId());
|
||||
|
@ -293,11 +292,11 @@ public class JdbcTestHelper
|
|||
return true;
|
||||
}
|
||||
|
||||
public static void insertSession(SessionData data) throws Exception
|
||||
public static void insertSession(SessionData data, String sessionTableName) throws Exception
|
||||
{
|
||||
try (Connection con = getConnection())
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement("insert into " + TABLE +
|
||||
PreparedStatement statement = con.prepareStatement("insert into " + sessionTableName +
|
||||
" (" + ID_COL + ", " + CONTEXT_COL + ", virtualHost, " + LAST_NODE_COL +
|
||||
", " + ACCESS_COL + ", " + LAST_ACCESS_COL + ", " + CREATE_COL + ", " + COOKIE_COL +
|
||||
", " + LAST_SAVE_COL + ", " + EXPIRY_COL + ", " + MAX_IDLE_COL + "," + MAP_COL + " ) " +
|
||||
|
@ -336,12 +335,12 @@ public class JdbcTestHelper
|
|||
public static void insertUnreadableSession(String id, String contextPath, String vhost,
|
||||
String lastNode, long created, long accessed,
|
||||
long lastAccessed, long maxIdle, long expiry,
|
||||
long cookieSet, long lastSaved)
|
||||
long cookieSet, long lastSaved, String sessionTableName)
|
||||
throws Exception
|
||||
{
|
||||
try (Connection con = getConnection())
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement("insert into " + TABLE +
|
||||
PreparedStatement statement = con.prepareStatement("insert into " + sessionTableName +
|
||||
" (" + ID_COL + ", " + CONTEXT_COL + ", virtualHost, " + LAST_NODE_COL +
|
||||
", " + ACCESS_COL + ", " + LAST_ACCESS_COL + ", " + CREATE_COL + ", " + COOKIE_COL +
|
||||
", " + LAST_SAVE_COL + ", " + EXPIRY_COL + ", " + MAX_IDLE_COL + "," + MAP_COL + " ) " +
|
||||
|
@ -368,13 +367,13 @@ public class JdbcTestHelper
|
|||
}
|
||||
}
|
||||
|
||||
public static Set<String> getSessionIds()
|
||||
public static Set<String> getSessionIds(String sessionTableName)
|
||||
throws Exception
|
||||
{
|
||||
HashSet<String> ids = new HashSet<>();
|
||||
try (Connection con = getConnection())
|
||||
{
|
||||
PreparedStatement statement = con.prepareStatement("select " + ID_COL + " from " + TABLE);
|
||||
PreparedStatement statement = con.prepareStatement("select " + ID_COL + " from " + sessionTableName);
|
||||
ResultSet result = statement.executeQuery();
|
||||
while (result.next())
|
||||
{
|
||||
|
|
|
@ -45,7 +45,6 @@ import org.eclipse.jetty.util.NanoTime;
|
|||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -181,7 +180,11 @@ public class HttpClientLoadTest extends AbstractTest
|
|||
{
|
||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||
// Choose a random destination
|
||||
String host = random.nextBoolean() ? "localhost" : "127.0.0.1";
|
||||
String host;
|
||||
if (transport == Transport.H3)
|
||||
host = "localhost";
|
||||
else
|
||||
host = random.nextBoolean() ? "localhost" : "127.0.0.1";
|
||||
// Choose a random method
|
||||
HttpMethod method = random.nextBoolean() ? HttpMethod.GET : HttpMethod.POST;
|
||||
|
||||
|
|
|
@ -673,6 +673,7 @@ public class HttpClientTest extends AbstractTest
|
|||
{
|
||||
assumeTrue(Net.isIpv6InterfaceAvailable());
|
||||
assumeTrue(transport != Transport.UNIX_DOMAIN);
|
||||
assumeTrue(transport != Transport.H3);
|
||||
|
||||
start(transport, new Handler.Abstract()
|
||||
{
|
||||
|
|
|
@ -64,63 +64,51 @@ public interface Attributes
|
|||
// TODO: change to getAttributeNames() once jetty-core is cleaned of servlet-api usages
|
||||
Set<String> getAttributeNameSet();
|
||||
|
||||
// TODO something better than this
|
||||
default Map<String, Object> asAttributeMap()
|
||||
{
|
||||
return new AbstractMap<>()
|
||||
{
|
||||
private final Set<String> _attributeNameSet = getAttributeNameSet();
|
||||
private final AbstractSet<Entry<String, Object>> _entrySet = new AbstractSet<>()
|
||||
{
|
||||
@Override
|
||||
public Iterator<Entry<String, Object>> iterator()
|
||||
{
|
||||
Iterator<String> names = _attributeNameSet.iterator();
|
||||
return new Iterator<>()
|
||||
{
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return names.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<String, Object> next()
|
||||
{
|
||||
String name = names.next();
|
||||
return new SimpleEntry<>(name, getAttribute(name));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
return _attributeNameSet.size();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
return _attributeNameSet.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<String, Object>> entrySet()
|
||||
{
|
||||
return new AbstractSet<>()
|
||||
{
|
||||
Iterator<String> names = getAttributeNameSet().iterator();
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<String, Object>> iterator()
|
||||
{
|
||||
return new Iterator<>()
|
||||
{
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return names.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entry<String, Object> next()
|
||||
{
|
||||
String name = names.next();
|
||||
return new Map.Entry<>()
|
||||
{
|
||||
@Override
|
||||
public String getKey()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue()
|
||||
{
|
||||
return getAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object setValue(Object value)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
return _entrySet;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
|
||||
/**
|
||||
* @deprecated use {@link Attributes.Lazy}
|
||||
* @deprecated use {@link Attributes.Mapped}
|
||||
*/
|
||||
@Deprecated
|
||||
public class AttributesMap implements Attributes, Dumpable
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
@ -172,6 +173,12 @@ public interface Callback extends Invocable
|
|||
{
|
||||
return invocationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Callback@%x{%s, %s,%s}".formatted(hashCode(), invocationType, success, failure);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -183,13 +190,7 @@ public interface Callback extends Invocable
|
|||
*/
|
||||
static Callback from(Runnable completed)
|
||||
{
|
||||
return new Completing()
|
||||
{
|
||||
public void completed()
|
||||
{
|
||||
completed.run();
|
||||
}
|
||||
};
|
||||
return from(Invocable.getInvocationType(completed), completed);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -202,13 +203,25 @@ public interface Callback extends Invocable
|
|||
*/
|
||||
static Callback from(InvocationType invocationType, Runnable completed)
|
||||
{
|
||||
return new Completing(invocationType)
|
||||
return new Completing()
|
||||
{
|
||||
@Override
|
||||
public void completed()
|
||||
{
|
||||
completed.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InvocationType getInvocationType()
|
||||
{
|
||||
return invocationType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Callback.Completing@%x{%s,%s}".formatted(hashCode(), invocationType, completed);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -309,81 +322,40 @@ public interface Callback extends Invocable
|
|||
*/
|
||||
static Callback from(Callback callback1, Callback callback2)
|
||||
{
|
||||
return new Callback()
|
||||
{
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
callback1.succeeded();
|
||||
callback2.succeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
callback1.failed(x);
|
||||
callback2.failed(x);
|
||||
}
|
||||
};
|
||||
return combine(callback1, callback2);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>A Callback implementation that calls the {@link #completed()} method when it either succeeds or fails.</p>
|
||||
*/
|
||||
class Completing implements Callback
|
||||
interface Completing extends Callback
|
||||
{
|
||||
private final InvocationType invocationType;
|
||||
|
||||
public Completing()
|
||||
{
|
||||
this(InvocationType.BLOCKING);
|
||||
}
|
||||
|
||||
public Completing(InvocationType invocationType)
|
||||
{
|
||||
this.invocationType = invocationType;
|
||||
}
|
||||
void completed();
|
||||
|
||||
@Override
|
||||
public void succeeded()
|
||||
default void succeeded()
|
||||
{
|
||||
completed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
default void failed(Throwable x)
|
||||
{
|
||||
completed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InvocationType getInvocationType()
|
||||
{
|
||||
return invocationType;
|
||||
}
|
||||
|
||||
public void completed()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nested Completing Callback that completes after
|
||||
* completing the nested callback
|
||||
*/
|
||||
class Nested extends Completing
|
||||
class Nested implements Completing
|
||||
{
|
||||
private final Callback callback;
|
||||
|
||||
public Nested(Callback callback)
|
||||
{
|
||||
super(Invocable.getInvocationType(callback));
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public Nested(Nested nested)
|
||||
{
|
||||
this(nested.callback);
|
||||
this.callback = Objects.requireNonNull(callback);
|
||||
}
|
||||
|
||||
public Callback getCallback()
|
||||
|
@ -391,6 +363,11 @@ public interface Callback extends Invocable
|
|||
return callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
|
@ -461,7 +438,7 @@ public interface Callback extends Invocable
|
|||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
if (x != t)
|
||||
if (ExceptionUtil.areNotAssociated(x, t))
|
||||
x.addSuppressed(t);
|
||||
}
|
||||
finally
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.util.component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.util.Attributes;
|
||||
|
||||
public class DumpableAttributes implements Dumpable
|
||||
{
|
||||
private final String _name;
|
||||
private final Attributes _attributes;
|
||||
|
||||
public DumpableAttributes(String name, Attributes attributes)
|
||||
{
|
||||
_name = name;
|
||||
_attributes = attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
Object[] array = _attributes.asAttributeMap().entrySet().stream()
|
||||
.sorted(Map.Entry.comparingByKey())
|
||||
.map(e -> Dumpable.named(e.getKey(), e.getValue())).toArray(Object[]::new);
|
||||
Dumpable.dumpObjects(out, indent, _name + " size=" + array.length, array);
|
||||
}
|
||||
}
|
|
@ -44,12 +44,6 @@ public class DumpableCollection implements Dumpable
|
|||
return new DumpableCollection(name, collection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dump()
|
||||
{
|
||||
return Dumpable.dump(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
|
@ -57,3 +51,4 @@ public class DumpableCollection implements Dumpable
|
|||
Dumpable.dumpObjects(out, indent, _name + " size=" + (array == null ? 0 : array.length), array);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ public interface Environment extends Attributes
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "%s@%s{%s}".formatted(TypeUtil.toShortName(this.getClass()), hashCode(), _name);
|
||||
return "%s@%x{%s}".formatted(TypeUtil.toShortName(this.getClass()), hashCode(), _name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,11 @@ public interface Graceful
|
|||
done.complete(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be called after {@link #shutdown()} has been called, but before
|
||||
* {@link #check()} has been called with {@link #isShutdownDone()} having returned
|
||||
* true to cancel the effects of the {@link #shutdown()} call.
|
||||
*/
|
||||
public void cancel()
|
||||
{
|
||||
CompletableFuture<Void> done = _done.get();
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.util.component;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class GracefulShutdownTest
|
||||
{
|
||||
@Test
|
||||
public void testGracefulShutdown() throws Exception
|
||||
{
|
||||
AtomicBoolean isShutdown = new AtomicBoolean();
|
||||
Graceful.Shutdown shutdown = new Graceful.Shutdown("testGracefulShutdown")
|
||||
{
|
||||
@Override
|
||||
public boolean isShutdownDone()
|
||||
{
|
||||
return isShutdown.get();
|
||||
}
|
||||
};
|
||||
|
||||
assertThat(shutdown.isShutdown(), is(false));
|
||||
|
||||
shutdown.check();
|
||||
assertThat(shutdown.isShutdown(), is(false));
|
||||
|
||||
CompletableFuture<Void> cf = shutdown.shutdown();
|
||||
assertThat(shutdown.isShutdown(), is(true));
|
||||
shutdown.check();
|
||||
assertThat(shutdown.isShutdown(), is(true));
|
||||
|
||||
assertThrows(TimeoutException.class, () -> cf.get(10, TimeUnit.MILLISECONDS));
|
||||
|
||||
isShutdown.set(true);
|
||||
shutdown.check();
|
||||
assertThat(shutdown.isShutdown(), is(true));
|
||||
assertThat(cf.get(), nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGracefulShutdownCancel() throws Exception
|
||||
{
|
||||
AtomicBoolean isShutdown = new AtomicBoolean();
|
||||
Graceful.Shutdown shutdown = new Graceful.Shutdown("testGracefulShutdownCancel")
|
||||
{
|
||||
@Override
|
||||
public boolean isShutdownDone()
|
||||
{
|
||||
return isShutdown.get();
|
||||
}
|
||||
};
|
||||
|
||||
CompletableFuture<Void> cf1 = shutdown.shutdown();
|
||||
shutdown.cancel();
|
||||
assertThat(shutdown.isShutdown(), is(false));
|
||||
assertThrows(CancellationException.class, cf1::get);
|
||||
|
||||
CompletableFuture<Void> cf2 = shutdown.shutdown();
|
||||
assertThat(shutdown.isShutdown(), is(true));
|
||||
isShutdown.set(true);
|
||||
assertThrows(TimeoutException.class, () -> cf2.get(10, TimeUnit.MILLISECONDS));
|
||||
shutdown.check();
|
||||
assertThat(shutdown.isShutdown(), is(true));
|
||||
assertThat(cf2.get(), nullValue());
|
||||
}
|
||||
}
|
|
@ -17,7 +17,6 @@
|
|||
<module>jetty-client</module>
|
||||
<module>jetty-deploy</module>
|
||||
<module>jetty-demos</module>
|
||||
<module>jetty-ee</module>
|
||||
<module>jetty-fcgi</module>
|
||||
<module>jetty-http</module>
|
||||
<module>jetty-http2</module>
|
||||
|
|
|
@ -15,8 +15,8 @@ package org.eclipse.jetty.ee10.annotations;
|
|||
|
||||
import jakarta.annotation.security.DeclareRoles;
|
||||
import jakarta.servlet.Servlet;
|
||||
import org.eclipse.jetty.ee.security.ConstraintAware;
|
||||
import org.eclipse.jetty.ee10.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintAware;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
import org.slf4j.Logger;
|
||||
|
|
|
@ -18,11 +18,11 @@ import java.util.List;
|
|||
|
||||
import jakarta.servlet.ServletSecurityElement;
|
||||
import jakarta.servlet.annotation.ServletSecurity;
|
||||
import org.eclipse.jetty.ee.security.ConstraintAware;
|
||||
import org.eclipse.jetty.ee.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintAware;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
import org.slf4j.Logger;
|
||||
|
|
|
@ -21,10 +21,10 @@ import jakarta.servlet.annotation.ServletSecurity;
|
|||
import jakarta.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
|
||||
import jakarta.servlet.annotation.ServletSecurity.TransportGuarantee;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import org.eclipse.jetty.ee.security.ConstraintAware;
|
||||
import org.eclipse.jetty.ee.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintAware;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.security.Constraint;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<body>
|
||||
<div class="topnav">
|
||||
<a class="menu" href="http://localhost:8080/">Demo Home</a>
|
||||
<a class="menu" href="https://github.com/eclipse/jetty.project/tree/jetty-11.0.x/demos/demo-async-rest">Source</a>
|
||||
<a class="menu" href="https://github.com/eclipse/jetty.project/tree/jetty-12.0.x/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-async-rest">Source</a>
|
||||
<a class="menu" href="https://www.eclipse.org/jetty/">Jetty Project Home</a>
|
||||
<a class="menu" href="https://www.eclipse.org/jetty/documentation/current/">Documentation</a>
|
||||
<a class="menu" href="https://webtide.com">Commercial Support</a>
|
||||
|
|
|
@ -22,7 +22,6 @@ import java.nio.file.Paths;
|
|||
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.deploy.providers.ContextProvider;
|
||||
import org.eclipse.jetty.ee.Deployable;
|
||||
import org.eclipse.jetty.ee10.annotations.AnnotationConfiguration;
|
||||
import org.eclipse.jetty.ee10.plus.webapp.EnvConfiguration;
|
||||
import org.eclipse.jetty.ee10.plus.webapp.PlusConfiguration;
|
||||
|
@ -36,6 +35,7 @@ import org.eclipse.jetty.rewrite.handler.RewriteHandler;
|
|||
import org.eclipse.jetty.security.HashLoginService;
|
||||
import org.eclipse.jetty.server.AsyncRequestLogWriter;
|
||||
import org.eclipse.jetty.server.CustomRequestLog;
|
||||
import org.eclipse.jetty.server.Deployable;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
import org.eclipse.jetty.server.LowResourceMonitor;
|
||||
|
|
|
@ -16,9 +16,9 @@ package org.eclipse.jetty.ee10.demos;
|
|||
import java.io.FileNotFoundException;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.eclipse.jetty.ee.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.Constraint;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<body>
|
||||
<div class="topnav">
|
||||
<a class="menu" href="http://localhost:8080/">Demo Home</a>
|
||||
<a class="menu" href="https://github.com/eclipse/jetty.project/tree/jetty-11.0.x/demos/demo-jaas-webapp">Source</a>
|
||||
<a class="menu" href="https://github.com/eclipse/jetty.project/tree/jetty-12.0.x/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jaas-webapp">Source</a>
|
||||
<a class="menu" href="https://www.eclipse.org/jetty/">Jetty Project Home</a>
|
||||
<a class="menu" href="https://www.eclipse.org/jetty/documentation/current/">Documentation</a>
|
||||
<a class="menu" href="https://webtide.com">Commercial Support</a>
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Arg>/test/rewrite/</Arg>
|
||||
<Arg>/test/rewrite/info.html</Arg>
|
||||
<Arg>/ee10-test/rewrite/</Arg>
|
||||
<Arg>/ee10-test/rewrite/info.html</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
@ -36,8 +36,8 @@
|
|||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Arg>/test/some/old/context</Arg>
|
||||
<Arg>/test/rewritten/newcontext</Arg>
|
||||
<Arg>/ee10-test/some/old/context</Arg>
|
||||
<Arg>/ee10-test/rewritten/newcontext</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
@ -46,8 +46,8 @@
|
|||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
|
||||
<Arg>/test/rewrite/for/*</Arg>
|
||||
<Arg>/test/rewritten/</Arg>
|
||||
<Arg>/ee10-test/rewrite/for/*</Arg>
|
||||
<Arg>/ee10-test/rewritten/</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
@ -77,8 +77,8 @@
|
|||
<Call name="addRule">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule">
|
||||
<Arg>/test/redirect/*</Arg>
|
||||
<Arg>/test/redirected</Arg>
|
||||
<Arg>/ee10-test/redirect/*</Arg>
|
||||
<Arg>/ee10-test/redirected</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
|
|
@ -20,7 +20,8 @@ ext
|
|||
ee10-servlets
|
||||
ee10-websocket-jakarta
|
||||
ee10-websocket-jetty
|
||||
ee10-demo-realm
|
||||
demo-realm
|
||||
ee10-demo-rewrite
|
||||
|
||||
[files]
|
||||
webapps/ee10-demo-jetty.d/
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<body>
|
||||
<div class="topnav">
|
||||
<a class="menu" href="http://localhost:8080/">Demo Home</a>
|
||||
<a class="menu" href="https://github.com/eclipse/jetty.project/tree/jetty-11.0.x/demos/demo-jetty-webapp">Source</a>
|
||||
<a class="menu" href="https://github.com/eclipse/jetty.project/tree/jetty-12.0.x/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jetty-webapp">Source</a>
|
||||
<a class="menu" href="https://www.eclipse.org/jetty/">Jetty Project Home</a>
|
||||
<a class="menu" href="https://www.eclipse.org/jetty/documentation/current/">Documentation</a>
|
||||
<a class="menu" href="https://webtide.com">Commercial Support</a>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<body>
|
||||
<div class="topnav">
|
||||
<a class="menu" href="http://localhost:8080/">Demo Home</a>
|
||||
<a class="menu" href="https://github.com/eclipse/jetty.project/tree/jetty-11.0.x/demos/demo-jndi-webapp">Source</a>
|
||||
<a class="menu" href="https://github.com/eclipse/jetty.project/tree/jetty-12.0.x/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jndi-webapp">Source</a>
|
||||
<a class="menu" href="https://www.eclipse.org/jetty/">Jetty Project Home</a>
|
||||
<a class="menu" href="https://www.eclipse.org/jetty/documentation/current/">Documentation</a>
|
||||
<a class="menu" href="https://webtide.com">Commercial Support</a>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<div class="topnav">
|
||||
<a class="menu" href="http://localhost:8080/">Demo Home</a>
|
||||
<a class="menu" href="https://github.com/eclipse/jetty.project/tree/jetty-11.0.x/demos/demo-jsp-webapp">Source</a>
|
||||
<a class="menu" href="https://github.com/eclipse/jetty.project/tree/jetty-12.0.x/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-jsp-webapp">Source</a>
|
||||
<a class="menu" href="https://www.eclipse.org/jetty/">Jetty Project Home</a>
|
||||
<a class="menu" href="https://www.eclipse.org/jetty/documentation/current/">Documentation</a>
|
||||
<a class="menu" href="https://webtide.com">Commercial Support</a>
|
||||
|
|
|
@ -16,7 +16,7 @@ jdbc
|
|||
ee10-jsp
|
||||
ee10-annotations
|
||||
ext
|
||||
ee10-demo-realm
|
||||
demo-realm
|
||||
ee10-demo-mock-resources
|
||||
|
||||
[files]
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<body>
|
||||
<div class="topnav">
|
||||
<a class="menu" href="http://localhost:8080/">Demo Home</a>
|
||||
<a class="menu" href="https://github.com/eclipse/jetty.project/tree/jetty-11.0.x/demos/demo-spec">Source</a>
|
||||
<a class="menu" href="https://github.com/eclipse/jetty.project/tree/jetty-12.0.x/jetty-ee10/jetty-ee10-demos/jetty-ee10-demo-spec">Source</a>
|
||||
<a class="menu" href="https://www.eclipse.org/jetty/">Jetty Project Home</a>
|
||||
<a class="menu" href="https://www.eclipse.org/jetty/documentation/current/">Documentation</a>
|
||||
<a class="menu" href="https://webtide.com">Commercial Support</a>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<div class="topnav">
|
||||
<a class="menu" href="http://localhost:8080/">Demo Home</a>
|
||||
<!-- Change source to suit -->
|
||||
<a class="menu" href="https://github.com/eclipse/jetty.project/tree/jetty-10.0.x/demos/XXX">Source</a>
|
||||
<a class="menu" href="https://github.com/eclipse/jetty.project/tree/jetty-12.0.x/jetty-eeX/jetty-eeX-demos/jetty-eeX-XXX">Source</a>
|
||||
<a class="menu" href="https://www.eclipse.org/jetty/">Jetty Project Home</a>
|
||||
<a class="menu" href="https://www.eclipse.org/jetty/documentation/current/">Documentation</a>
|
||||
<a class="menu" href="https://webtide.com">Commercial Support</a>
|
||||
|
|
|
@ -25,8 +25,8 @@ import jakarta.security.auth.message.config.AuthConfigFactory;
|
|||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.ee.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.AbstractLoginService;
|
||||
import org.eclipse.jetty.security.Constraint;
|
||||
|
|
|
@ -202,7 +202,6 @@ public class TestOSGiUtil
|
|||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-util").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-io").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-security").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-ee").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-server").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-session").versionAsInProject().start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-deploy").versionAsInProject().start());
|
||||
|
|
|
@ -30,8 +30,6 @@ import jakarta.servlet.SessionCookieConfig;
|
|||
import jakarta.servlet.SessionTrackingMode;
|
||||
import jakarta.servlet.descriptor.JspPropertyGroupDescriptor;
|
||||
import jakarta.servlet.descriptor.TaglibDescriptor;
|
||||
import org.eclipse.jetty.ee.security.ConstraintAware;
|
||||
import org.eclipse.jetty.ee.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.annotations.AnnotationConfiguration;
|
||||
import org.eclipse.jetty.ee10.plus.annotation.LifeCycleCallback;
|
||||
import org.eclipse.jetty.ee10.plus.annotation.LifeCycleCallbackCollection;
|
||||
|
@ -45,6 +43,8 @@ import org.eclipse.jetty.ee10.servlet.ServletHandler;
|
|||
import org.eclipse.jetty.ee10.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.Source;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintAware;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.webapp.AbstractConfiguration;
|
||||
import org.eclipse.jetty.ee10.webapp.MetaData;
|
||||
import org.eclipse.jetty.ee10.webapp.MetaData.OriginInfo;
|
||||
|
|
|
@ -28,11 +28,11 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jetty.ee.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.plus.webapp.EnvConfiguration;
|
||||
import org.eclipse.jetty.ee10.plus.webapp.PlusConfiguration;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.SessionHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.ee10.webapp.MetaInfConfiguration;
|
||||
import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||
|
|
|
@ -42,10 +42,6 @@
|
|||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-ee</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-session</artifactId>
|
||||
|
|
|
@ -18,7 +18,6 @@ module org.eclipse.jetty.ee10.servlet
|
|||
requires org.slf4j;
|
||||
|
||||
requires transitive jakarta.servlet;
|
||||
requires transitive org.eclipse.jetty.ee;
|
||||
requires transitive org.eclipse.jetty.server;
|
||||
requires transitive org.eclipse.jetty.security;
|
||||
requires transitive org.eclipse.jetty.session;
|
||||
|
|
|
@ -567,8 +567,8 @@ public class ServletApiRequest implements HttpServletRequest
|
|||
@Override
|
||||
public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException
|
||||
{
|
||||
// TODO NYI
|
||||
return null;
|
||||
// Not implemented. Throw ServletException as per spec.
|
||||
throw new ServletException("Not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -38,7 +38,6 @@ import org.eclipse.jetty.http.HttpURI;
|
|||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.QuietException;
|
||||
import org.eclipse.jetty.security.AuthenticationState;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.CustomRequestLog;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
|
@ -843,17 +842,12 @@ public class ServletChannel
|
|||
if (idleTO >= 0 && getIdleTimeout() != _oldIdleTimeout)
|
||||
setIdleTimeout(_oldIdleTimeout);
|
||||
|
||||
if (getServer().getRequestLog() != null)
|
||||
if (getServer().getRequestLog() instanceof CustomRequestLog)
|
||||
{
|
||||
AuthenticationState authenticationState = apiRequest.getAuthentication();
|
||||
if (authenticationState instanceof AuthenticationState.Succeeded succeededAuthentication)
|
||||
_servletContextRequest.setAttribute(CustomRequestLog.USER_NAME, succeededAuthentication.getUserIdentity().getUserPrincipal().getName());
|
||||
|
||||
String realPath = apiRequest.getServletContext().getRealPath(Request.getPathInContext(_servletContextRequest));
|
||||
_servletContextRequest.setAttribute(CustomRequestLog.REAL_PATH, realPath);
|
||||
|
||||
String servletName = _servletContextRequest.getServletName();
|
||||
_servletContextRequest.setAttribute(CustomRequestLog.HANDLER_NAME, servletName);
|
||||
CustomRequestLog.LogDetail logDetail = new CustomRequestLog.LogDetail(
|
||||
_servletContextRequest.getServletName(),
|
||||
apiRequest.getServletContext().getRealPath(Request.getPathInContext(_servletContextRequest)));
|
||||
_servletContextRequest.setAttribute(CustomRequestLog.LOG_DETAIL, logDetail);
|
||||
}
|
||||
|
||||
// Callback will either be succeeded here or failed in abort().
|
||||
|
|
|
@ -66,8 +66,8 @@ import jakarta.servlet.http.HttpSessionAttributeListener;
|
|||
import jakarta.servlet.http.HttpSessionBindingListener;
|
||||
import jakarta.servlet.http.HttpSessionIdListener;
|
||||
import jakarta.servlet.http.HttpSessionListener;
|
||||
import org.eclipse.jetty.ee.security.ConstraintAware;
|
||||
import org.eclipse.jetty.ee.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintAware;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.http.pathmap.MatchedResource;
|
||||
|
@ -95,7 +95,6 @@ import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
|||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.component.DumpableCollection;
|
||||
import org.eclipse.jetty.util.component.Environment;
|
||||
import org.eclipse.jetty.util.component.Graceful;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
|
@ -120,7 +119,7 @@ import static jakarta.servlet.ServletContext.TEMPDIR;
|
|||
* cause confusion with {@link ServletContext}.
|
||||
*/
|
||||
@ManagedObject("Servlet Context Handler")
|
||||
public class ServletContextHandler extends ContextHandler implements Graceful
|
||||
public class ServletContextHandler extends ContextHandler
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ServletContextHandler.class);
|
||||
public static final Environment __environment = Environment.ensure("ee10");
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee.security;
|
||||
package org.eclipse.jetty.ee10.servlet.security;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
|
@ -11,7 +11,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.ee.security;
|
||||
package org.eclipse.jetty.ee10.servlet.security;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
|
@ -32,9 +32,9 @@ import jakarta.servlet.HttpMethodConstraintElement;
|
|||
import jakarta.servlet.ServletSecurityElement;
|
||||
import jakarta.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
|
||||
import jakarta.servlet.annotation.ServletSecurity.TransportGuarantee;
|
||||
import org.eclipse.jetty.ee.security.ConstraintAware;
|
||||
import org.eclipse.jetty.ee.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintAware;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.http.pathmap.MappedResource;
|
||||
import org.eclipse.jetty.http.pathmap.MatchedResource;
|
||||
import org.eclipse.jetty.http.pathmap.PathMappings;
|
||||
|
|
|
@ -24,7 +24,7 @@ import jakarta.servlet.ServletException;
|
|||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.ee.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.security.Constraint;
|
||||
|
|
|
@ -34,7 +34,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.client.ContentResponse;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.ee.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.security.Constraint;
|
||||
|
|
|
@ -38,11 +38,11 @@ import jakarta.servlet.annotation.ServletSecurity.TransportGuarantee;
|
|||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.ee.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.ee10.servlet.SessionHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.HttpTester;
|
||||
|
|
|
@ -23,9 +23,9 @@ import jakarta.servlet.ServletException;
|
|||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.ee.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.SessionHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.security.Constraint;
|
||||
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
|
|
|
@ -37,8 +37,8 @@ import org.eclipse.jetty.client.DigestAuthentication;
|
|||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.Request;
|
||||
import org.eclipse.jetty.client.StringRequestContent;
|
||||
import org.eclipse.jetty.ee.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.security.AbstractLoginService;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue