Merge remote-tracking branch 'origin/jetty-9.4.x'
This commit is contained in:
commit
d28802ad62
|
@ -15,19 +15,19 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
||||||
[[jetty-runner]]
|
[[jetty-runner]]
|
||||||
=== Use Jetty without an installed distribution
|
=== Use Jetty Without an Installed Distribution
|
||||||
|
|
||||||
The idea of the `jetty-runner` is extremely simple – run a webapp directly from the command line using a single jar file and as much default configuration as possible.
|
The idea of the `jetty-runner` is extremely simple – run a webapp directly from the command line using a single jar file and as much default configuration as possible.
|
||||||
Of course, if your webapp is not so straightforward, the `jetty-runner` has command line options which allow you to customize the execution environment.
|
Of course, if your webapp is not as straightforward, the `jetty-runner` has command line options which allow you to customize the execution environment.
|
||||||
|
|
||||||
[[jetty-runner-preparation]]
|
[[jetty-runner-preparation]]
|
||||||
==== Preparation
|
==== Preparation
|
||||||
|
|
||||||
You will need the `jetty-runner` jar:
|
You will need the `jetty-runner` jar:
|
||||||
|
|
||||||
1. http://central.maven.org/maven2/org/eclipse/jetty/jetty-runner/[Get] the `jetty-runner` jar available at http://search.maven.org/#browse[maven central].
|
1. Download the `jetty-runner` jar available at http://central.maven.org/maven2/org/eclipse/jetty/jetty-runner/[Maven Central].
|
||||||
|
|
||||||
==== Deploying a simple context
|
==== Deploying a Simple Context
|
||||||
|
|
||||||
Let's assume we have a very simple webapp that does not need any resources from its environment, nor any configuration apart from the defaults.
|
Let's assume we have a very simple webapp that does not need any resources from its environment, nor any configuration apart from the defaults.
|
||||||
Starting it is as simple as performing the following:
|
Starting it is as simple as performing the following:
|
||||||
|
@ -55,10 +55,26 @@ In fact, the webapp does not have to be a war or even a directory, it can simply
|
||||||
|
|
||||||
____
|
____
|
||||||
[NOTE]
|
[NOTE]
|
||||||
When using a context xml file, the application being deployed is not even required to be a fully-fledged webapp. It can simply be a Jetty link:#what-is-a-context[context].
|
When using a context xml file, the application being deployed is not even required to be a fully-fledged webapp.
|
||||||
|
It can simply be a Jetty link:#what-is-a-context[context].
|
||||||
____
|
____
|
||||||
|
|
||||||
==== Deploying multiple contexts
|
By default, `jetty-runner` implements all Configuration Classes so that users can set up and deploy new instances with as little configuration as possible.
|
||||||
|
If you wish to only implement certain Configuration Classes, they will need to be defined in the context xml for the webapp/context.
|
||||||
|
The default Configuration Classes are:
|
||||||
|
|
||||||
|
`org.eclipse.jetty.webapp.WebInfConfiguration`
|
||||||
|
`org.eclipse.jetty.webapp.WebXmlConfiguration`
|
||||||
|
`org.eclipse.jetty.webapp.MetaInfConfiguration`
|
||||||
|
`org.eclipse.jetty.webapp.FragmentConfiguration`
|
||||||
|
`org.eclipse.jetty.webapp.JettyWebXmlConfiguration`
|
||||||
|
`org.eclipse.jetty.plus.webapp.EnvConfiguration`
|
||||||
|
`org.eclipse.jetty.plus.webapp.PlusConfiguration`
|
||||||
|
`org.eclipse.jetty.annotations.AnnotationConfiguration`
|
||||||
|
|
||||||
|
You can learn more about implementing specific Configuration Classes link:https://www.eclipse.org/jetty/documentation/current/configuring-webapps.html#webapp-configurations[here.]
|
||||||
|
|
||||||
|
==== Deploying Multiple Contexts
|
||||||
|
|
||||||
If you have more than one webapp that must be deployed, simply provide them all on the command line.
|
If you have more than one webapp that must be deployed, simply provide them all on the command line.
|
||||||
You can control the context paths for them using the `--path` parameter.
|
You can control the context paths for them using the `--path` parameter.
|
||||||
|
@ -69,7 +85,7 @@ Here's an example of deploying 2 wars (although either or both of them could be
|
||||||
> java -jar jetty-runner.jar --path /one my1.war --path /two my2.war
|
> java -jar jetty-runner.jar --path /one my1.war --path /two my2.war
|
||||||
....
|
....
|
||||||
|
|
||||||
If you have context xml files that describe your webapps, you can fully configure your webapps in them and hence you don't need to use the command line switches.
|
If you have context xml files that describe your webapps, you can fully configure your webapps in them and hence you won't need to use the command line switches.
|
||||||
Just provide the list of context files like so:
|
Just provide the list of context files like so:
|
||||||
|
|
||||||
[source, screen, subs="{sub-order}"]
|
[source, screen, subs="{sub-order}"]
|
||||||
|
@ -84,7 +100,7 @@ So, for example, you could set the context path for the webapp inside the contex
|
||||||
____
|
____
|
||||||
|
|
||||||
|
|
||||||
===== Changing the default port
|
===== Changing the Default Port
|
||||||
|
|
||||||
By default the `jetty-runner` will listen on port 8080.
|
By default the `jetty-runner` will listen on port 8080.
|
||||||
You can easily change this on the command line using the `--port` command.
|
You can easily change this on the command line using the `--port` command.
|
||||||
|
@ -95,7 +111,7 @@ Here's an example that runs our simple.war on port 9090:
|
||||||
> java -jar jetty-runner.jar --port 9090 simple.war
|
> java -jar jetty-runner.jar --port 9090 simple.war
|
||||||
....
|
....
|
||||||
|
|
||||||
===== Using jetty.xml files
|
===== Using jetty.xml Files
|
||||||
|
|
||||||
Instead of, or in addition to, using command line switches, you can use one or more `jetty.xml` files to configure the environment for your webapps.
|
Instead of, or in addition to, using command line switches, you can use one or more `jetty.xml` files to configure the environment for your webapps.
|
||||||
Here's an example where we apply two different `jetty.xml` files:
|
Here's an example where we apply two different `jetty.xml` files:
|
||||||
|
@ -105,7 +121,8 @@ Here's an example where we apply two different `jetty.xml` files:
|
||||||
> java -jar jetty-runner.jar --config jetty.xml --config jetty-https.xml simple.war
|
> java -jar jetty-runner.jar --config jetty.xml --config jetty-https.xml simple.war
|
||||||
....
|
....
|
||||||
|
|
||||||
===== Full configuration reference
|
[[runner-configuration-reference]]
|
||||||
|
==== Full Configuration Reference
|
||||||
|
|
||||||
You can see the fill set of configuration options using the `--help` switch:
|
You can see the fill set of configuration options using the `--help` switch:
|
||||||
|
|
||||||
|
@ -137,115 +154,123 @@ Context opts:
|
||||||
[[--path /path] context]*n - WAR file, web app dir or context xml file, optionally with a context path
|
[[--path /path] context]*n - WAR file, web app dir or context xml file, optionally with a context path
|
||||||
----
|
----
|
||||||
|
|
||||||
Printing the version:::
|
===== Printing the Version
|
||||||
Print out the version of Jetty and then exit immediately.
|
Print out the version of Jetty and then exit immediately.
|
||||||
+
|
|
||||||
[source, screen, subs="{sub-order}"]
|
[source, screen, subs="{sub-order}"]
|
||||||
....
|
....
|
||||||
> java -jar jetty-runner.jar --version
|
> java -jar jetty-runner.jar --version
|
||||||
....
|
....
|
||||||
|
|
||||||
Configuring a request log:::
|
===== Configuring a Request Log
|
||||||
Cause Jetty to write a request log with the given name.
|
Cause Jetty to write a request log with the given name.
|
||||||
If the file is prefixed with `yyyy_mm_dd` then the file will be automatically rolled over.
|
If the file is prefixed with `yyyy_mm_dd` then the file will be automatically rolled over.
|
||||||
Note that for finer grained configuration of the link:{JDURL}/org/eclipse/jetty/server/NCSARequestLog.html[request log], you will need to use a Jetty xml file instead.
|
Note that for finer grained configuration of the link:{JDURL}/org/eclipse/jetty/server/NCSARequestLog.html[request log], you will need to use a Jetty xml file instead.
|
||||||
+
|
|
||||||
[source, screen, subs="{sub-order}"]
|
[source, screen, subs="{sub-order}"]
|
||||||
....
|
....
|
||||||
> java -jar jetty-runner.jar --log yyyy_mm_dd-requests.log my.war
|
> java -jar jetty-runner.jar --log yyyy_mm_dd-requests.log my.war
|
||||||
....
|
....
|
||||||
|
|
||||||
Configuring the output log:::
|
===== Configuring the Output Log
|
||||||
Redirect the output of jetty logging to the named file.
|
Redirect the output of jetty logging to the named file.
|
||||||
If the file is prefixed with `yyyy_mm_dd` then the file will be automatically rolled over.
|
If the file is prefixed with `yyyy_mm_dd` then the file will be automatically rolled over.
|
||||||
+
|
|
||||||
[source, screen, subs="{sub-order}"]
|
[source, screen, subs="{sub-order}"]
|
||||||
....
|
....
|
||||||
> java -jar jetty-runner.jar --out yyyy_mm_dd-output.log my.war
|
> java -jar jetty-runner.jar --out yyyy_mm_dd-output.log my.war
|
||||||
....
|
....
|
||||||
|
|
||||||
Configuring the interface for http:::
|
===== Configuring the Interface for HTTP
|
||||||
Like Jetty standalone, the default is for the connectors to listen on all interfaces on a machine.
|
Like Jetty standalone, the default is for the connectors to listen on all interfaces on a machine.
|
||||||
You can control that by specifying the name or ip address of the particular interface you wish to use with the `--host` argument:
|
You can control that by specifying the name or ip address of the particular interface you wish to use with the `--host` argument:
|
||||||
+
|
|
||||||
[source, screen, subs="{sub-order}"]
|
[source, screen, subs="{sub-order}"]
|
||||||
....
|
....
|
||||||
> java -jar jetty-runner.jar --host 192.168.22.19 my.war
|
> java -jar jetty-runner.jar --host 192.168.22.19 my.war
|
||||||
....
|
....
|
||||||
|
|
||||||
Configuring the port for http:::
|
===== Configuring the Port for HTTP
|
||||||
The default port number is 8080.
|
The default port number is 8080.
|
||||||
To link:#how-to-configure-connectors[configure a https connector], use a Jetty xml config file instead.
|
To link:#how-to-configure-connectors[configure a https connector], use a Jetty xml config file instead.
|
||||||
+
|
|
||||||
[source, screen, subs="{sub-order}"]
|
[source, screen, subs="{sub-order}"]
|
||||||
....
|
....
|
||||||
> java -jar jetty-runner.jar --port 9090 my.war
|
> java -jar jetty-runner.jar --port 9090 my.war
|
||||||
....
|
....
|
||||||
|
|
||||||
Configuring stop:::
|
===== Configuring Stop
|
||||||
You can configure a port number for jetty to listen on for a stop command, so you are able to stop it from a different terminal.
|
You can configure a port number for jetty to listen on for a stop command, so you are able to stop it from a different terminal.
|
||||||
This requires the use of a "secret" key, to prevent malicious or accidental termination.
|
This requires the use of a "secret" key, to prevent malicious or accidental termination.
|
||||||
Use the `--stop-port` and `--stop-key` parameters as arguments to the `jetty-runner`:
|
Use the `--stop-port` and `--stop-key` parameters as arguments to the `jetty-runner`:
|
||||||
+
|
|
||||||
[source, screen, subs="{sub-order}"]
|
[source, screen, subs="{sub-order}"]
|
||||||
....
|
....
|
||||||
> java -jar jetty-runner.jar --stop-port 8181 --stop-key abc123
|
> java -jar jetty-runner.jar --stop-port 8181 --stop-key abc123
|
||||||
|
|
||||||
....
|
....
|
||||||
+
|
|
||||||
Then, to stop Jetty from a different terminal, you need to supply the same port and key information.
|
Then, to stop Jetty from a different terminal, you need to supply the same port and key information.
|
||||||
For this you'll either need a local installation of Jetty, the link:#jetty-maven-plugin[jetty-maven-plugin], the link:#jetty-ant[jetty-ant plugin], or a custom class.
|
For this you'll either need a local installation of Jetty, the link:#jetty-maven-plugin[jetty-maven-plugin], the link:#jetty-ant[jetty-ant plugin], or a custom class.
|
||||||
Here's how to use a Jetty installation to perform a stop:
|
Here's how to use a Jetty installation to perform a stop:
|
||||||
+
|
|
||||||
[source, screen, subs="{sub-order}"]
|
[source, screen, subs="{sub-order}"]
|
||||||
....
|
....
|
||||||
> java -jar start.jar --stop-port 8181 --stop-key abc123 --stop
|
> java -jar start.jar --stop-port 8181 --stop-key abc123 --stop
|
||||||
....
|
....
|
||||||
|
|
||||||
Configuring the container classpath:::
|
===== Configuring the Container Classpath
|
||||||
With a local installation of Jetty, you add jars and classes to the container's classpath by putting them in the `{$jetty.base}/lib` directory.
|
With a local installation of Jetty, you add jars and classes to the container's classpath by putting them in the `{$jetty.base}/lib` directory.
|
||||||
With the `jetty-runner`, you can use the `--lib`, `--jar` and `--classes` arguments instead to achieve the same thing.
|
With the `jetty-runner`, you can use the `--lib`, `--jar` and `--classes` arguments instead to achieve the same thing.
|
||||||
+
|
|
||||||
`--lib` adds the location of a directory which contains jars to add to the container classpath.
|
`--lib` adds the location of a directory which contains jars to add to the container classpath.
|
||||||
You can add 1 or more.
|
You can add 1 or more.
|
||||||
Here's an example of configuring 2 directories:
|
Here's an example of configuring 2 directories:
|
||||||
+
|
|
||||||
[source, screen, subs="{sub-order}"]
|
[source, screen, subs="{sub-order}"]
|
||||||
....
|
....
|
||||||
> java -jar jetty-runner.jar --lib /usr/local/external/lib --lib $HOME/external-other/lib my.war
|
> java -jar jetty-runner.jar --lib /usr/local/external/lib --lib $HOME/external-other/lib my.war
|
||||||
....
|
....
|
||||||
+
|
|
||||||
`--jar` adds a single jar file to the container classpath.
|
`--jar` adds a single jar file to the container classpath.
|
||||||
You can add 1 or more.
|
You can add 1 or more.
|
||||||
Here's an example of configuring 3 extra jars:
|
Here's an example of configuring 3 extra jars:
|
||||||
+
|
|
||||||
[source, screen, subs="{sub-order}"]
|
[source, screen, subs="{sub-order}"]
|
||||||
....
|
....
|
||||||
> java -jar jetty-runner.jar --jar /opt/stuff/jars/jar1.jar --jar $HOME/jars/jar2.jar --jar /usr/local/proj/jars/jar3.jar my.war
|
> java -jar jetty-runner.jar --jar /opt/stuff/jars/jar1.jar --jar $HOME/jars/jar2.jar --jar /usr/local/proj/jars/jar3.jar my.war
|
||||||
....
|
....
|
||||||
+
|
|
||||||
`--classes` add the location of a directory containing classes to add to the container classpath.
|
`--classes` add the location of a directory containing classes to add to the container classpath.
|
||||||
You can add 1 or more.
|
You can add 1 or more.
|
||||||
Here's an example of configuring a single extra classes dir:
|
Here's an example of configuring a single extra classes dir:
|
||||||
+
|
|
||||||
[source, screen, subs="{sub-order}"]
|
[source, screen, subs="{sub-order}"]
|
||||||
....
|
....
|
||||||
> java -jar jetty-runner.jar --classes /opt/stuff/classes my.war
|
> java -jar jetty-runner.jar --classes /opt/stuff/classes my.war
|
||||||
....
|
....
|
||||||
|
|
||||||
Gathering statistics:::
|
____
|
||||||
|
[NOTE]
|
||||||
|
When using the `--jar` and/or `--lib` arguments, by default these will *not* be inspected for `META-INF` information such as `META-INF/resources`, `META-INF/web-fragment.xml`, or `META-INF/taglib.tld`.
|
||||||
|
If you require these jar files inspected you will need to define the link:https://www.eclipse.org/jetty/documentation/current/configuring-webapps.html#webapp-context-attributes[jar pattern in your context xml file].
|
||||||
|
Jetty-Runner automatically provides and appends a suitable pattern for jtsl taglibs (this pattern is different than the one in the standard Jetty distribution).
|
||||||
|
____
|
||||||
|
|
||||||
|
|
||||||
|
===== Gathering Statistics
|
||||||
If statistics gathering is enabled, then they are viewable by surfing to the context `/stats`.
|
If statistics gathering is enabled, then they are viewable by surfing to the context `/stats`.
|
||||||
You may optionally protect access to that context with a password.
|
You may optionally protect access to that context with a password.
|
||||||
Here's an example of enabling statistics, with no password protection:
|
Here's an example of enabling statistics, with no password protection:
|
||||||
+
|
|
||||||
[source, screen, subs="{sub-order}"]
|
[source, screen, subs="{sub-order}"]
|
||||||
....
|
....
|
||||||
> java -jar jetty-runner.jar --stats unsecure my.war
|
> java -jar jetty-runner.jar --stats unsecure my.war
|
||||||
....
|
....
|
||||||
+
|
|
||||||
If we wished to protect access to the `/stats` context, we would provide the location of a Jetty realm configuration file containing authentication and authorization information.
|
If we wished to protect access to the `/stats` context, we would provide the location of a Jetty realm configuration file containing authentication and authorization information.
|
||||||
For example, we could use the following example realm file from the Jetty distribution:
|
For example, we could use the following example realm file from the Jetty distribution:
|
||||||
+
|
|
||||||
[source, screen, subs="{sub-order}"]
|
[source, screen, subs="{sub-order}"]
|
||||||
....
|
....
|
||||||
jetty: MD5:164c88b302622e17050af52c89945d44,user
|
jetty: MD5:164c88b302622e17050af52c89945d44,user
|
||||||
|
@ -256,16 +281,16 @@ user: password,user
|
||||||
# This entry is for digest auth. The credential is a MD5 hash of username:realmname:password
|
# This entry is for digest auth. The credential is a MD5 hash of username:realmname:password
|
||||||
digest: MD5:6e120743ad67abfbc385bc2bb754e297,user
|
digest: MD5:6e120743ad67abfbc385bc2bb754e297,user
|
||||||
....
|
....
|
||||||
+
|
|
||||||
Assuming we've copied it into the local directory, we would apply it like so
|
Assuming we've copied it into the local directory, we would apply it like so
|
||||||
+
|
|
||||||
[source, screen, subs="{sub-order}"]
|
[source, screen, subs="{sub-order}"]
|
||||||
....
|
....
|
||||||
> java -jar jetty-runner.jar --stats realm.properties my.war
|
> java -jar jetty-runner.jar --stats realm.properties my.war
|
||||||
....
|
....
|
||||||
+
|
|
||||||
After navigating to http://localhost:8080/ a few times, we can point to the stats servlet on http://localhost:8080/stats to see the output:
|
After navigating to http://localhost:8080/ a few times, we can point to the stats servlet on http://localhost:8080/stats to see the output:
|
||||||
+
|
|
||||||
....
|
....
|
||||||
Statistics:
|
Statistics:
|
||||||
Statistics gathering started 1490627ms ago
|
Statistics gathering started 1490627ms ago
|
||||||
|
|
|
@ -25,6 +25,7 @@ Jetty also offers more niche session managers that leverage backends such as Mon
|
||||||
|
|
||||||
include::session-hierarchy.adoc[]
|
include::session-hierarchy.adoc[]
|
||||||
include::sessions-details.adoc[]
|
include::sessions-details.adoc[]
|
||||||
|
include::session-configuration-memory.adoc[]
|
||||||
include::session-configuration-file-system.adoc[]
|
include::session-configuration-file-system.adoc[]
|
||||||
include::session-configuration-jdbc.adoc[]
|
include::session-configuration-jdbc.adoc[]
|
||||||
include::session-configuration-mongodb.adoc[]
|
include::session-configuration-mongodb.adoc[]
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ========================================================================
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
[[configuring-sessions-memory]]
|
||||||
|
|
||||||
|
=== Non-Clustered Session Management: Memory
|
||||||
|
|
||||||
|
Non-clustered, in-memory-only is the default style of session management.
|
||||||
|
In previous versions of jetty this was referred to as "hash" sessions, as they were stored in a HashMap in memory.
|
||||||
|
When using the Jetty distribution, if you do not configure any session module, this will be enabled by default.
|
||||||
|
|
||||||
|
Specifically, jetty will hook up:
|
||||||
|
|
||||||
|
[horizontal]
|
||||||
|
*a DefaultSessionIdManager*::
|
||||||
|
- produces unique session ids and supports cross-context dispatch re-use of session ids
|
||||||
|
*a HouseKeeper*::
|
||||||
|
- scavenges expired sessions every 10 mins
|
||||||
|
*a DefaultSessionCache per context*::
|
||||||
|
- keeps session objects in memory
|
||||||
|
*a NullSessionDataStore per context*::
|
||||||
|
- no persistence of sessions
|
||||||
|
|
||||||
|
|
||||||
|
If you wish to change any of the default configuration, enable the *session-cache-hash* module.
|
||||||
|
|
|
@ -128,7 +128,7 @@ The new default provides similar features to the old hash session management:
|
||||||
Requests for the same session in the same context share the same session object.
|
Requests for the same session in the same context share the same session object.
|
||||||
Session objects remain in the cache until they expire or are explicitly invalidated.
|
Session objects remain in the cache until they expire or are explicitly invalidated.
|
||||||
|
|
||||||
If you wish to configure the default setup further, enable the `session-cache-default` module.
|
If you wish to configure the default setup further, enable the `session-cache-hash` module.
|
||||||
|
|
||||||
*Compatibility*
|
*Compatibility*
|
||||||
|
|
||||||
|
|
|
@ -37,14 +37,13 @@ import org.eclipse.jetty.io.ChannelEndPoint;
|
||||||
import org.eclipse.jetty.io.Connection;
|
import org.eclipse.jetty.io.Connection;
|
||||||
import org.eclipse.jetty.io.EndPoint;
|
import org.eclipse.jetty.io.EndPoint;
|
||||||
import org.eclipse.jetty.io.ManagedSelector;
|
import org.eclipse.jetty.io.ManagedSelector;
|
||||||
import org.eclipse.jetty.io.SelectChannelEndPoint;
|
|
||||||
import org.eclipse.jetty.io.SelectorManager;
|
import org.eclipse.jetty.io.SelectorManager;
|
||||||
|
import org.eclipse.jetty.io.SocketChannelEndPoint;
|
||||||
import org.eclipse.jetty.util.Callback;
|
import org.eclipse.jetty.util.Callback;
|
||||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||||
import org.eclipse.jetty.util.annotation.Name;
|
import org.eclipse.jetty.util.annotation.Name;
|
||||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
import org.eclipse.jetty.util.thread.ExecutionStrategy;
|
|
||||||
import org.eclipse.jetty.util.thread.Scheduler;
|
import org.eclipse.jetty.util.thread.Scheduler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -401,7 +400,9 @@ public class ServerConnector extends AbstractNetworkConnector
|
||||||
|
|
||||||
protected ChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException
|
protected ChannelEndPoint newEndPoint(SocketChannel channel, ManagedSelector selectSet, SelectionKey key) throws IOException
|
||||||
{
|
{
|
||||||
return new SelectChannelEndPoint(channel, selectSet, key, getScheduler(), getIdleTimeout());
|
SocketChannelEndPoint endpoint = new SocketChannelEndPoint(channel, selectSet, key, getScheduler());
|
||||||
|
endpoint.setIdleTimeout(getIdleTimeout());
|
||||||
|
return endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
package org.eclipse.jetty.server;
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
@ -31,16 +32,21 @@ import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.servlet.DispatcherType;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.io.LeakTrackingByteBufferPool;
|
import org.eclipse.jetty.io.LeakTrackingByteBufferPool;
|
||||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||||
|
@ -62,8 +68,8 @@ public class ThreadStarvationTest
|
||||||
{
|
{
|
||||||
final static int BUFFER_SIZE=1024*1024;
|
final static int BUFFER_SIZE=1024*1024;
|
||||||
final static int BUFFERS=64;
|
final static int BUFFERS=64;
|
||||||
final static int CLIENTS=10;
|
|
||||||
final static int THREADS=5;
|
final static int THREADS=5;
|
||||||
|
final static int CLIENTS=THREADS*2;
|
||||||
@Rule
|
@Rule
|
||||||
public TestTracker tracker = new TestTracker();
|
public TestTracker tracker = new TestTracker();
|
||||||
|
|
||||||
|
@ -199,45 +205,81 @@ public class ThreadStarvationTest
|
||||||
{
|
{
|
||||||
prepareServer(new ReadHandler());
|
prepareServer(new ReadHandler());
|
||||||
_server.start();
|
_server.start();
|
||||||
|
|
||||||
|
ExecutorService clientExecutors = Executors.newFixedThreadPool(CLIENTS);
|
||||||
|
|
||||||
|
List<Callable<String>> clientTasks = new ArrayList<>();
|
||||||
|
|
||||||
|
for(int i=0; i<CLIENTS; i++) {
|
||||||
|
clientTasks.add(() ->
|
||||||
|
{
|
||||||
|
try (Socket client = clientSocketProvider.newSocket("localhost", _connector.getLocalPort());
|
||||||
|
OutputStream out = client.getOutputStream();
|
||||||
|
InputStream in = client.getInputStream())
|
||||||
|
{
|
||||||
|
client.setSoTimeout(10000);
|
||||||
|
|
||||||
Socket[] client = new Socket[CLIENTS];
|
String request = "" +
|
||||||
OutputStream[] os = new OutputStream[client.length];
|
"PUT / HTTP/1.0\r\n" +
|
||||||
InputStream[] is = new InputStream[client.length];
|
"host: localhost\r\n" +
|
||||||
|
"content-length: 10\r\n" +
|
||||||
for (int i = 0; i < client.length; i++)
|
"\r\n" +
|
||||||
{
|
"1";
|
||||||
client[i] = clientSocketProvider.newSocket("localhost", _connector.getLocalPort());
|
|
||||||
client[i].setSoTimeout(10000);
|
// Write partial request
|
||||||
|
out.write(request.getBytes(StandardCharsets.UTF_8));
|
||||||
os[i] = client[i].getOutputStream();
|
out.flush();
|
||||||
is[i] = client[i].getInputStream();
|
|
||||||
|
// Finish Request
|
||||||
String request = "" +
|
Thread.sleep(1500);
|
||||||
"PUT / HTTP/1.0\r\n" +
|
out.write(("234567890\r\n").getBytes(StandardCharsets.UTF_8));
|
||||||
"host: localhost\r\n" +
|
out.flush();
|
||||||
"content-length: 10\r\n" +
|
|
||||||
"\r\n" +
|
// Read Response
|
||||||
"1";
|
String response = IO.toString(in);
|
||||||
os[i].write(request.getBytes(StandardCharsets.UTF_8));
|
assertEquals(-1, in.read());
|
||||||
os[i].flush();
|
return response;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread.sleep(500);
|
// new Thread(()->{
|
||||||
|
// try
|
||||||
for (int i = 0; i < client.length; i++)
|
// {
|
||||||
|
// TimeUnit.SECONDS.sleep(10);
|
||||||
|
//
|
||||||
|
// ServerConnector conn = _server.getBean(ServerConnector.class);
|
||||||
|
// ManagedSelector ms = conn.getSelectorManager().getBean(ManagedSelector.class);
|
||||||
|
//
|
||||||
|
// Selector sel = ms.getSelector();
|
||||||
|
// sel.keys().stream().map((key)->key.attachment()).forEach(
|
||||||
|
// (attach) -> {
|
||||||
|
// System.out.println(attach);
|
||||||
|
// SocketChannelEndPoint endp = (SocketChannelEndPoint) attach;
|
||||||
|
// SslConnection sslconn = (SslConnection) endp.getConnection();
|
||||||
|
// sslconn.dumpBuffers();
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// _server.dump(System.out, "");
|
||||||
|
// }
|
||||||
|
// catch (Throwable ignore)
|
||||||
|
// {
|
||||||
|
// }
|
||||||
|
// }).start();
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
os[i].write(("234567890\r\n").getBytes(StandardCharsets.UTF_8));
|
List<Future<String>> responses = clientExecutors.invokeAll(clientTasks, 60, TimeUnit.SECONDS);
|
||||||
os[i].flush();
|
|
||||||
}
|
for (Future<String> responseFut : responses)
|
||||||
|
{
|
||||||
Thread.sleep(500);
|
String response = responseFut.get();
|
||||||
|
assertThat(response, containsString("200 OK"));
|
||||||
for (int i = 0; i < client.length; i++)
|
assertThat(response, containsString("Read Input 10"));
|
||||||
|
}
|
||||||
|
} finally
|
||||||
{
|
{
|
||||||
String response = IO.toString(is[i]);
|
clientExecutors.shutdownNow();
|
||||||
assertEquals(-1, is[i].read());
|
|
||||||
assertThat(response, containsString("200 OK"));
|
|
||||||
assertThat(response, containsString("Read Input 10"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,17 +289,25 @@ public class ThreadStarvationTest
|
||||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
{
|
{
|
||||||
baseRequest.setHandled(true);
|
baseRequest.setHandled(true);
|
||||||
response.setStatus(200);
|
|
||||||
|
if(request.getDispatcherType() == DispatcherType.REQUEST)
|
||||||
int l = request.getContentLength();
|
|
||||||
int r = 0;
|
|
||||||
while (r < l)
|
|
||||||
{
|
{
|
||||||
if (request.getInputStream().read() >= 0)
|
response.setStatus(200);
|
||||||
r++;
|
|
||||||
|
int l = request.getContentLength();
|
||||||
|
int r = 0;
|
||||||
|
while (r < l)
|
||||||
|
{
|
||||||
|
if (request.getInputStream().read() >= 0)
|
||||||
|
r++;
|
||||||
|
}
|
||||||
|
|
||||||
|
response.getOutputStream().write(("Read Input " + r + "\r\n").getBytes());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
response.sendError(HttpStatus.INTERNAL_SERVER_ERROR_500);
|
||||||
}
|
}
|
||||||
|
|
||||||
response.getOutputStream().write(("Read Input " + r + "\r\n").getBytes());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,121 +317,71 @@ public class ThreadStarvationTest
|
||||||
{
|
{
|
||||||
prepareServer(new WriteHandler());
|
prepareServer(new WriteHandler());
|
||||||
_server.start();
|
_server.start();
|
||||||
|
|
||||||
Socket[] client = new Socket[CLIENTS];
|
|
||||||
OutputStream[] os = new OutputStream[client.length];
|
|
||||||
final InputStream[] is = new InputStream[client.length];
|
|
||||||
|
|
||||||
for (int i = 0; i < client.length; i++)
|
|
||||||
{
|
|
||||||
client[i] = clientSocketProvider.newSocket("localhost", _connector.getLocalPort());
|
|
||||||
client[i].setSoTimeout(10000);
|
|
||||||
|
|
||||||
os[i] = client[i].getOutputStream();
|
|
||||||
is[i] = client[i].getInputStream();
|
|
||||||
|
|
||||||
String request =
|
|
||||||
"GET / HTTP/1.0\r\n" +
|
|
||||||
"host: localhost\r\n" +
|
|
||||||
"\r\n";
|
|
||||||
os[i].write(request.getBytes(StandardCharsets.UTF_8));
|
|
||||||
os[i].flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread.sleep(100);
|
|
||||||
|
|
||||||
final AtomicLong total=new AtomicLong();
|
|
||||||
final CountDownLatch latch=new CountDownLatch(client.length);
|
|
||||||
|
|
||||||
for (int i = client.length; i-->0;)
|
|
||||||
{
|
|
||||||
final int c=i;
|
|
||||||
new Thread()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
byte[] content=new byte[BUFFER_SIZE];
|
|
||||||
int content_length=0;
|
|
||||||
String header= "No HEADER!";
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Read an initial content buffer
|
|
||||||
int len=0;
|
|
||||||
|
|
||||||
while (len<BUFFER_SIZE)
|
|
||||||
{
|
|
||||||
int l=is[c].read(content,len,content.length-len);
|
|
||||||
if (l<0)
|
|
||||||
throw new IllegalStateException();
|
|
||||||
len+=l;
|
|
||||||
content_length+=l;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for the end of the header
|
|
||||||
int state=0;
|
|
||||||
loop: for(int j=0;j<len;j++)
|
|
||||||
{
|
|
||||||
content_length--;
|
|
||||||
switch(content[j])
|
|
||||||
{
|
|
||||||
case '\r':
|
|
||||||
state++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\n':
|
|
||||||
switch(state)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
state=2;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
header=new String(content,0,j,StandardCharsets.ISO_8859_1);
|
|
||||||
assertThat(header,containsString(" 200 OK"));
|
|
||||||
break loop;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
state=0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the rest of the body
|
|
||||||
while(len>0)
|
|
||||||
{
|
|
||||||
len=is[c].read(content);
|
|
||||||
if (len>0)
|
|
||||||
content_length+=len;
|
|
||||||
}
|
|
||||||
|
|
||||||
// System.err.printf("client %d cl=%d %n%s%n",c,content_length,header);
|
|
||||||
total.addAndGet(content_length);
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.start();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
latch.await();
|
|
||||||
assertEquals(CLIENTS*BUFFERS*BUFFER_SIZE,total.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ExecutorService clientExecutors = Executors.newFixedThreadPool(CLIENTS);
|
||||||
|
|
||||||
|
List<Callable<Long>> clientTasks = new ArrayList<>();
|
||||||
|
|
||||||
|
for(int i=0; i<CLIENTS; i++) {
|
||||||
|
clientTasks.add(() ->
|
||||||
|
{
|
||||||
|
try (Socket client = clientSocketProvider.newSocket("localhost", _connector.getLocalPort());
|
||||||
|
OutputStream out = client.getOutputStream();
|
||||||
|
InputStream in = client.getInputStream())
|
||||||
|
{
|
||||||
|
client.setSoTimeout(30000);
|
||||||
|
|
||||||
|
String request = "" +
|
||||||
|
"GET / HTTP/1.0\r\n" +
|
||||||
|
"host: localhost\r\n" +
|
||||||
|
"\r\n";
|
||||||
|
|
||||||
|
// Write GET request
|
||||||
|
out.write(request.getBytes(StandardCharsets.UTF_8));
|
||||||
|
out.flush();
|
||||||
|
|
||||||
|
TimeUnit.MILLISECONDS.sleep(1500);
|
||||||
|
|
||||||
|
// Read Response
|
||||||
|
long bodyCount = 0;
|
||||||
|
long len;
|
||||||
|
|
||||||
|
byte buf[] = new byte[1024];
|
||||||
|
|
||||||
|
while((len = in.read(buf,0,buf.length)) != -1)
|
||||||
|
{
|
||||||
|
for(int x=0; x<len; x++)
|
||||||
|
{
|
||||||
|
if(buf[x] == '!') bodyCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bodyCount;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
List<Future<Long>> responses = clientExecutors.invokeAll(clientTasks, 60, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
long expected = BUFFERS * BUFFER_SIZE;
|
||||||
|
for (Future<Long> responseFut : responses)
|
||||||
|
{
|
||||||
|
Long bodyCount = responseFut.get();
|
||||||
|
assertThat(bodyCount.longValue(), is(expected));
|
||||||
|
}
|
||||||
|
} finally
|
||||||
|
{
|
||||||
|
clientExecutors.shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected static class WriteHandler extends AbstractHandler
|
protected static class WriteHandler extends AbstractHandler
|
||||||
{
|
{
|
||||||
byte[] content=new byte[BUFFER_SIZE];
|
byte[] content=new byte[BUFFER_SIZE];
|
||||||
{
|
{
|
||||||
Arrays.fill(content,(byte)'x');
|
// Using a character that will not show up in a HTTP response header
|
||||||
|
Arrays.fill(content,(byte)'!');
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -398,6 +398,4 @@ public class ThreadStarvationTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue