Merge remote-tracking branch 'origin/jetty-9.4.x' into jetty-10.0.x
This commit is contained in:
commit
30f6132117
|
@ -1,5 +1,6 @@
|
|||
#!groovy
|
||||
|
||||
// in case of change update method isMainBuild
|
||||
def jdks = ["jdk8","jdk9","jdk10","jdk11"]
|
||||
def oss = ["linux"]
|
||||
def builds = [:]
|
||||
|
@ -21,10 +22,11 @@ def getFullBuild(jdk, os) {
|
|||
def mvnName = 'maven3.5'
|
||||
def localRepo = "${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}" // ".repository" //
|
||||
def settingsName = 'oss-settings.xml'
|
||||
def mavenOpts = '-Xms1g -Xmx4g -Djava.awt.headless=true'
|
||||
|
||||
// Environment
|
||||
List mvnEnv = ["PATH+MVN=${mvntool}/bin", "PATH+JDK=${jdktool}/bin", "JAVA_HOME=${jdktool}/", "MAVEN_HOME=${mvntool}"]
|
||||
mvnEnv.add("MAVEN_OPTS=-Xms256m -Xmx1024m -Djava.awt.headless=true")
|
||||
mvnEnv.add("MAVEN_OPTS=$mavenOpts")
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -46,6 +48,7 @@ def getFullBuild(jdk, os) {
|
|||
jdk: "$jdk",
|
||||
publisherStrategy: 'EXPLICIT',
|
||||
globalMavenSettingsConfig: settingsName,
|
||||
mavenOpts: mavenOpts,
|
||||
mavenLocalRepo: localRepo) {
|
||||
sh "mvn -V -B clean install -DskipTests -T6 -e"
|
||||
}
|
||||
|
@ -68,6 +71,7 @@ def getFullBuild(jdk, os) {
|
|||
jdk: "$jdk",
|
||||
publisherStrategy: 'EXPLICIT',
|
||||
globalMavenSettingsConfig: settingsName,
|
||||
mavenOpts: mavenOpts,
|
||||
mavenLocalRepo: localRepo) {
|
||||
sh "mvn -V -B javadoc:javadoc -T6 -e"
|
||||
}
|
||||
|
@ -91,37 +95,44 @@ def getFullBuild(jdk, os) {
|
|||
publisherStrategy: 'EXPLICIT',
|
||||
globalMavenSettingsConfig: settingsName,
|
||||
//options: [invokerPublisher(disabled: false)],
|
||||
mavenOpts: mavenOpts,
|
||||
mavenLocalRepo: localRepo) {
|
||||
sh "mvn -V -B install -Dmaven.test.failure.ignore=true -e -Pmongodb -T3 -DmavenHome=${mvntoolInvoker} -Dunix.socket.tmp="+env.JENKINS_HOME
|
||||
}
|
||||
// withMaven doesn't label..
|
||||
// Report failures in the jenkins UI
|
||||
junit testResults:'**/target/surefire-reports/TEST-*.xml,**/target/failsafe-reports/TEST-*.xml'
|
||||
// Collect up the jacoco execution results
|
||||
def jacocoExcludes =
|
||||
// build tools
|
||||
"**/org/eclipse/jetty/ant/**" + ",**/org/eclipse/jetty/maven/**" +
|
||||
",**/org/eclipse/jetty/jspc/**" +
|
||||
// example code / documentation
|
||||
",**/org/eclipse/jetty/embedded/**" + ",**/org/eclipse/jetty/asyncrest/**" +
|
||||
",**/org/eclipse/jetty/demo/**" +
|
||||
// special environments / late integrations
|
||||
",**/org/eclipse/jetty/gcloud/**" + ",**/org/eclipse/jetty/infinispan/**" +
|
||||
",**/org/eclipse/jetty/osgi/**" + ",**/org/eclipse/jetty/spring/**" +
|
||||
",**/org/eclipse/jetty/http/spi/**" +
|
||||
// test classes
|
||||
",**/org/eclipse/jetty/tests/**" + ",**/org/eclipse/jetty/test/**";
|
||||
step( [$class : 'JacocoPublisher',
|
||||
inclusionPattern: '**/org/eclipse/jetty/**/*.class',
|
||||
exclusionPattern: jacocoExcludes,
|
||||
execPattern : '**/target/jacoco.exec',
|
||||
classPattern : '**/target/classes',
|
||||
sourcePattern : '**/src/main/java'] )
|
||||
consoleParsers = [[parserName: 'JavaDoc'],
|
||||
[parserName: 'JavaC']];
|
||||
if (isMainBuild( jdk )) {
|
||||
// Collect up the jacoco execution results
|
||||
def jacocoExcludes =
|
||||
// build tools
|
||||
"**/org/eclipse/jetty/ant/**" + ",**/org/eclipse/jetty/maven/**" +
|
||||
",**/org/eclipse/jetty/jspc/**" +
|
||||
// example code / documentation
|
||||
",**/org/eclipse/jetty/embedded/**" + ",**/org/eclipse/jetty/asyncrest/**" +
|
||||
",**/org/eclipse/jetty/demo/**" +
|
||||
// special environments / late integrations
|
||||
",**/org/eclipse/jetty/gcloud/**" + ",**/org/eclipse/jetty/infinispan/**" +
|
||||
",**/org/eclipse/jetty/osgi/**" + ",**/org/eclipse/jetty/spring/**" +
|
||||
",**/org/eclipse/jetty/http/spi/**" +
|
||||
// test classes
|
||||
",**/org/eclipse/jetty/tests/**" + ",**/org/eclipse/jetty/test/**";
|
||||
step( [$class : 'JacocoPublisher',
|
||||
inclusionPattern: '**/org/eclipse/jetty/**/*.class',
|
||||
exclusionPattern: jacocoExcludes,
|
||||
execPattern : '**/target/jacoco.exec',
|
||||
classPattern : '**/target/classes',
|
||||
sourcePattern : '**/src/main/java'] )
|
||||
consoleParsers = [[parserName: 'Maven'],
|
||||
[parserName: 'JavaDoc'],
|
||||
[parserName: 'JavaC']];
|
||||
}
|
||||
|
||||
// Report on Maven and Javadoc warnings
|
||||
step( [$class : 'WarningsPublisher',
|
||||
consoleParsers: [[parserName: 'Maven'],
|
||||
[parserName: 'JavaDoc'],
|
||||
[parserName: 'JavaC']]] )
|
||||
consoleParsers: consoleParsers] )
|
||||
}
|
||||
if(isUnstable())
|
||||
{
|
||||
|
@ -143,6 +154,7 @@ def getFullBuild(jdk, os) {
|
|||
jdk: "$jdk",
|
||||
publisherStrategy: 'EXPLICIT',
|
||||
globalMavenSettingsConfig: settingsName,
|
||||
mavenOpts: mavenOpts,
|
||||
mavenLocalRepo: localRepo) {
|
||||
sh "mvn -f aggregates/jetty-all-compact3 -V -B -Pcompact3 clean install -T5"
|
||||
}
|
||||
|
@ -156,6 +168,10 @@ def getFullBuild(jdk, os) {
|
|||
}
|
||||
}
|
||||
|
||||
def isMainBuild(jdk) {
|
||||
return jdk == "jdk8"
|
||||
}
|
||||
|
||||
|
||||
// True if this build is part of the "active" branches
|
||||
// for Jetty.
|
||||
|
|
|
@ -63,7 +63,8 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact
|
|||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug(x);
|
||||
failure.addSuppressed(x);
|
||||
if (x != failure)
|
||||
failure.addSuppressed(x);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -76,7 +77,8 @@ public class ALPNServerConnectionFactory extends NegotiatingServerConnectionFact
|
|||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Could not initialize " + processor, x);
|
||||
failure.addSuppressed(x);
|
||||
if (x != failure)
|
||||
failure.addSuppressed(x);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -440,7 +440,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
int javaPlatform = 0;
|
||||
Object target = context.getAttribute(JavaVersion.JAVA_TARGET_PLATFORM);
|
||||
if (target!=null)
|
||||
javaPlatform = Integer.valueOf(target.toString());
|
||||
javaPlatform = Integer.parseInt(target.toString());
|
||||
AnnotationParser parser = createAnnotationParser(javaPlatform);
|
||||
_parserTasks = new ArrayList<ParserTask>();
|
||||
|
||||
|
@ -553,7 +553,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
|
|||
return ((Boolean)o).booleanValue();
|
||||
}
|
||||
//try system property to see if we should use multithreading
|
||||
return Boolean.valueOf(System.getProperty(MULTI_THREADED, Boolean.toString(DEFAULT_MULTI_THREADED)));
|
||||
return Boolean.parseBoolean(System.getProperty(MULTI_THREADED, Boolean.toString(DEFAULT_MULTI_THREADED)));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -45,6 +45,18 @@ tags: [connector]
|
|||
Modules for tag 'connector':
|
||||
----------------------------
|
||||
|
||||
Module: acceptratelimit
|
||||
: Enable a server wide accept rate limit
|
||||
Tags: connector
|
||||
Depend: server
|
||||
XML: etc/jetty-acceptratelimit.xml
|
||||
|
||||
Module: connectionlimit
|
||||
: Enable a server wide connection limit
|
||||
Tags: connector
|
||||
Depend: server
|
||||
XML: etc/jetty-connectionlimit.xml
|
||||
|
||||
Module: http
|
||||
: Enables a HTTP connector on the server.
|
||||
: By default HTTP/1 is support, but HTTP2C can
|
||||
|
@ -52,7 +64,6 @@ Modules for tag 'connector':
|
|||
Tags: connector, http
|
||||
Depend: server
|
||||
XML: etc/jetty-http.xml
|
||||
Enabled: ${jetty.base}/start.ini
|
||||
|
||||
Module: http-forwarded
|
||||
: Adds a forwarded request customizer to the HTTP Connector
|
||||
|
@ -285,6 +296,20 @@ Making changes to the associated Jetty XML file for connectors is *not* recommen
|
|||
If you do wish to edit Jetty XML, please see our section on managing link:#[Jetty Home and Jetty Base] to ensure your Jetty Home remains a standard of truth for your implementation.
|
||||
____
|
||||
|
||||
==== Limiting Connections
|
||||
|
||||
Jetty also provides the means by which to limit connections to the server and/or contexts.
|
||||
This is provided by two different modules in the distribution.
|
||||
|
||||
`connectionlimit`::
|
||||
Applies a limit to the number of connections.
|
||||
If this limit is exceeded, new connections are suspended for the time specified (in milliseconds).
|
||||
`acceptratelimit`::
|
||||
Limits the rate at which new connections are accepted.
|
||||
If this limit is exceeded, new connections are suspended for the time specified (in milliseconds).
|
||||
|
||||
As with the modules listed above, these can be enabled by adding `--add-to-start=<module-name>` to the command line.
|
||||
|
||||
==== Advanced Configuration
|
||||
|
||||
Jetty primarily uses a single connector type called link:{JDURL}/org/eclipse/jetty/server/ServerConnector.html[ServerConnector].
|
||||
|
@ -430,7 +455,7 @@ This example HttpConfiguration may be used by reference to the ID "`httpConfig`"
|
|||
This same `httpConfig` is referenced by the link:{JDURL}/org/eclipse/jetty/server/handler/SecuredRedirectHandler.html[`SecuredRedirectHandler`] when redirecting secure requests.
|
||||
Please note that if your `httpConfig` does not include a `secureScheme` or `securePort` or there is no `HttpConfiguration` present these types of secured requests will be returned a `403` error.
|
||||
|
||||
For SSL based connectors (in `jetty-https.xml` and `jetty-http2.xml`), the common "`httpConfig`" instance is used as the basis to create an SSL specific configuration with ID "`sslHttpConfig`":
|
||||
For SSL-based connectors (in `jetty-https.xml` and `jetty-http2.xml`), the common "`httpConfig`" instance is used as the basis to create an SSL specific configuration with ID "`sslHttpConfig`":
|
||||
|
||||
[source, xml, subs="{sub-order}"]
|
||||
----
|
||||
|
|
|
@ -27,8 +27,24 @@ If you would like to report a security issue please follow these link:#security-
|
|||
[width="99%",cols="11%,19%,14%,9%,14%,14%,19%",options="header",]
|
||||
|=======================================================================
|
||||
|yyyy/mm/dd |ID |Exploitable |Severity |Affects |Fixed Version |Comment
|
||||
|2016/05/31 |http://www.ocert.org/advisories/ocert-2016-001.html[CVE-2016-4800] |high |high |>= 9.3.0, < = 9.3.8 |9.3.9
|
||||
|Alias vulnerability allowing access to protected resources within a webapp on Windows.
|
||||
|
||||
|2018/06/25 |CVE-2018-12538 |High |High |>= 9.4.0, < = 9.4.8 |9.4.9
|
||||
|https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12538[`HttpSessions` present specifically in the FileSystem’s storage could be hijacked/accessed by an unauthorized user.]
|
||||
|
||||
|2018/06/25 |CVE-2018-12536 |High |See https://cwe.mitre.org/data/definitions/209.html[CWE-202] |< = 9.4.10 |9.2.25, 9.3.24, 9.4.11
|
||||
|https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12536[`InvalidPathException` Message reveals webapp system path.]
|
||||
|
||||
|2018/06/25 |CVE-2017-7658 |See https://cwe.mitre.org/data/definitions/444.html[CWE-444] |See https://cwe.mitre.org/data/definitions/444.html[CWE-444] |< = 9.4.10 |9.2.25, 9.3.24, 9.4.11
|
||||
|https://cve.mitre.org/cgi-bin/cvename.cgi?name=2017-7658[Too Tolerant Parser, Double Content-Length + Transfer-Encoding + Whitespace.]
|
||||
|
||||
|2018/06/25 |CVE-2017-7657 |See https://cwe.mitre.org/data/definitions/444.html[CWE-444] |See https://cwe.mitre.org/data/definitions/444.html[CWE-444] |< = 9.4.10 |9.2.25, 9.3.24, 9.4.11
|
||||
|https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7657[HTTP/1.1 Request smuggling with carefully crafted body content (Does not apply to HTTP/1.0 or HTTP/2).]
|
||||
|
||||
|2018/06/25 |CVE-2017-7656 |See https://cwe.mitre.org/data/definitions/444.html[CWE-444] |See https://cwe.mitre.org/data/definitions/444.html[CWE-444] |< = 9.4.10 |9.2.25, 9.3.24, 9.4.11
|
||||
|https://cve.mitre.org/cgi-bin/cvename.cgi?name=2017-7656[HTTP Request Smuggling when used with invalid request headers (for HTTP/0.9).]
|
||||
|
||||
|2016/05/31 |CVE-2016-4800 |high |high |>= 9.3.0, < = 9.3.8 |9.3.9
|
||||
|http://www.ocert.org/advisories/ocert-2016-001.html[Alias vulnerability allowing access to protected resources within a webapp on Windows.]
|
||||
|
||||
|2015/02/24 |http://blog.gdssecurity.com/labs/2015/2/25/jetleak-vulnerability-remote-leakage-of-shared-buffers-in-je.html[CVE-2015-2080] |high |high |>=9.2.3 <9.2.9 |9.2.9
|
||||
|JetLeak exposure of past buffers during HttpParser error
|
||||
|
|
|
@ -204,7 +204,7 @@ public class HazelcastSessionDataStore
|
|||
if (sd.getExpiry() <= 0)
|
||||
return true; //never expires
|
||||
else
|
||||
return (Boolean.valueOf(sd.getExpiry() > System.currentTimeMillis())); //not expired yet
|
||||
return sd.getExpiry() > System.currentTimeMillis(); //not expired yet
|
||||
}
|
||||
|
||||
public String getCacheKey( String id )
|
||||
|
|
|
@ -29,6 +29,6 @@ Conscrypt is distributed under the Apache Licence 2.0
|
|||
https://github.com/google/conscrypt/blob/master/LICENSE
|
||||
|
||||
[ini]
|
||||
conscrypt.version?=1.0.0.RC11
|
||||
conscrypt.version?=1.1.4
|
||||
jetty.sslContext.provider?=Conscrypt
|
||||
|
||||
|
|
|
@ -72,12 +72,12 @@ public class HttpField
|
|||
|
||||
public int getIntValue()
|
||||
{
|
||||
return Integer.valueOf(_value);
|
||||
return Integer.parseInt(_value);
|
||||
}
|
||||
|
||||
public long getLongValue()
|
||||
{
|
||||
return Long.valueOf(_value);
|
||||
return Long.parseLong(_value);
|
||||
}
|
||||
|
||||
public String[] getValues()
|
||||
|
@ -348,7 +348,7 @@ public class HttpField
|
|||
|
||||
public IntValueHttpField(HttpHeader header, String name, String value)
|
||||
{
|
||||
this(header,name,value,Integer.valueOf(value));
|
||||
this(header,name,value,Integer.parseInt(value));
|
||||
}
|
||||
|
||||
public IntValueHttpField(HttpHeader header, String name, int intValue)
|
||||
|
@ -386,7 +386,7 @@ public class HttpField
|
|||
|
||||
public LongValueHttpField(HttpHeader header, String name, String value)
|
||||
{
|
||||
this(header,name,value,Long.valueOf(value));
|
||||
this(header,name,value,Long.parseLong(value));
|
||||
}
|
||||
|
||||
public LongValueHttpField(HttpHeader header, String name, long value)
|
||||
|
|
|
@ -516,7 +516,7 @@ public class MimeTypes
|
|||
*/
|
||||
public static Map<String,String> getAssumedEncodings()
|
||||
{
|
||||
return __inferredEncodings;
|
||||
return __assumedEncodings;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
|
|
@ -93,7 +93,7 @@ public class ProxyTest
|
|||
configuration.setSendServerVersion(false);
|
||||
String value = initParams.get("outputBufferSize");
|
||||
if (value != null)
|
||||
configuration.setOutputBufferSize(Integer.valueOf(value));
|
||||
configuration.setOutputBufferSize(Integer.parseInt(value));
|
||||
proxyConnector = new ServerConnector(proxy, new HTTP2ServerConnectionFactory(configuration));
|
||||
proxy.addConnector(proxyConnector);
|
||||
|
||||
|
|
|
@ -1550,7 +1550,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
failure.addSuppressed(x);
|
||||
if (x != failure)
|
||||
failure.addSuppressed(x);
|
||||
complete();
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ package org.eclipse.jetty.session.infinispan;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jetty.server.session.AbstractSessionDataStore;
|
||||
|
@ -258,7 +259,7 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
|
|||
{
|
||||
// TODO find a better way to do this that does not pull into memory the
|
||||
// whole session object
|
||||
final AtomicReference<Boolean> reference = new AtomicReference<>();
|
||||
final AtomicBoolean reference = new AtomicBoolean();
|
||||
final AtomicReference<Exception> exception = new AtomicReference<>();
|
||||
|
||||
Runnable load = new Runnable()
|
||||
|
@ -271,14 +272,14 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
|
|||
SessionData sd = load(id);
|
||||
if (sd == null)
|
||||
{
|
||||
reference.set(Boolean.FALSE);
|
||||
reference.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sd.getExpiry() <= 0)
|
||||
reference.set(Boolean.TRUE); //never expires
|
||||
reference.set(true); //never expires
|
||||
else
|
||||
reference.set(Boolean.valueOf(sd.getExpiry() > System.currentTimeMillis())); //not expired yet
|
||||
reference.set(sd.getExpiry() > System.currentTimeMillis()); //not expired yet
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -40,7 +40,7 @@ public abstract class AbstractConnection implements Connection
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(AbstractConnection.class);
|
||||
|
||||
private final List<Listener> listeners = new CopyOnWriteArrayList<>();
|
||||
private final List<Listener> _listeners = new CopyOnWriteArrayList<>();
|
||||
private final long _created=System.currentTimeMillis();
|
||||
private final EndPoint _endPoint;
|
||||
private final Executor _executor;
|
||||
|
@ -59,13 +59,13 @@ public abstract class AbstractConnection implements Connection
|
|||
@Override
|
||||
public void addListener(Listener listener)
|
||||
{
|
||||
listeners.add(listener);
|
||||
_listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(Listener listener)
|
||||
{
|
||||
listeners.remove(listener);
|
||||
_listeners.remove(listener);
|
||||
}
|
||||
|
||||
public int getInputBufferSize()
|
||||
|
@ -198,7 +198,7 @@ public abstract class AbstractConnection implements Connection
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onOpen {}", this);
|
||||
|
||||
for (Listener listener : listeners)
|
||||
for (Listener listener : _listeners)
|
||||
listener.onOpened(this);
|
||||
}
|
||||
|
||||
|
@ -208,7 +208,7 @@ public abstract class AbstractConnection implements Connection
|
|||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onClose {}",this);
|
||||
|
||||
for (Listener listener : listeners)
|
||||
for (Listener listener : _listeners)
|
||||
listener.onClosed(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -635,6 +635,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
|||
{
|
||||
this.channel = channel;
|
||||
this.attachment = attachment;
|
||||
_selectorManager.onAccepting(channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -655,6 +656,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
|||
catch (Throwable x)
|
||||
{
|
||||
closeNoExceptions(channel);
|
||||
_selectorManager.onAcceptFailed(channel,x);
|
||||
LOG.debug(x);
|
||||
}
|
||||
}
|
||||
|
@ -665,6 +667,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
|||
try
|
||||
{
|
||||
createEndPoint(channel, key);
|
||||
_selectorManager.onAccepted(channel);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
|
@ -678,6 +681,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
|||
closeNoExceptions(channel);
|
||||
LOG.warn(String.valueOf(failure));
|
||||
LOG.debug(failure);
|
||||
_selectorManager.onAcceptFailed(channel,failure);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,10 @@ import java.nio.channels.SelectionKey;
|
|||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EventListener;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.IntUnaryOperator;
|
||||
|
@ -61,6 +64,7 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump
|
|||
private final ManagedSelector[] _selectors;
|
||||
private final AtomicInteger _selectorIndex = new AtomicInteger();
|
||||
private final IntUnaryOperator _selectorIndexUpdate;
|
||||
private final List<AcceptListener> _acceptListeners = new ArrayList<>();
|
||||
private long _connectTimeout = DEFAULT_CONNECT_TIMEOUT;
|
||||
private ThreadPoolBudget.Lease _lease;
|
||||
|
||||
|
@ -405,5 +409,106 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump
|
|||
*/
|
||||
public abstract Connection newConnection(SelectableChannel channel, EndPoint endpoint, Object attachment) throws IOException;
|
||||
|
||||
public void addEventListener(EventListener listener)
|
||||
{
|
||||
if (isRunning())
|
||||
throw new IllegalStateException(this.toString());
|
||||
if (listener instanceof AcceptListener)
|
||||
addAcceptListener(AcceptListener.class.cast(listener));
|
||||
}
|
||||
|
||||
public void removeEventListener(EventListener listener)
|
||||
{
|
||||
if (isRunning())
|
||||
throw new IllegalStateException(this.toString());
|
||||
if (listener instanceof AcceptListener)
|
||||
removeAcceptListener(AcceptListener.class.cast(listener));
|
||||
}
|
||||
|
||||
public void addAcceptListener(AcceptListener listener)
|
||||
{
|
||||
if (!_acceptListeners.contains(listener))
|
||||
_acceptListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeAcceptListener(AcceptListener listener)
|
||||
{
|
||||
_acceptListeners.remove(listener);
|
||||
}
|
||||
|
||||
protected void onAccepting(SelectableChannel channel)
|
||||
{
|
||||
for (AcceptListener l : _acceptListeners)
|
||||
{
|
||||
try
|
||||
{
|
||||
l.onAccepting(channel);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
LOG.warn(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onAcceptFailed(SelectableChannel channel, Throwable cause)
|
||||
{
|
||||
for (AcceptListener l : _acceptListeners)
|
||||
{
|
||||
try
|
||||
{
|
||||
l.onAcceptFailed(channel,cause);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
LOG.warn(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onAccepted(SelectableChannel channel)
|
||||
{
|
||||
for (AcceptListener l : _acceptListeners)
|
||||
{
|
||||
try
|
||||
{
|
||||
l.onAccepted(channel);
|
||||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
LOG.warn(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>A listener for accept events.</p>
|
||||
* <p>This listener is called from either the selector or acceptor thread
|
||||
* and implementations must be non blocking and fast.</p>
|
||||
*/
|
||||
public interface AcceptListener extends EventListener
|
||||
{
|
||||
/**
|
||||
* Called immediately after a new SelectableChannel is accepted, but
|
||||
* before it has been submitted to the {@link SelectorManager}.
|
||||
* @param channel the accepted channel
|
||||
*/
|
||||
default void onAccepting(SelectableChannel channel) {}
|
||||
|
||||
/**
|
||||
* Called if the processing of the accepted channel fails prior to calling
|
||||
* {@link #onAccepted(SelectableChannel)}.
|
||||
* @param channel the accepted channel
|
||||
* @param cause the cause of the failure
|
||||
*/
|
||||
default void onAcceptFailed(SelectableChannel channel, Throwable cause) {}
|
||||
|
||||
/**
|
||||
* Called after the accepted channel has been allocated an {@link EndPoint}
|
||||
* and associated {@link Connection}, and after the onOpen notifications have
|
||||
* been called on both endPoint and connection.
|
||||
* @param channel the accepted channel
|
||||
*/
|
||||
default void onAccepted(SelectableChannel channel) {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -310,8 +310,11 @@ abstract public class WriteFlusher
|
|||
FailedState failed = (FailedState)_state.get();
|
||||
|
||||
Throwable cause = failed.getCause();
|
||||
for(Throwable t : suppressed)
|
||||
cause.addSuppressed(t);
|
||||
for (Throwable t : suppressed)
|
||||
{
|
||||
if (t != cause)
|
||||
cause.addSuppressed(t);
|
||||
}
|
||||
|
||||
callback.failed(cause);
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ public class BaseAuthModule implements ServerAuthModule, ServerAuthContext
|
|||
{
|
||||
String mandatory = (String) messageInfo.getMap().get(JaspiMessageInfo.MANDATORY_KEY);
|
||||
if (mandatory == null) return false;
|
||||
return Boolean.valueOf(mandatory);
|
||||
return Boolean.parseBoolean(mandatory);
|
||||
}
|
||||
|
||||
protected boolean login(Subject clientSubject, String credentials,
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
<debug>${it.debug}</debug>
|
||||
<addTestClassPath>true</addTestClassPath>
|
||||
<projectsDirectory>src/it</projectsDirectory>
|
||||
<timeoutInSeconds>60</timeoutInSeconds>
|
||||
<timeoutInSeconds>600</timeoutInSeconds>
|
||||
<cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
|
||||
<pomIncludes>
|
||||
<pomInclude>*/pom.xml</pomInclude>
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
org.xml.sax.helpers,
|
||||
*
|
||||
</Import-Package>
|
||||
<DynamicImport-Package>org.eclipse.jetty.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))"</DynamicImport-Package>
|
||||
<DynamicImport-Package>org.eclipse.jetty.*;version="[9.1,10.0)"</DynamicImport-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
org.xml.sax.helpers,
|
||||
*
|
||||
</Import-Package>
|
||||
<DynamicImport-Package>org.eclipse.jetty.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))"</DynamicImport-Package>
|
||||
<DynamicImport-Package>org.eclipse.jetty.*;version="[9.1,10.0)"</DynamicImport-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -59,20 +59,6 @@
|
|||
<!-- disable the uses directive: jetty will accomodate pretty much any versions
|
||||
of the packages it uses; no need to reflect some tight dependency determined at
|
||||
compilation time. -->
|
||||
<Import-Package>
|
||||
org.osgi.framework,
|
||||
org.osgi.service.cm;version="1.2.0",
|
||||
org.osgi.service.packageadmin,
|
||||
org.osgi.service.startlevel;version="1.0.o",
|
||||
org.osgi.service.url;version="1.0.0",
|
||||
org.osgi.util.tracker;version="1.3.0",
|
||||
org.slf4j;resolution:=optional,
|
||||
org.slf4j.spi;resolution:=optional,
|
||||
org.slf4j.helpers;resolution:=optional,
|
||||
org.xml.sax,
|
||||
org.xml.sax.helpers,
|
||||
*
|
||||
</Import-Package>
|
||||
<Export-Package>com.acme.osgi</Export-Package>
|
||||
<DynamicImport-Package>org.eclipse.jetty.*;version="[$(version;===;${parsedVersion.osgiVersion}),$(version;==+;${parsedVersion.osgiVersion}))"</DynamicImport-Package>
|
||||
</instructions>
|
||||
|
|
|
@ -100,9 +100,9 @@ public class TestJettyOSGiBootHTTP2Conscrypt
|
|||
res.add(CoreOptions.systemProperty("jetty.alpn.protocols").value("h2,http/1.1"));
|
||||
res.add(CoreOptions.systemProperty("jetty.sslContext.provider").value("Conscrypt"));
|
||||
|
||||
res.add(wrappedBundle(mavenBundle().groupId("org.conscrypt").artifactId("conscrypt-openjdk-uber").version("1.0.0.RC11"))
|
||||
res.add(wrappedBundle(mavenBundle().groupId("org.conscrypt").artifactId("conscrypt-openjdk-uber").version("1.1.4"))
|
||||
.imports("javax.net.ssl,*")
|
||||
.exports("org.conscrypt;version=1.0.0.RC11")
|
||||
.exports("org.conscrypt;version=1.1.4")
|
||||
.instructions("Bundle-NativeCode=META-INF/native/libconscrypt_openjdk_jni-linux-x86_64.so")
|
||||
.start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.osgi").artifactId("jetty-osgi-alpn").versionAsInProject().noStart());
|
||||
|
|
|
@ -131,7 +131,7 @@ public class AsyncMiddleManServletTest
|
|||
configuration.setSendServerVersion(false);
|
||||
String value = initParams.get("outputBufferSize");
|
||||
if (value != null)
|
||||
configuration.setOutputBufferSize(Integer.valueOf(value));
|
||||
configuration.setOutputBufferSize(Integer.parseInt(value));
|
||||
proxyConnector = new ServerConnector(proxy, new HttpConnectionFactory(configuration));
|
||||
proxy.addConnector(proxyConnector);
|
||||
|
||||
|
|
|
@ -160,7 +160,7 @@ public class ProxyServletTest
|
|||
configuration.setSendServerVersion(false);
|
||||
String value = initParams.get("outputBufferSize");
|
||||
if (value != null)
|
||||
configuration.setOutputBufferSize(Integer.valueOf(value));
|
||||
configuration.setOutputBufferSize(Integer.parseInt(value));
|
||||
proxyConnector = new ServerConnector(proxy, new HttpConnectionFactory(configuration));
|
||||
proxy.addConnector(proxyConnector);
|
||||
|
||||
|
|
|
@ -24,11 +24,6 @@
|
|||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
|
@ -38,5 +33,18 @@
|
|||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -18,63 +18,198 @@
|
|||
|
||||
package org.eclipse.jetty.rewrite.handler;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringReader;
|
||||
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.junit.Before;
|
||||
import org.eclipse.jetty.http.HttpTester;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
import org.junit.After;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CookiePatternRuleTest extends AbstractRuleTestCase
|
||||
public class CookiePatternRuleTest
|
||||
{
|
||||
@Before
|
||||
public void init() throws Exception
|
||||
private Server server;
|
||||
private LocalConnector localConnector;
|
||||
|
||||
public void startServer(CookiePatternRule rule) throws Exception
|
||||
{
|
||||
start(false);
|
||||
}
|
||||
server = new Server();
|
||||
localConnector = new LocalConnector(server);
|
||||
server.addConnector(localConnector);
|
||||
|
||||
@Test
|
||||
public void testSingleCookie() throws IOException
|
||||
{
|
||||
String[] cookie = {"cookie", "value"};
|
||||
assertCookies(cookie,true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAlready() throws IOException
|
||||
{
|
||||
String[] cookie = {"set", "already"};
|
||||
assertCookies(cookie,false);
|
||||
}
|
||||
RewriteHandler rewriteHandler = new RewriteHandler();
|
||||
// rewriteHandler.setRewriteRequestURI(false);
|
||||
rewriteHandler.addRule(rule);
|
||||
|
||||
private void assertCookies(String[] cookie,boolean setExpected) throws IOException
|
||||
{
|
||||
// set cookie pattern
|
||||
CookiePatternRule rule = new CookiePatternRule();
|
||||
rule.setPattern("*");
|
||||
rule.setName(cookie[0]);
|
||||
rule.setValue(cookie[1]);
|
||||
|
||||
// System.out.println(rule.toString());
|
||||
|
||||
// apply cookie pattern
|
||||
rule.apply(_request.getRequestURI(), _request, _response);
|
||||
|
||||
// verify
|
||||
HttpFields httpFields = _response.getHttpFields();
|
||||
Enumeration<String> e = httpFields.getValues(HttpHeader.SET_COOKIE.asString());
|
||||
boolean set = false;
|
||||
while (e.hasMoreElements())
|
||||
Handler dummyHandler = new AbstractHandler()
|
||||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
String[] result = (e.nextElement()).split("=");
|
||||
assertEquals(cookie[0], result[0]);
|
||||
assertEquals(cookie[1], result[1]);
|
||||
set=true;
|
||||
response.setContentType("text/plain");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
PrintWriter out = response.getWriter();
|
||||
out.printf("target=%s%n", target);
|
||||
out.printf("baseRequest.requestUri=%s%n", baseRequest.getRequestURI());
|
||||
out.printf("baseRequest.originalUri=%s%n", baseRequest.getOriginalURI());
|
||||
out.printf("request.requestUri=%s%n", request.getRequestURI());
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
|
||||
assertEquals(setExpected,set);
|
||||
};
|
||||
|
||||
HandlerList handlers = new HandlerList();
|
||||
handlers.addHandler(rewriteHandler);
|
||||
handlers.addHandler(dummyHandler);
|
||||
|
||||
server.setHandler(handlers);
|
||||
server.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServer() throws Exception
|
||||
{
|
||||
if (server != null)
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleCookie() throws Exception
|
||||
{
|
||||
CookiePatternRule rule = new CookiePatternRule();
|
||||
rule.setPattern("*");
|
||||
rule.setName("cookie");
|
||||
rule.setValue("value");
|
||||
|
||||
startServer(rule);
|
||||
|
||||
StringBuilder rawRequest = new StringBuilder();
|
||||
rawRequest.append("GET / HTTP/1.1\r\n");
|
||||
rawRequest.append("Host: local\r\n");
|
||||
rawRequest.append("Connection: close\r\n");
|
||||
rawRequest.append("\r\n");
|
||||
|
||||
String rawResponse = localConnector.getResponse(rawRequest.toString());
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
// verify
|
||||
HttpField setCookieField = response.getField(HttpHeader.SET_COOKIE);
|
||||
assertThat("response should have Set-Cookie", setCookieField, notNullValue());
|
||||
for (String value : setCookieField.getValues())
|
||||
{
|
||||
String[] result = value.split("=");
|
||||
assertThat(result[0], is("cookie"));
|
||||
assertThat(result[1], is("value"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAlready() throws Exception
|
||||
{
|
||||
CookiePatternRule rule = new CookiePatternRule();
|
||||
rule.setPattern("*");
|
||||
rule.setName("set");
|
||||
rule.setValue("already");
|
||||
|
||||
startServer(rule);
|
||||
|
||||
StringBuilder rawRequest = new StringBuilder();
|
||||
rawRequest.append("GET / HTTP/1.1\r\n");
|
||||
rawRequest.append("Host: local\r\n");
|
||||
rawRequest.append("Connection: close\r\n");
|
||||
rawRequest.append("Cookie: set=already\r\n"); // already present on request
|
||||
rawRequest.append("\r\n");
|
||||
|
||||
String rawResponse = localConnector.getResponse(rawRequest.toString());
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
// verify
|
||||
assertThat("response should not have Set-Cookie", response.getField(HttpHeader.SET_COOKIE), nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("See #2675 for details") // TODO: needs to be fixed in RuleContainer
|
||||
public void testUrlParameter() throws Exception
|
||||
{
|
||||
CookiePatternRule rule = new CookiePatternRule();
|
||||
rule.setPattern("*");
|
||||
rule.setName("fruit");
|
||||
rule.setValue("banana");
|
||||
|
||||
startServer(rule);
|
||||
|
||||
StringBuilder rawRequest = new StringBuilder();
|
||||
rawRequest.append("GET /other;fruit=apple HTTP/1.1\r\n");
|
||||
rawRequest.append("Host: local\r\n");
|
||||
rawRequest.append("Connection: close\r\n");
|
||||
rawRequest.append("\r\n");
|
||||
|
||||
String rawResponse = localConnector.getResponse(rawRequest.toString());
|
||||
HttpTester.Response response = HttpTester.parseResponse(rawResponse);
|
||||
|
||||
String responseContent = response.getContent();
|
||||
System.out.println(responseContent);
|
||||
assertResponseContentLine(responseContent, "baseRequest.requestUri=", "/other;fruit=apple");
|
||||
|
||||
// verify
|
||||
HttpField setCookieField = response.getField(HttpHeader.SET_COOKIE);
|
||||
assertThat("response should have Set-Cookie", setCookieField, notNullValue());
|
||||
for (String value : setCookieField.getValues())
|
||||
{
|
||||
String[] result = value.split("=");
|
||||
assertThat(result[0], is("fruit"));
|
||||
assertThat(result[1], is("banana"));
|
||||
}
|
||||
}
|
||||
|
||||
private void assertResponseContentLine(String responseContent, String linePrefix, String expectedEquals) throws IOException
|
||||
{
|
||||
String line;
|
||||
try (StringReader stringReader = new StringReader(responseContent);
|
||||
BufferedReader bufferedReader = new BufferedReader(stringReader))
|
||||
{
|
||||
boolean foundIt = false;
|
||||
while ((line = bufferedReader.readLine()) != null)
|
||||
{
|
||||
if (line.startsWith(linePrefix))
|
||||
{
|
||||
if (foundIt)
|
||||
{
|
||||
// duplicate lines
|
||||
fail("Found multiple lines prefixed with: " + linePrefix);
|
||||
}
|
||||
// found it
|
||||
String actualValue = line.substring(linePrefix.length());
|
||||
assertThat("Line:" + linePrefix, actualValue, is(expectedEquals));
|
||||
foundIt = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundIt)
|
||||
{
|
||||
fail("Unable to find line prefixed with: " + linePrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,10 +72,10 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
|
||||
String mna = configuration.getInitParameter("maxNonceAge");
|
||||
if (mna != null)
|
||||
setMaxNonceAge(Long.valueOf(mna));
|
||||
setMaxNonceAge(Long.parseLong(mna));
|
||||
String mnc = configuration.getInitParameter("maxNonceCount");
|
||||
if (mnc != null)
|
||||
setMaxNonceCount(Integer.valueOf(mnc));
|
||||
setMaxNonceCount(Integer.parseInt(mnc));
|
||||
}
|
||||
|
||||
public int getMaxNonceCount()
|
||||
|
|
|
@ -136,7 +136,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
if (error!=null)
|
||||
setErrorPage(error);
|
||||
String dispatch=configuration.getInitParameter(FormAuthenticator.__FORM_DISPATCH);
|
||||
_dispatch = dispatch==null?_dispatch:Boolean.valueOf(dispatch);
|
||||
_dispatch = dispatch==null?_dispatch:Boolean.parseBoolean(dispatch);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
<Call name="addBean">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.server.AcceptRateLimit">
|
||||
<Arg name="maxRate" type="int"><Property name="jetty.acceptratelimit.acceptRateLimit" default="1000" /></Arg>
|
||||
<Arg name="period" type="long"><Property name="jetty.acceptratelimit.period" default="1000" /></Arg>
|
||||
<Arg name="units"><Call class="java.util.concurrent.TimeUnit" name="valueOf"><Arg>
|
||||
<Property name="jetty.acceptratelimit.units" default="MILLISECONDS" />
|
||||
</Arg></Call></Arg>
|
||||
<Arg name="server"><Ref refid="Server" /></Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
</Configure>
|
|
@ -1,12 +1,16 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
<Call name="addBean">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.server.ConnectionLimit">
|
||||
<Arg type="int"><Property name="jetty.connection.limit" default="1000"/></Arg>
|
||||
<Arg><Ref refid="Server"/></Arg>
|
||||
<Arg name= "maxConnections" type="int">
|
||||
<Property name="jetty.connectionlimit.maxConnections" deprecated="jetty.connection.limit" default="1000" />
|
||||
</Arg>
|
||||
<Arg name="server">
|
||||
<Ref refid="Server" />
|
||||
</Arg>
|
||||
<Set name="idleTimeout"><Property name="jetty.connectionlimit.idleTimeout" default="1000" /></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[description]
|
||||
Enable a server wide accept rate limit
|
||||
|
||||
[tags]
|
||||
connector
|
||||
|
||||
[depend]
|
||||
server
|
||||
|
||||
[xml]
|
||||
etc/jetty-acceptratelimit.xml
|
||||
|
||||
[ini-template]
|
||||
## The limit of accepted connections
|
||||
#jetty.acceptratelimit.acceptRateLimit=1000
|
||||
|
||||
## The period over which the rate applies
|
||||
#jetty.acceptratelimit.period=1000
|
||||
|
||||
# The unit of time for the period
|
||||
#jetty.acceptratelimit.units=MILLISECONDS
|
|
@ -13,4 +13,9 @@ server
|
|||
etc/jetty-connectionlimit.xml
|
||||
|
||||
[ini-template]
|
||||
jetty.connection.limit=1000
|
||||
|
||||
## The limit of connections to apply
|
||||
#jetty.connectionlimit.maxConnections=1000
|
||||
|
||||
## The idle timeout to apply (in milliseconds) when connections are limited
|
||||
#jetty.connectionlimit.idleTimeout=1000
|
||||
|
|
|
@ -0,0 +1,265 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.io.SelectorManager;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.annotation.ManagedOperation;
|
||||
import org.eclipse.jetty.util.annotation.Name;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Container;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.statistic.RateStatistic;
|
||||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
|
||||
/**
|
||||
* <p>A Listener that limits the rate at which new connections are accepted</p>
|
||||
* <p>
|
||||
* If the limits are exceeded, accepting is suspended until the rate is again below
|
||||
* the limit, so incoming connections are held in the operating system accept
|
||||
* queue (no syn ack sent), where they may either timeout or wait for the server
|
||||
* to resume accepting.
|
||||
* </p>
|
||||
* <p>
|
||||
* It can be applied to an entire server or to a specific connector by adding it
|
||||
* via {@link Container#addBean(Object)}
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Usage:</b>
|
||||
* </p>
|
||||
* <pre>
|
||||
* Server server = new Server();
|
||||
* server.addBean(new AcceptLimit(100,5,TimeUnit.SECONDS,server));
|
||||
* ...
|
||||
* server.start();
|
||||
* </pre>
|
||||
* @see SelectorManager.AcceptListener
|
||||
*/
|
||||
@ManagedObject
|
||||
public class AcceptRateLimit extends AbstractLifeCycle implements SelectorManager.AcceptListener, Runnable
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AcceptRateLimit.class);
|
||||
|
||||
private final Server _server;
|
||||
private final List<AbstractConnector> _connectors = new ArrayList<>();
|
||||
private final Rate _rate;
|
||||
private final int _acceptRateLimit;
|
||||
private boolean _limiting;
|
||||
private Scheduler.Task _task;
|
||||
|
||||
public AcceptRateLimit(@Name("acceptRateLimit") int acceptRateLimit, @Name("period") long period, @Name("units") TimeUnit units, @Name("server") Server server)
|
||||
{
|
||||
_server = server;
|
||||
_acceptRateLimit = acceptRateLimit;
|
||||
_rate = new Rate(period,units);
|
||||
}
|
||||
|
||||
public AcceptRateLimit(@Name("limit") int limit, @Name("period") long period, @Name("units") TimeUnit units, @Name("connectors") Connector...connectors)
|
||||
{
|
||||
this(limit, period, units, (Server)null);
|
||||
for (Connector c: connectors)
|
||||
{
|
||||
if (c instanceof AbstractConnector)
|
||||
_connectors.add((AbstractConnector)c);
|
||||
else
|
||||
LOG.warn("Connector {} is not an AbstractConnector. Connections not limited",c);
|
||||
}
|
||||
}
|
||||
|
||||
@ManagedAttribute("The accept rate limit")
|
||||
public int getAcceptRateLimit()
|
||||
{
|
||||
return _acceptRateLimit;
|
||||
}
|
||||
|
||||
@ManagedAttribute("The accept rate period")
|
||||
public long getPeriod()
|
||||
{
|
||||
return _rate.getPeriod();
|
||||
}
|
||||
|
||||
@ManagedAttribute("The accept rate period units")
|
||||
public TimeUnit getUnits()
|
||||
{
|
||||
return _rate.getUnits();
|
||||
}
|
||||
|
||||
@ManagedAttribute("The current accept rate")
|
||||
public int getRate()
|
||||
{
|
||||
return _rate.getRate();
|
||||
}
|
||||
|
||||
@ManagedAttribute("The maximum accept rate achieved")
|
||||
public long getMaxRate()
|
||||
{
|
||||
return _rate.getMax();
|
||||
}
|
||||
|
||||
@ManagedOperation(value = "Resets the accept rate", impact = "ACTION")
|
||||
public void reset()
|
||||
{
|
||||
synchronized (_rate)
|
||||
{
|
||||
_rate.reset();
|
||||
if (_limiting)
|
||||
{
|
||||
_limiting = false;
|
||||
unlimit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void age(long period, TimeUnit units)
|
||||
{
|
||||
_rate.age(period,units);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
synchronized (_rate)
|
||||
{
|
||||
if (_server!=null)
|
||||
{
|
||||
for (Connector c: _server.getConnectors())
|
||||
{
|
||||
if (c instanceof AbstractConnector)
|
||||
_connectors.add((AbstractConnector)c);
|
||||
else
|
||||
LOG.warn("Connector {} is not an AbstractConnector. Connections not limited",c);
|
||||
}
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("AcceptLimit accept<{} rate<{} in {} for {}", _acceptRateLimit, _rate, _connectors);
|
||||
|
||||
for (AbstractConnector c : _connectors)
|
||||
c.addBean(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
synchronized (_rate)
|
||||
{
|
||||
if (_task!=null)
|
||||
_task.cancel();
|
||||
_task = null;
|
||||
for (AbstractConnector c : _connectors)
|
||||
c.removeBean(this);
|
||||
if (_server != null)
|
||||
_connectors.clear();
|
||||
_limiting = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void limit()
|
||||
{
|
||||
for (AbstractConnector c : _connectors)
|
||||
c.setAccepting(false);
|
||||
schedule();
|
||||
}
|
||||
|
||||
protected void unlimit()
|
||||
{
|
||||
for (AbstractConnector c : _connectors)
|
||||
c.setAccepting(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccepting(SelectableChannel channel)
|
||||
{
|
||||
synchronized (_rate)
|
||||
{
|
||||
int rate = _rate.record();
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("onAccepting rate {}/{} for {} {}",rate,_acceptRateLimit,_rate,channel);
|
||||
}
|
||||
if (rate > _acceptRateLimit)
|
||||
{
|
||||
if (!_limiting)
|
||||
{
|
||||
_limiting = true;
|
||||
|
||||
LOG.warn("AcceptLimit rate exceeded {}>{} on {}",rate,_acceptRateLimit,_connectors);
|
||||
limit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void schedule()
|
||||
{
|
||||
long oldest = _rate.getOldest(TimeUnit.MILLISECONDS);
|
||||
long period = TimeUnit.MILLISECONDS.convert(_rate.getPeriod(),_rate.getUnits());
|
||||
long delay = period-(oldest>0?oldest:0);
|
||||
if (delay < 0)
|
||||
delay = 0;
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("schedule {} {}",delay,TimeUnit.MILLISECONDS);
|
||||
_task = _connectors.get(0).getScheduler().schedule(this,delay,TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
synchronized (_rate)
|
||||
{
|
||||
_task = null;
|
||||
if (!isRunning())
|
||||
return;
|
||||
int rate = _rate.getRate();
|
||||
if (rate > _acceptRateLimit)
|
||||
{
|
||||
schedule();
|
||||
return;
|
||||
}
|
||||
if (_limiting)
|
||||
{
|
||||
_limiting = false;
|
||||
LOG.warn("AcceptLimit rate OK {}<={} on {}",rate,_acceptRateLimit,_connectors);
|
||||
unlimit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class Rate extends RateStatistic
|
||||
{
|
||||
private Rate(long period, TimeUnit units)
|
||||
{
|
||||
super(period,units);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void age(long period, TimeUnit units)
|
||||
{
|
||||
super.age(period,units);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -168,7 +168,7 @@ public class AsyncContextEvent extends AsyncEvent implements Runnable
|
|||
{
|
||||
if (_throwable==null)
|
||||
_throwable=e;
|
||||
else if (_throwable != e)
|
||||
else if (e != _throwable)
|
||||
_throwable.addSuppressed(e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,47 +18,66 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.nio.channels.SelectableChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.Connection.Listener;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.SelectorManager;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.annotation.Name;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Container;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* <p>A Connection Listener that limits the number of Connections.</p>
|
||||
* <p>A Listener that limits the number of Connections.</p>
|
||||
* <p>This listener applies a limit to the number of connections, which when
|
||||
* exceeded results in a call to {@link AbstractConnector#setAccepting(boolean)}
|
||||
* to prevent further connections being received. It can be applied to an
|
||||
* entire server or to a specific connector.
|
||||
* entire server or to a specific connector by adding it via {@link Container#addBean(Object)}
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Usage:</b>
|
||||
* </p>
|
||||
* <pre>
|
||||
* Server server = new Server();
|
||||
* server.addBean(new ConnectionLimit(5000,server));
|
||||
* ...
|
||||
* server.start();
|
||||
* </pre>
|
||||
* @see LowResourceMonitor
|
||||
* @see Connection.Listener
|
||||
* @see SelectorManager.AcceptListener
|
||||
*/
|
||||
@ManagedObject
|
||||
public class ConnectionLimit extends AbstractLifeCycle implements Listener
|
||||
public class ConnectionLimit extends AbstractLifeCycle implements Listener, SelectorManager.AcceptListener
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ConnectionLimit.class);
|
||||
|
||||
private final Server _server;
|
||||
private final List<AbstractConnector> _connectors = new ArrayList<>();
|
||||
private final Set<SelectableChannel> _accepting = new HashSet<>();
|
||||
private int _connections;
|
||||
private int _maxConnections;
|
||||
private boolean _accepting = true;
|
||||
private long _idleTimeout;
|
||||
private boolean _limiting = false;
|
||||
|
||||
public ConnectionLimit(int maxConnections, Server server)
|
||||
public ConnectionLimit(@Name("maxConnections") int maxConnections, @Name("server") Server server)
|
||||
{
|
||||
_maxConnections = maxConnections;
|
||||
_server = server;
|
||||
}
|
||||
|
||||
public ConnectionLimit(int maxConnections, Connector...connectors)
|
||||
public ConnectionLimit(@Name("maxConnections") int maxConnections, @Name("connectors") Connector...connectors)
|
||||
{
|
||||
_maxConnections = maxConnections;
|
||||
_server = null;
|
||||
this(maxConnections, (Server)null);
|
||||
for (Connector c: connectors)
|
||||
{
|
||||
if (c instanceof AbstractConnector)
|
||||
|
@ -67,84 +86,188 @@ public class ConnectionLimit extends AbstractLifeCycle implements Listener
|
|||
LOG.warn("Connector {} is not an AbstractConnection. Connections not limited",c);
|
||||
}
|
||||
}
|
||||
|
||||
@ManagedAttribute("The maximum number of connections allowed")
|
||||
public synchronized int getMaxConnections()
|
||||
|
||||
/**
|
||||
* @return If >= 0, the endpoint idle timeout in ms to apply when the connection limit is reached
|
||||
*/
|
||||
@ManagedAttribute("The endpoint idle timeout in ms to apply when the connection limit is reached")
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
return _maxConnections;
|
||||
return _idleTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param idleTimeout If >= 0 the endpoint idle timeout in ms to apply when the connection limit is reached
|
||||
*/
|
||||
public void setIdleTimeout(long idleTimeout)
|
||||
{
|
||||
_idleTimeout = idleTimeout;
|
||||
}
|
||||
|
||||
@ManagedAttribute("The maximum number of connections allowed")
|
||||
public int getMaxConnections()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
return _maxConnections;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void setMaxConnections(int max)
|
||||
public void setMaxConnections(int max)
|
||||
{
|
||||
_maxConnections = max;
|
||||
synchronized (this)
|
||||
{
|
||||
_maxConnections = max;
|
||||
}
|
||||
}
|
||||
|
||||
@ManagedAttribute("The current number of connections ")
|
||||
public synchronized int getConnections()
|
||||
public int getConnections()
|
||||
{
|
||||
return _connections;
|
||||
synchronized (this)
|
||||
{
|
||||
return _connections;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void doStart() throws Exception
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
if (_server!=null)
|
||||
synchronized (this)
|
||||
{
|
||||
for (Connector c: _server.getConnectors())
|
||||
if (_server != null)
|
||||
{
|
||||
if (c instanceof AbstractConnector)
|
||||
_connectors.add((AbstractConnector)c);
|
||||
else
|
||||
LOG.warn("Connector {} is not an AbstractConnection. Connections not limited",c);
|
||||
for (Connector c : _server.getConnectors())
|
||||
{
|
||||
if (c instanceof AbstractConnector)
|
||||
_connectors.add((AbstractConnector)c);
|
||||
else
|
||||
LOG.warn("Connector {} is not an AbstractConnector. Connections not limited",c);
|
||||
}
|
||||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("ConnectionLimit {} for {}",_maxConnections,_connectors);
|
||||
_connections = 0;
|
||||
_limiting = false;
|
||||
for (AbstractConnector c : _connectors)
|
||||
c.addBean(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
for (AbstractConnector c : _connectors)
|
||||
c.removeBean(this);
|
||||
_connections = 0;
|
||||
if (_server != null)
|
||||
_connectors.clear();
|
||||
}
|
||||
}
|
||||
|
||||
protected void check()
|
||||
{
|
||||
if ( (_accepting.size()+_connections) >= _maxConnections)
|
||||
{
|
||||
if (!_limiting)
|
||||
{
|
||||
_limiting = true;
|
||||
LOG.info("Connection Limit({}) reached for {}",_maxConnections,_connectors);
|
||||
limit();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_limiting)
|
||||
{
|
||||
_limiting = false;
|
||||
LOG.info("Connection Limit({}) cleared for {}",_maxConnections,_connectors);
|
||||
unlimit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("ConnectionLimit {} for {}",_maxConnections,_connectors);
|
||||
|
||||
_connections = 0;
|
||||
_accepting = true;
|
||||
|
||||
protected void limit()
|
||||
{
|
||||
for (AbstractConnector c : _connectors)
|
||||
c.addBean(this);
|
||||
{
|
||||
c.setAccepting(false);
|
||||
|
||||
if (_idleTimeout>0)
|
||||
{
|
||||
for (EndPoint endPoint : c.getConnectedEndPoints())
|
||||
endPoint.setIdleTimeout(_idleTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void unlimit()
|
||||
{
|
||||
for (AbstractConnector c : _connectors)
|
||||
{
|
||||
c.setAccepting(true);
|
||||
|
||||
if (_idleTimeout>0)
|
||||
{
|
||||
for (EndPoint endPoint : c.getConnectedEndPoints())
|
||||
endPoint.setIdleTimeout(c.getIdleTimeout());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccepting(SelectableChannel channel)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
_accepting.add(channel);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onAccepting ({}+{}) < {} {}",_accepting.size(),_connections,_maxConnections,channel);
|
||||
check();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void doStop() throws Exception
|
||||
public void onAcceptFailed(SelectableChannel channel, Throwable cause)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
_accepting.remove(channel);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onAcceptFailed ({}+{}) < {} {} {}",_accepting.size(),_connections,_maxConnections,channel,cause);
|
||||
check();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccepted(SelectableChannel channel)
|
||||
{
|
||||
for (AbstractConnector c : _connectors)
|
||||
c.removeBean(this);
|
||||
_connections = 0;
|
||||
if (_server!=null)
|
||||
_connectors.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onOpened(Connection connection)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onOpen {} < {} {}",_connections, _maxConnections, connection);
|
||||
if ( ++_connections >= _maxConnections && _accepting)
|
||||
{
|
||||
_accepting = false;
|
||||
LOG.info("Connection Limit({}) reached for {}",_maxConnections,_connectors);
|
||||
for (AbstractConnector c : _connectors)
|
||||
c.setAccepting(false);
|
||||
public void onOpened(Connection connection)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
_accepting.remove(connection.getEndPoint().getTransport());
|
||||
_connections++;
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onOpened ({}+{}) < {} {}",_accepting.size(),_connections,_maxConnections,connection);
|
||||
check();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onClosed(Connection connection)
|
||||
public void onClosed(Connection connection)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onClosed {} < {} {}",_connections, _maxConnections, connection);
|
||||
if ( --_connections < _maxConnections && !_accepting)
|
||||
synchronized (this)
|
||||
{
|
||||
_accepting = true;
|
||||
LOG.info("Connection Limit({}) cleared for {}",_maxConnections,_connectors);
|
||||
for (AbstractConnector c : _connectors)
|
||||
c.setAccepting(true);
|
||||
_connections--;
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onClosed ({}+{}) < {} {}",_accepting.size(),_connections,_maxConnections,connection);
|
||||
check();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -428,7 +428,7 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
|||
}
|
||||
else
|
||||
{
|
||||
if (failure != x)
|
||||
if (x != failure)
|
||||
failure.addSuppressed(x);
|
||||
minimalErrorResponse(failure);
|
||||
}
|
||||
|
@ -579,7 +579,8 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
|||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
failure.addSuppressed(e);
|
||||
if (e != failure)
|
||||
failure.addSuppressed(e);
|
||||
LOG.warn("ERROR dispatch failed", failure);
|
||||
// Try to send a minimal response.
|
||||
minimalErrorResponse(failure);
|
||||
|
@ -597,7 +598,8 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
|
|||
}
|
||||
catch (Throwable x)
|
||||
{
|
||||
failure.addSuppressed(x);
|
||||
if (x != failure)
|
||||
failure.addSuppressed(x);
|
||||
abort(failure);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -593,10 +593,11 @@ public class HttpChannelState
|
|||
{
|
||||
LOG.warn(x+" while invoking onTimeout listener " + listener);
|
||||
LOG.debug(x);
|
||||
if (error.get()==null)
|
||||
Throwable failure = error.get();
|
||||
if (failure == null)
|
||||
error.set(x);
|
||||
else
|
||||
error.get().addSuppressed(x);
|
||||
else if (x != failure)
|
||||
failure.addSuppressed(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,8 @@ import org.eclipse.jetty.util.thread.ThreadPool;
|
|||
* {@link Runtime} instance has {@link Runtime#totalMemory()} minus {@link Runtime#freeMemory()}
|
||||
* greater than {@link #getMaxMemory()}</li>
|
||||
* <li>If {@link #setMaxConnections(int)} is non zero then low resources is dected if the total number
|
||||
* of connections exceeds {@link #getMaxConnections()}</li>
|
||||
* of connections exceeds {@link #getMaxConnections()}. This feature is deprecated and replaced by
|
||||
* {@link ConnectionLimit}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Once low resources state is detected, the cause is logged and all existing connections returned
|
||||
|
@ -181,7 +182,12 @@ public class LowResourceMonitor extends AbstractLifeCycle
|
|||
_monitorThreads = monitorThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The maximum connections allowed for the monitored connectors before low resource handling is activated
|
||||
* @deprecated Replaced by ConnectionLimit
|
||||
*/
|
||||
@ManagedAttribute("The maximum connections allowed for the monitored connectors before low resource handling is activated")
|
||||
@Deprecated
|
||||
public int getMaxConnections()
|
||||
{
|
||||
return _maxConnections;
|
||||
|
@ -189,9 +195,13 @@ public class LowResourceMonitor extends AbstractLifeCycle
|
|||
|
||||
/**
|
||||
* @param maxConnections The maximum connections before low resources state is triggered
|
||||
* @deprecated Replaced by ConnectionLimit
|
||||
*/
|
||||
@Deprecated
|
||||
public void setMaxConnections(int maxConnections)
|
||||
{
|
||||
if (maxConnections>0)
|
||||
LOG.warn("LowResourceMonitor.setMaxConnections is deprecated. Use ConnectionLimit.");
|
||||
_maxConnections = maxConnections;
|
||||
}
|
||||
|
||||
|
|
|
@ -511,7 +511,7 @@ public class Request implements HttpServletRequest
|
|||
}
|
||||
else if (obj instanceof String)
|
||||
{
|
||||
maxFormContentSize = Integer.valueOf((String)obj);
|
||||
maxFormContentSize = Integer.parseInt((String)obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -527,7 +527,7 @@ public class Request implements HttpServletRequest
|
|||
}
|
||||
else if (obj instanceof String)
|
||||
{
|
||||
maxFormKeys = Integer.valueOf((String)obj);
|
||||
maxFormKeys = Integer.parseInt((String)obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2336,11 +2336,16 @@ public class Request implements HttpServletRequest
|
|||
}
|
||||
}
|
||||
|
||||
// charset should be:
|
||||
// 1. the charset set in the parts content type; else
|
||||
// 2. the default charset set in the _charset_ part; else
|
||||
// 3. the default charset set in the request.setCharacterEncoding; else
|
||||
// 4. the default charset set to UTF_8
|
||||
/*
|
||||
Select Charset to use for this part. (NOTE: charset behavior is for the part value only and not the part header/field names)
|
||||
1. Use the part specific charset as provided in that part's Content-Type header; else
|
||||
2. Use the overall default charset. Determined by:
|
||||
a. if part name _charset_ exists, use that part's value.
|
||||
b. if the request.getCharacterEncoding() returns a value, use that.
|
||||
(note, this can be either from the charset field on the request Content-Type
|
||||
header, or from a manual call to request.setCharacterEncoding())
|
||||
c. use utf-8.
|
||||
*/
|
||||
Charset defaultCharset;
|
||||
if (_charset_ != null)
|
||||
defaultCharset = Charset.forName(_charset_);
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.nio.channels.SelectableChannel;
|
|||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.EventListener;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
|
@ -228,6 +229,9 @@ public class ServerConnector extends AbstractNetworkConnector
|
|||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
for (EventListener l: getBeans(EventListener.class))
|
||||
_manager.addEventListener(l);
|
||||
|
||||
super.doStart();
|
||||
|
||||
if (getAcceptors()==0)
|
||||
|
@ -236,6 +240,14 @@ public class ServerConnector extends AbstractNetworkConnector
|
|||
_acceptor.set(_manager.acceptor(_acceptChannel));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
super.doStop();
|
||||
for (EventListener l: getBeans(EventListener.class))
|
||||
_manager.removeEventListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen()
|
||||
|
|
|
@ -93,7 +93,7 @@ public abstract class AbstractHandler extends ContainerLifeCycle implements Hand
|
|||
protected void doError(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
Object o = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
|
||||
int code = (o instanceof Integer)?((Integer)o).intValue():(o!=null?Integer.valueOf(o.toString()):500);
|
||||
int code = (o instanceof Integer)?((Integer)o).intValue():(o!=null?Integer.parseInt(o.toString()):500);
|
||||
o = request.getAttribute(RequestDispatcher.ERROR_MESSAGE);
|
||||
String reason = o!=null?o.toString():null;
|
||||
|
||||
|
|
|
@ -85,7 +85,8 @@ public class ContextHandlerCollection extends HandlerCollection
|
|||
{
|
||||
_contextBranches.clear();
|
||||
|
||||
if (getHandlers()==null)
|
||||
Handler[] handlers = getHandlers();
|
||||
if (handlers==null)
|
||||
{
|
||||
_pathBranches=new ArrayTernaryTrie<>(false,16);
|
||||
return;
|
||||
|
@ -93,7 +94,7 @@ public class ContextHandlerCollection extends HandlerCollection
|
|||
|
||||
// Create map of contextPath to handler Branch
|
||||
Map<String,Branch[]> map = new HashMap<>();
|
||||
for (Handler handler:getHandlers())
|
||||
for (Handler handler:handlers)
|
||||
{
|
||||
Branch branch=new Branch(handler);
|
||||
for (String contextPath : branch.getContextPaths())
|
||||
|
|
|
@ -54,25 +54,30 @@ public class DefaultHandler extends AbstractHandler
|
|||
private static final Logger LOG = Log.getLogger(DefaultHandler.class);
|
||||
|
||||
final long _faviconModified=(System.currentTimeMillis()/1000)*1000L;
|
||||
byte[] _favicon;
|
||||
final byte[] _favicon;
|
||||
boolean _serveIcon=true;
|
||||
boolean _showContexts=true;
|
||||
|
||||
public DefaultHandler()
|
||||
{
|
||||
byte[] favbytes=null;
|
||||
try
|
||||
{
|
||||
URL fav = this.getClass().getClassLoader().getResource("org/eclipse/jetty/favicon.ico");
|
||||
if (fav!=null)
|
||||
{
|
||||
Resource r = Resource.newResource(fav);
|
||||
_favicon=IO.readBytes(r.getInputStream());
|
||||
favbytes=IO.readBytes(r.getInputStream());
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_favicon = favbytes;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -90,7 +95,7 @@ public class DefaultHandler extends AbstractHandler
|
|||
String method=request.getMethod();
|
||||
|
||||
// little cheat for common request
|
||||
if (_serveIcon && _favicon!=null && HttpMethod.GET.is(method) && request.getRequestURI().equals("/favicon.ico"))
|
||||
if (_serveIcon && _favicon!=null && HttpMethod.GET.is(method) && target.equals("/favicon.ico"))
|
||||
{
|
||||
if (request.getDateHeader(HttpHeader.IF_MODIFIED_SINCE.toString())==_faviconModified)
|
||||
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
|
||||
|
@ -106,7 +111,6 @@ public class DefaultHandler extends AbstractHandler
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!_showContexts || !HttpMethod.GET.is(method) || !request.getRequestURI().equals("/"))
|
||||
{
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
|
@ -114,7 +118,7 @@ public class DefaultHandler extends AbstractHandler
|
|||
}
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
response.setContentType(MimeTypes.Type.TEXT_HTML.toString());
|
||||
response.setContentType(MimeTypes.Type.TEXT_HTML_8859_1.asString());
|
||||
|
||||
try (ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer(1500);)
|
||||
{
|
||||
|
|
|
@ -184,8 +184,9 @@ public class HandlerCollection extends AbstractHandlerContainer
|
|||
@Override
|
||||
protected void expandChildren(List<Handler> list, Class<?> byClass)
|
||||
{
|
||||
if (getHandlers()!=null)
|
||||
for (Handler h:getHandlers())
|
||||
Handler[] handlers = getHandlers();
|
||||
if (handlers!=null)
|
||||
for (Handler h:handlers)
|
||||
expandHandler(h, list, byClass);
|
||||
}
|
||||
|
||||
|
@ -207,6 +208,6 @@ public class HandlerCollection extends AbstractHandlerContainer
|
|||
public String toString()
|
||||
{
|
||||
Handler[] handlers=getHandlers();
|
||||
return super.toString()+(handlers==null?"[]":Arrays.asList(getHandlers()).toString());
|
||||
return super.toString()+(handlers==null?"[]":Arrays.asList(handlers).toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -354,7 +354,7 @@ public class AsyncRequestReadTest
|
|||
|
||||
BufferedReader in = request.getReader();
|
||||
PrintWriter out =httpResponse.getWriter();
|
||||
int read=Integer.valueOf(request.getParameter("read"));
|
||||
int read=Integer.parseInt(request.getParameter("read"));
|
||||
// System.err.println("read="+read);
|
||||
for (int i=read;i-->0;)
|
||||
{
|
||||
|
|
|
@ -63,10 +63,10 @@ public class DumpHandler extends AbstractHandler.ErrorDispatchHandler
|
|||
if (!isStarted())
|
||||
return;
|
||||
|
||||
if (Boolean.valueOf(request.getParameter("flush")))
|
||||
if (Boolean.parseBoolean(request.getParameter("flush")))
|
||||
response.flushBuffer();
|
||||
|
||||
if (Boolean.valueOf(request.getParameter("empty")))
|
||||
if (Boolean.parseBoolean(request.getParameter("empty")))
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.setStatus(200);
|
||||
|
@ -230,7 +230,7 @@ public class DumpHandler extends AbstractHandler.ErrorDispatchHandler
|
|||
writer.flush();
|
||||
|
||||
// commit now
|
||||
if (!Boolean.valueOf(request.getParameter("no-content-length")))
|
||||
if (!Boolean.parseBoolean(request.getParameter("no-content-length")))
|
||||
response.setContentLength(buf.size()+1000);
|
||||
response.addHeader("Before-Flush",response.isCommitted()?"Committed???":"Not Committed");
|
||||
buf.writeTo(out);
|
||||
|
|
|
@ -147,7 +147,7 @@ public class ExtendedServerTest extends HttpServerTestBase
|
|||
|
||||
String s=response.substring(response.indexOf("DispatchedAt=")+13);
|
||||
s=s.substring(0,s.indexOf('\n'));
|
||||
long dispatched=Long.valueOf(s);
|
||||
long dispatched=Long.parseLong(s);
|
||||
|
||||
Assert.assertThat(dispatched, Matchers.greaterThanOrEqualTo(start));
|
||||
Assert.assertThat(dispatched, Matchers.lessThan(end));
|
||||
|
|
|
@ -911,7 +911,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
// read and check the times are < 999ms
|
||||
String[] times = in.readLine().split(",");
|
||||
for (String t : times)
|
||||
Assert.assertTrue(Integer.valueOf(t) < 999);
|
||||
Assert.assertTrue(Integer.parseInt(t) < 999);
|
||||
|
||||
|
||||
// read the EOF chunk
|
||||
|
@ -941,7 +941,7 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
|
|||
// read and check the times are < 999ms
|
||||
times = in.readLine().split(",");
|
||||
for (String t : times)
|
||||
Assert.assertTrue(t, Integer.valueOf(t) < 999);
|
||||
Assert.assertTrue(t, Integer.parseInt(t) < 999);
|
||||
|
||||
// check close
|
||||
Assert.assertTrue(in.readLine() == null);
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.eclipse.jetty.server.LocalConnector.LocalEndPoint;
|
|||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
|
@ -304,6 +305,71 @@ public class NotAcceptingTest
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptRateLimit() throws Exception
|
||||
{
|
||||
AcceptRateLimit limit = new AcceptRateLimit(4,1,TimeUnit.HOURS, server);
|
||||
server.addBean(limit);
|
||||
server.setHandler(new HelloHandler());
|
||||
|
||||
server.start();
|
||||
|
||||
try (
|
||||
Socket async0 = new Socket("localhost",asyncConnector.getLocalPort());
|
||||
Socket async1 = new Socket("localhost",asyncConnector.getLocalPort());
|
||||
Socket async2 = new Socket("localhost",asyncConnector.getLocalPort());
|
||||
)
|
||||
{
|
||||
String expectedContent = "Hello" + System.lineSeparator();
|
||||
|
||||
for (Socket client : new Socket[]{async2})
|
||||
{
|
||||
HttpTester.Input in = HttpTester.from(client.getInputStream());
|
||||
client.getOutputStream().write("GET /test HTTP/1.1\r\nHost:localhost\r\n\r\n".getBytes());
|
||||
HttpTester.Response response = HttpTester.parseResponse(in);
|
||||
assertThat(response.getStatus(),is(200));
|
||||
assertThat(response.getContent(),is(expectedContent));
|
||||
}
|
||||
|
||||
assertThat(localConnector.isAccepting(),is(true));
|
||||
assertThat(blockingConnector.isAccepting(),is(true));
|
||||
assertThat(asyncConnector.isAccepting(),is(true));
|
||||
}
|
||||
|
||||
limit.age(45,TimeUnit.MINUTES);
|
||||
|
||||
try (
|
||||
Socket async0 = new Socket("localhost",asyncConnector.getLocalPort());
|
||||
Socket async1 = new Socket("localhost",asyncConnector.getLocalPort());
|
||||
)
|
||||
{
|
||||
String expectedContent = "Hello" + System.lineSeparator();
|
||||
|
||||
for (Socket client : new Socket[]{async1})
|
||||
{
|
||||
HttpTester.Input in = HttpTester.from(client.getInputStream());
|
||||
client.getOutputStream().write("GET /test HTTP/1.1\r\nHost:localhost\r\n\r\n".getBytes());
|
||||
HttpTester.Response response = HttpTester.parseResponse(in);
|
||||
assertThat(response.getStatus(),is(200));
|
||||
assertThat(response.getContent(),is(expectedContent));
|
||||
}
|
||||
|
||||
assertThat(localConnector.isAccepting(),is(false));
|
||||
assertThat(blockingConnector.isAccepting(),is(false));
|
||||
assertThat(asyncConnector.isAccepting(),is(false));
|
||||
}
|
||||
|
||||
limit.age(45,TimeUnit.MINUTES);
|
||||
assertThat(localConnector.isAccepting(),is(false));
|
||||
assertThat(blockingConnector.isAccepting(),is(false));
|
||||
assertThat(asyncConnector.isAccepting(),is(false));
|
||||
limit.run();
|
||||
assertThat(localConnector.isAccepting(),is(true));
|
||||
assertThat(blockingConnector.isAccepting(),is(true));
|
||||
assertThat(asyncConnector.isAccepting(),is(true));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testConnectionLimit() throws Exception
|
||||
{
|
||||
|
@ -311,7 +377,8 @@ public class NotAcceptingTest
|
|||
server.setHandler(new HelloHandler());
|
||||
|
||||
server.start();
|
||||
|
||||
|
||||
Log.getLogger(ConnectionLimit.class).debug("CONNECT:");
|
||||
try (
|
||||
LocalEndPoint local0 = localConnector.connect();
|
||||
LocalEndPoint local1 = localConnector.connect();
|
||||
|
@ -326,6 +393,7 @@ public class NotAcceptingTest
|
|||
{
|
||||
String expectedContent = "Hello" + System.lineSeparator();
|
||||
|
||||
Log.getLogger(ConnectionLimit.class).debug("LOCAL:");
|
||||
for (LocalEndPoint client: new LocalEndPoint[] {local0,local1,local2})
|
||||
{
|
||||
client.addInputAndExecute(BufferUtil.toBuffer("GET /test HTTP/1.1\r\nHost:localhost\r\n\r\n"));
|
||||
|
@ -334,6 +402,7 @@ public class NotAcceptingTest
|
|||
assertThat(response.getContent(),is(expectedContent));
|
||||
}
|
||||
|
||||
Log.getLogger(ConnectionLimit.class).debug("NETWORK:");
|
||||
for (Socket client : new Socket[]{blocking0,blocking1,blocking2,async0,async1,async2})
|
||||
{
|
||||
HttpTester.Input in = HttpTester.from(client.getInputStream());
|
||||
|
@ -361,7 +430,7 @@ public class NotAcceptingTest
|
|||
waitFor(blockingConnector::isAccepting,is(true),2*IDLE_TIMEOUT,TimeUnit.MILLISECONDS);
|
||||
waitFor(asyncConnector::isAccepting,is(true),2*IDLE_TIMEOUT,TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
|
||||
public static class HelloHandler extends AbstractHandler
|
||||
{
|
||||
public HelloHandler()
|
||||
|
@ -404,8 +473,5 @@ public class NotAcceptingTest
|
|||
catch(InterruptedException e)
|
||||
{}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server.handler;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.HttpTester;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DefaultHandlerTest
|
||||
{
|
||||
private Server server;
|
||||
private ServerConnector connector;
|
||||
private DefaultHandler handler;
|
||||
|
||||
@Before
|
||||
public void before() throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new ServerConnector(server);
|
||||
server.addConnector(connector);
|
||||
|
||||
|
||||
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
||||
handler = new DefaultHandler();
|
||||
HandlerCollection handlers = new HandlerCollection();
|
||||
handlers.setHandlers(new Handler[] { contexts, handler });
|
||||
server.setHandler(handlers);
|
||||
|
||||
handler.setServeIcon(true);
|
||||
handler.setShowContexts(true);
|
||||
|
||||
contexts.addHandler(new ContextHandler("/foo"));
|
||||
contexts.addHandler(new ContextHandler("/bar"));
|
||||
|
||||
server.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoot() throws Exception
|
||||
{
|
||||
try (Socket socket = new Socket("localhost", connector.getLocalPort()))
|
||||
{
|
||||
String request = "" +
|
||||
"GET / HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n";
|
||||
OutputStream output = socket.getOutputStream();
|
||||
output.write(request.getBytes(StandardCharsets.UTF_8));
|
||||
output.flush();
|
||||
|
||||
HttpTester.Input input = HttpTester.from(socket.getInputStream());
|
||||
HttpTester.Response response = HttpTester.parseResponse(input);
|
||||
|
||||
Assert.assertEquals(HttpStatus.NOT_FOUND_404, response.getStatus());
|
||||
Assert.assertEquals("text/html;charset=ISO-8859-1", response.get(HttpHeader.CONTENT_TYPE));
|
||||
|
||||
String content = new String(response.getContentBytes(),StandardCharsets.ISO_8859_1);
|
||||
Assert.assertThat(content,containsString("Contexts known to this server are:"));
|
||||
Assert.assertThat(content,containsString("/foo"));
|
||||
Assert.assertThat(content,containsString("/bar"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSomePath() throws Exception
|
||||
{
|
||||
try (Socket socket = new Socket("localhost", connector.getLocalPort()))
|
||||
{
|
||||
String request = "" +
|
||||
"GET /some/path HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n";
|
||||
OutputStream output = socket.getOutputStream();
|
||||
output.write(request.getBytes(StandardCharsets.UTF_8));
|
||||
output.flush();
|
||||
|
||||
HttpTester.Input input = HttpTester.from(socket.getInputStream());
|
||||
HttpTester.Response response = HttpTester.parseResponse(input);
|
||||
|
||||
Assert.assertEquals(HttpStatus.NOT_FOUND_404, response.getStatus());
|
||||
Assert.assertEquals("text/html;charset=ISO-8859-1", response.get(HttpHeader.CONTENT_TYPE));
|
||||
|
||||
String content = new String(response.getContentBytes(),StandardCharsets.ISO_8859_1);
|
||||
Assert.assertThat(content,not(containsString("Contexts known to this server are:")));
|
||||
Assert.assertThat(content,not(containsString("/foo")));
|
||||
Assert.assertThat(content,not(containsString("/bar")));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFavIcon() throws Exception
|
||||
{
|
||||
try (Socket socket = new Socket("localhost", connector.getLocalPort()))
|
||||
{
|
||||
String request = "" +
|
||||
"GET /favicon.ico HTTP/1.1\r\n" +
|
||||
"Host: localhost\r\n" +
|
||||
"\r\n";
|
||||
OutputStream output = socket.getOutputStream();
|
||||
output.write(request.getBytes(StandardCharsets.UTF_8));
|
||||
output.flush();
|
||||
|
||||
HttpTester.Input input = HttpTester.from(socket.getInputStream());
|
||||
HttpTester.Response response = HttpTester.parseResponse(input);
|
||||
|
||||
Assert.assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
Assert.assertEquals("image/x-icon", response.get(HttpHeader.CONTENT_TYPE));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -369,7 +369,7 @@ public class SSLEngineTest
|
|||
if (request.getParameter("dump")!=null)
|
||||
{
|
||||
ServletOutputStream out=response.getOutputStream();
|
||||
byte[] buf = new byte[Integer.valueOf(request.getParameter("dump"))];
|
||||
byte[] buf = new byte[Integer.parseInt(request.getParameter("dump"))];
|
||||
// System.err.println("DUMP "+buf.length);
|
||||
for (int i=0;i<buf.length;i++)
|
||||
buf[i]=(byte)('0'+(i%10));
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
#org.eclipse.jetty.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.server.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.server.ConnectionLimit.LEVEL=DEBUG
|
||||
#org.eclipse.jetty.server.AcceptRateLimit.LEVEL=DEBUG
|
|
@ -103,7 +103,7 @@ public class StatisticsServlet extends HttpServlet
|
|||
}
|
||||
}
|
||||
|
||||
if (Boolean.valueOf( req.getParameter("statsReset")))
|
||||
if (Boolean.parseBoolean( req.getParameter("statsReset")))
|
||||
{
|
||||
_statsHandler.statsReset();
|
||||
return;
|
||||
|
@ -113,7 +113,7 @@ public class StatisticsServlet extends HttpServlet
|
|||
if (wantXml == null)
|
||||
wantXml = req.getParameter("XML");
|
||||
|
||||
if (Boolean.valueOf(wantXml))
|
||||
if (Boolean.parseBoolean(wantXml))
|
||||
{
|
||||
sendXmlResponse(resp);
|
||||
}
|
||||
|
|
|
@ -651,15 +651,15 @@ public class AsyncContextTest
|
|||
{
|
||||
request.startAsync(request, response);
|
||||
|
||||
if (Boolean.valueOf(request.getParameter("dispatch")))
|
||||
if (Boolean.parseBoolean(request.getParameter("dispatch")))
|
||||
{
|
||||
request.getAsyncContext().dispatch();
|
||||
}
|
||||
|
||||
if (Boolean.valueOf(request.getParameter("complete")))
|
||||
if (Boolean.parseBoolean(request.getParameter("complete")))
|
||||
{
|
||||
response.getOutputStream().write("completeBeforeThrow".getBytes());
|
||||
if (Boolean.valueOf(request.getParameter("flush")))
|
||||
if (Boolean.parseBoolean(request.getParameter("flush")))
|
||||
response.flushBuffer();
|
||||
request.getAsyncContext().complete();
|
||||
}
|
||||
|
|
|
@ -482,7 +482,7 @@ public class AsyncServletIOTest
|
|||
|
||||
while (writes!=null && _w< writes.length)
|
||||
{
|
||||
int write=Integer.valueOf(writes[_w++]);
|
||||
int write=Integer.parseInt(writes[_w++]);
|
||||
|
||||
if (write==0)
|
||||
out.flush();
|
||||
|
|
|
@ -725,7 +725,7 @@ public class DoSFilter implements Filter
|
|||
byte[] result = new byte[16];
|
||||
for (int i = 0; i < result.length; i += 2)
|
||||
{
|
||||
int word = Integer.valueOf(ipv6Matcher.group(i / 2 + 1), 16);
|
||||
int word = Integer.parseInt(ipv6Matcher.group(i / 2 + 1), 16);
|
||||
result[i] = (byte)((word & 0xFF00) >>> 8);
|
||||
result[i + 1] = (byte)(word & 0xFF);
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ public class PushSessionCacheFilter implements Filter
|
|||
public void init(FilterConfig config) throws ServletException
|
||||
{
|
||||
if (config.getInitParameter("associateDelay") != null)
|
||||
_associateDelay = Long.valueOf(config.getInitParameter("associateDelay"));
|
||||
_associateDelay = Long.parseLong(config.getInitParameter("associateDelay"));
|
||||
|
||||
// Add a listener that is used to collect information about associated resource,
|
||||
// etags and modified dates
|
||||
|
|
|
@ -246,7 +246,7 @@ public class BaseBuilder
|
|||
|
||||
files.addAll(startArgs.getFiles());
|
||||
if (!files.isEmpty() && processFileResources(files))
|
||||
modified.set(Boolean.TRUE);
|
||||
modified.set(true);
|
||||
|
||||
return modified.get();
|
||||
}
|
||||
|
|
|
@ -59,6 +59,6 @@ public class TestFileInitializer extends FileInitializer
|
|||
}
|
||||
|
||||
StartLog.log("TESTING MODE","Skipping download of " + uri);
|
||||
return Boolean.TRUE;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,15 +55,15 @@ public class MultiException extends Exception
|
|||
super(DEFAULT_MESSAGE);
|
||||
this.nested = new ArrayList<>(nested);
|
||||
|
||||
if(nested.size() > 0) {
|
||||
if (nested.size() > 0)
|
||||
initCause(nested.get(0));
|
||||
}
|
||||
|
||||
for(Throwable t : nested) {
|
||||
this.addSuppressed(t);
|
||||
|
||||
for (Throwable t : nested)
|
||||
{
|
||||
if (t != this)
|
||||
addSuppressed(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void add(Throwable e)
|
||||
|
@ -196,8 +196,10 @@ public class MultiException extends Exception
|
|||
th = new MultiException(Collections.emptyList());
|
||||
|
||||
for (Throwable s : nested)
|
||||
{
|
||||
if (s!=th)
|
||||
th.addSuppressed(s);
|
||||
}
|
||||
if (Error.class.isInstance(th))
|
||||
throw (Error)th;
|
||||
throw (Exception)th;
|
||||
|
|
|
@ -75,7 +75,7 @@ public class MultiReleaseJarFile implements Closeable
|
|||
if (manifest==null)
|
||||
multiRelease = false;
|
||||
else
|
||||
multiRelease = Boolean.valueOf(String.valueOf(manifest.getMainAttributes().getValue("Multi-Release")));
|
||||
multiRelease = Boolean.parseBoolean(String.valueOf(manifest.getMainAttributes().getValue("Multi-Release")));
|
||||
|
||||
Map<String,VersionedJarEntry> map = new TreeMap<>();
|
||||
jarFile.stream()
|
||||
|
|
|
@ -234,23 +234,4 @@ public abstract class AbstractLifeCycle implements LifeCycle
|
|||
@Override public void lifeCycleStopped(LifeCycle event) {}
|
||||
@Override public void lifeCycleStopping(LifeCycle event) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* A LifeCycle Listener that will call stop if any failures are notified.
|
||||
*/
|
||||
public static final LifeCycle.Listener STOP_ON_FAILURE = new AbstractLifeCycleListener()
|
||||
{
|
||||
@Override
|
||||
public void lifeCycleFailure(LifeCycle lifecycle, Throwable cause)
|
||||
{
|
||||
try
|
||||
{
|
||||
lifecycle.stop();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
cause.addSuppressed(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -208,7 +208,7 @@ public class Log
|
|||
log_class = StdErrLog.class;
|
||||
LOG = new StdErrLog();
|
||||
|
||||
Boolean announce = Boolean.parseBoolean(__props.getProperty("org.eclipse.jetty.util.log.announce", "true"));
|
||||
boolean announce = Boolean.parseBoolean(__props.getProperty("org.eclipse.jetty.util.log.announce", "true"));
|
||||
if(announce)
|
||||
{
|
||||
LOG.debug("Logging to {} via {}", LOG, log_class.getName());
|
||||
|
|
|
@ -1051,10 +1051,14 @@ public class SslContextFactory extends AbstractLifeCycle implements Dumpable
|
|||
{
|
||||
String type = Objects.toString(getTrustStoreType(), getKeyStoreType());
|
||||
String provider = Objects.toString(getTrustStoreProvider(), getKeyStoreProvider());
|
||||
String passwd = Objects.toString(_trustStorePassword, Objects.toString(_keyStorePassword, null));
|
||||
if (resource == null)
|
||||
Password passwd = _trustStorePassword;
|
||||
if (resource == null || resource.equals(_keyStoreResource))
|
||||
{
|
||||
resource = _keyStoreResource;
|
||||
return CertificateUtils.getKeyStore(resource, type, provider, passwd);
|
||||
if (passwd == null)
|
||||
passwd = _keyStorePassword;
|
||||
}
|
||||
return CertificateUtils.getKeyStore(resource, type, provider, Objects.toString(passwd, null));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.util.statistic;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* <p>Statistics on a time sequence rate.</p>
|
||||
* <p>Calculates the rate at which the {@link #record()} method is called
|
||||
* over the configured period, retaining also the total count and maximum
|
||||
* rate achieved.</p>
|
||||
* <p>The implementation keeps a Deque of timestamps for all records for
|
||||
* the last time period, so this method is not suitable for large rates
|
||||
* unless a small time period is used.</p>
|
||||
*/
|
||||
public class RateStatistic
|
||||
{
|
||||
private final Deque<Long> _samples = new ArrayDeque<>();
|
||||
private final long _nanoPeriod;
|
||||
private final TimeUnit _units;
|
||||
private long _max;
|
||||
private long _count;
|
||||
|
||||
public RateStatistic(long period, TimeUnit units)
|
||||
{
|
||||
_nanoPeriod = TimeUnit.NANOSECONDS.convert(period,units);
|
||||
_units = units;
|
||||
}
|
||||
|
||||
public long getPeriod()
|
||||
{
|
||||
return _units.convert(_nanoPeriod,TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
public TimeUnit getUnits()
|
||||
{
|
||||
return _units;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the statistics.
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
_samples.clear();
|
||||
_max = 0;
|
||||
_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void update()
|
||||
{
|
||||
update(System.nanoTime());
|
||||
}
|
||||
|
||||
private void update(long now)
|
||||
{
|
||||
long expire = now - _nanoPeriod;
|
||||
Long head = _samples.peekFirst();
|
||||
while (head != null && head < expire)
|
||||
{
|
||||
_samples.removeFirst();
|
||||
head = _samples.peekFirst();
|
||||
}
|
||||
}
|
||||
|
||||
protected void age(long period, TimeUnit units)
|
||||
{
|
||||
long increment = TimeUnit.NANOSECONDS.convert(period,units);
|
||||
synchronized(this)
|
||||
{
|
||||
int size = _samples.size();
|
||||
for (int i=0; i<size; i++)
|
||||
_samples.addLast(_samples.removeFirst()-increment);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records a sample value.
|
||||
* @return the number of records in the current period.
|
||||
*/
|
||||
public int record()
|
||||
{
|
||||
long now = System.nanoTime();
|
||||
synchronized(this)
|
||||
{
|
||||
_count++;
|
||||
_samples.add(now);
|
||||
update(now);
|
||||
int rate = _samples.size();
|
||||
if (rate>_max)
|
||||
_max = rate;
|
||||
return rate;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of records in the current period
|
||||
*/
|
||||
public int getRate()
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
update();
|
||||
return _samples.size();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the max number of samples per period.
|
||||
*/
|
||||
public long getMax()
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
return _max;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param units the units of the return
|
||||
* @return the age of the oldest sample in the requested units
|
||||
*/
|
||||
public long getOldest(TimeUnit units)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
Long head = _samples.peekFirst();
|
||||
if (head==null)
|
||||
return -1;
|
||||
return units.convert(System.nanoTime()-head,TimeUnit.NANOSECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of samples recorded
|
||||
*/
|
||||
public long getCount()
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
return _count;
|
||||
}
|
||||
}
|
||||
|
||||
public String dump()
|
||||
{
|
||||
return dump(TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
public String dump(TimeUnit units)
|
||||
{
|
||||
long now = System.nanoTime();
|
||||
synchronized(this)
|
||||
{
|
||||
String samples = _samples.stream()
|
||||
.mapToLong(t -> units.convert(now - t, TimeUnit.NANOSECONDS))
|
||||
.mapToObj(Long::toString)
|
||||
.collect(Collectors.joining(System.lineSeparator()));
|
||||
return String.format("%s%n%s", toString(now), samples);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return toString(System.nanoTime());
|
||||
}
|
||||
|
||||
private String toString(long nanoTime)
|
||||
{
|
||||
synchronized(this)
|
||||
{
|
||||
update(nanoTime);
|
||||
return String.format("%s@%x{count=%d,max=%d,rate=%d per %d %s}",
|
||||
getClass().getSimpleName(), hashCode(),
|
||||
_count, _max, _samples.size(),
|
||||
_units.convert(_nanoPeriod,TimeUnit.NANOSECONDS), _units);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -90,10 +90,7 @@ public class CounterStatisticTest
|
|||
final CountDownLatch decBarrier = new CountDownLatch(N/2);
|
||||
|
||||
for (int i=N;i-->0;)
|
||||
{
|
||||
final int I = i;
|
||||
|
||||
|
||||
{
|
||||
threads[i]=(i>=N/2)
|
||||
?new Thread()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.util.statistic;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public class RateStatisticTest
|
||||
{
|
||||
@Test
|
||||
public void testRate()
|
||||
throws Exception
|
||||
{
|
||||
RateStatistic rs = new RateStatistic(1,TimeUnit.HOURS);
|
||||
assertThat(rs.getCount(),equalTo(0L));
|
||||
assertThat(rs.getRate(),equalTo(0));
|
||||
assertThat(rs.getMax(),equalTo(0L));
|
||||
|
||||
rs.record();
|
||||
assertThat(rs.getCount(),equalTo(1L));
|
||||
assertThat(rs.getRate(),equalTo(1));
|
||||
assertThat(rs.getMax(),equalTo(1L));
|
||||
|
||||
rs.age(35,TimeUnit.MINUTES);
|
||||
assertThat(rs.getCount(),equalTo(1L));
|
||||
assertThat(rs.getRate(),equalTo(1));
|
||||
assertThat(rs.getMax(),equalTo(1L));
|
||||
assertThat(rs.getOldest(TimeUnit.MINUTES),Matchers.is(35L));
|
||||
|
||||
rs.record();
|
||||
assertThat(rs.getCount(),equalTo(2L));
|
||||
assertThat(rs.getRate(),equalTo(2));
|
||||
assertThat(rs.getMax(),equalTo(2L));
|
||||
|
||||
rs.age(35,TimeUnit.MINUTES);
|
||||
assertThat(rs.getCount(),equalTo(2L));
|
||||
assertThat(rs.getRate(),equalTo(1));
|
||||
assertThat(rs.getMax(),equalTo(2L));
|
||||
|
||||
rs.record();
|
||||
assertThat(rs.getCount(),equalTo(3L));
|
||||
assertThat(rs.getRate(),equalTo(2));
|
||||
assertThat(rs.getMax(),equalTo(2L));
|
||||
|
||||
rs.age(35,TimeUnit.MINUTES);
|
||||
assertThat(rs.getCount(),equalTo(3L));
|
||||
assertThat(rs.getRate(),equalTo(1));
|
||||
assertThat(rs.getMax(),equalTo(2L));
|
||||
|
||||
}
|
||||
}
|
|
@ -76,7 +76,7 @@ public class TestConnection implements Producer
|
|||
{
|
||||
_request = request;
|
||||
_futureResult = futureResult;
|
||||
_blocking = Boolean.valueOf(request.get("blocking"));
|
||||
_blocking = Boolean.parseBoolean(request.get("blocking"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -478,7 +478,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
String async=node.getString("async-supported",false,true);
|
||||
if (async!=null)
|
||||
{
|
||||
boolean val = async.length()==0||Boolean.valueOf(async);
|
||||
boolean val = async.length()==0||Boolean.parseBoolean(async);
|
||||
switch (context.getMetaData().getOrigin(name+".servlet.async-supported"))
|
||||
{
|
||||
case NotSet:
|
||||
|
@ -515,7 +515,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
String enabled = node.getString("enabled", false, true);
|
||||
if (enabled!=null)
|
||||
{
|
||||
boolean is_enabled = enabled.length()==0||Boolean.valueOf(enabled);
|
||||
boolean is_enabled = enabled.length()==0||Boolean.parseBoolean(enabled);
|
||||
switch (context.getMetaData().getOrigin(name+".servlet.enabled"))
|
||||
{
|
||||
case NotSet:
|
||||
|
@ -1121,7 +1121,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
error = ErrorPageErrorHandler.GLOBAL_ERROR_PAGE;
|
||||
}
|
||||
else
|
||||
code=Integer.valueOf(error);
|
||||
code=Integer.parseInt(error);
|
||||
|
||||
String location = node.getString("location", false, true);
|
||||
if (!location.startsWith("/"))
|
||||
|
@ -1816,10 +1816,10 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
|
|||
|
||||
String async=node.getString("async-supported",false,true);
|
||||
if (async!=null)
|
||||
holder.setAsyncSupported(async.length()==0||Boolean.valueOf(async));
|
||||
holder.setAsyncSupported(async.length()==0||Boolean.parseBoolean(async));
|
||||
if (async!=null)
|
||||
{
|
||||
boolean val = async.length()==0||Boolean.valueOf(async);
|
||||
boolean val = async.length()==0||Boolean.parseBoolean(async);
|
||||
switch (context.getMetaData().getOrigin(name+".filter.async-supported"))
|
||||
{
|
||||
case NotSet:
|
||||
|
|
|
@ -535,7 +535,7 @@ public class WebAppClassLoader extends URLClassLoader
|
|||
{
|
||||
if (ex==null)
|
||||
ex = e;
|
||||
else
|
||||
else if (e != ex)
|
||||
ex.addSuppressed(e);
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,12 @@ public class WebSocketPolicy
|
|||
|
||||
public WebSocketPolicy clonePolicy()
|
||||
{
|
||||
WebSocketPolicy clone = new WebSocketPolicy(this.behavior);
|
||||
return clonePolicy(this.behavior);
|
||||
}
|
||||
|
||||
public WebSocketPolicy clonePolicy(WebSocketBehavior behavior)
|
||||
{
|
||||
WebSocketPolicy clone = new WebSocketPolicy(behavior);
|
||||
clone.idleTimeout = this.idleTimeout;
|
||||
clone.maxTextMessageSize = this.maxTextMessageSize;
|
||||
clone.maxTextMessageBufferSize = this.maxTextMessageBufferSize;
|
||||
|
|
|
@ -170,7 +170,7 @@ public class ExtensionConfig
|
|||
{
|
||||
return defValue;
|
||||
}
|
||||
return Integer.valueOf(val);
|
||||
return Integer.parseInt(val);
|
||||
}
|
||||
|
||||
public final String getParameter(String key, String defValue)
|
||||
|
|
|
@ -21,6 +21,8 @@ package org.eclipse.jetty.websocket.client;
|
|||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
|
||||
|
@ -31,11 +33,13 @@ class DefaultHttpClientProvider
|
|||
{
|
||||
SslContextFactory sslContextFactory = null;
|
||||
Executor executor = null;
|
||||
ByteBufferPool bufferPool = null;
|
||||
|
||||
if (scope != null)
|
||||
{
|
||||
sslContextFactory = scope.getSslContextFactory();
|
||||
executor = scope.getExecutor();
|
||||
bufferPool = scope.getBufferPool();
|
||||
}
|
||||
|
||||
if (sslContextFactory == null)
|
||||
|
@ -53,6 +57,13 @@ class DefaultHttpClientProvider
|
|||
executor = threadPool;
|
||||
}
|
||||
client.setExecutor(executor);
|
||||
|
||||
if (bufferPool == null)
|
||||
{
|
||||
bufferPool = new MappedByteBufferPool();
|
||||
}
|
||||
client.setByteBufferPool(bufferPool);
|
||||
|
||||
return client;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,12 +31,11 @@ import java.util.Set;
|
|||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.util.DecoratedObjectFactory;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
|
@ -57,7 +56,6 @@ import org.eclipse.jetty.websocket.common.SessionFactory;
|
|||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSessionFactory;
|
||||
import org.eclipse.jetty.websocket.common.extensions.WebSocketExtensionFactory;
|
||||
import org.eclipse.jetty.websocket.common.scopes.DelegatedContainerScope;
|
||||
import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
|
||||
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
|
||||
|
||||
|
@ -71,14 +69,15 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
// From HttpClient
|
||||
private final HttpClient httpClient;
|
||||
|
||||
// The container
|
||||
private final WebSocketContainerScope containerScope;
|
||||
// CDI layer
|
||||
private final Supplier<DecoratedObjectFactory> objectFactorySupplier;
|
||||
|
||||
// WebSocket Specifics
|
||||
private final WebSocketPolicy policy;
|
||||
private final WebSocketExtensionFactory extensionRegistry;
|
||||
private SessionFactory sessionFactory;
|
||||
private final List<WebSocketSession.Listener> listeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
private final int id = ThreadLocalRandom.current().nextInt();
|
||||
|
||||
// defaults to true for backwards compatibility
|
||||
private boolean stopAtShutdown = true;
|
||||
|
||||
|
@ -87,9 +86,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
*/
|
||||
public WebSocketClient()
|
||||
{
|
||||
// Create synthetic HttpClient
|
||||
this(HttpClientProvider.get(null));
|
||||
addBean(this.httpClient);
|
||||
this((HttpClient)null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,7 +97,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
*/
|
||||
public WebSocketClient(HttpClient httpClient)
|
||||
{
|
||||
this(httpClient,new DecoratedObjectFactory());
|
||||
this(httpClient, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,10 +110,20 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
*/
|
||||
public WebSocketClient(HttpClient httpClient, DecoratedObjectFactory objectFactory)
|
||||
{
|
||||
this.containerScope = new SimpleContainerScope(WebSocketPolicy.newClientPolicy(),new MappedByteBufferPool(),objectFactory);
|
||||
this.httpClient = httpClient;
|
||||
this.extensionRegistry = new WebSocketExtensionFactory(containerScope);
|
||||
this.sessionFactory = new WebSocketSessionFactory(containerScope);
|
||||
this(new SimpleContainerScope(new WebSocketPolicy(WebSocketBehavior.CLIENT), null, null, null, objectFactory), null, null, httpClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new WebSocketClient
|
||||
*
|
||||
* @param sslContextFactory
|
||||
* ssl context factory to use
|
||||
* @deprecated use {@link #WebSocketClient(HttpClient)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public WebSocketClient(SslContextFactory sslContextFactory)
|
||||
{
|
||||
this(sslContextFactory,null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,12 +131,11 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
*
|
||||
* @param executor
|
||||
* the executor to use
|
||||
* @deprecated use {@link #WebSocketClient(HttpClient)} instead
|
||||
*/
|
||||
public WebSocketClient(Executor executor)
|
||||
{
|
||||
this(new HttpClient());
|
||||
this.httpClient.setExecutor(executor);
|
||||
|
||||
this(null, executor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,24 +143,12 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
*
|
||||
* @param bufferPool
|
||||
* byte buffer pool to use
|
||||
* @deprecated use {@link #WebSocketClient(HttpClient)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public WebSocketClient(ByteBufferPool bufferPool)
|
||||
{
|
||||
this(new HttpClient());
|
||||
addBean(this.httpClient);
|
||||
this.httpClient.setByteBufferPool(bufferPool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new WebSocketClient
|
||||
*
|
||||
* @param sslContextFactory
|
||||
* ssl context factory to use
|
||||
*/
|
||||
public WebSocketClient(SslContextFactory sslContextFactory)
|
||||
{
|
||||
this(new HttpClient(sslContextFactory));
|
||||
addBean(this.httpClient);
|
||||
this(null, null, bufferPool);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,12 +158,12 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
* ssl context factory to use
|
||||
* @param executor
|
||||
* the executor to use
|
||||
* @deprecated use {@link #WebSocketClient(HttpClient)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public WebSocketClient(SslContextFactory sslContextFactory, Executor executor)
|
||||
{
|
||||
this(new HttpClient(sslContextFactory));
|
||||
addBean(this.httpClient);
|
||||
this.httpClient.setExecutor(executor);
|
||||
this(sslContextFactory, executor, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -181,7 +175,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
*/
|
||||
public WebSocketClient(WebSocketContainerScope scope)
|
||||
{
|
||||
this(scope.getSslContextFactory(),scope.getExecutor(),scope.getBufferPool(),scope.getObjectFactory());
|
||||
this(scope, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -212,7 +206,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
*/
|
||||
public WebSocketClient(SslContextFactory sslContextFactory, Executor executor, ByteBufferPool bufferPool)
|
||||
{
|
||||
this(sslContextFactory,executor,bufferPool,new DecoratedObjectFactory());
|
||||
this(sslContextFactory, executor, bufferPool, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -230,16 +224,8 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
*/
|
||||
private WebSocketClient(SslContextFactory sslContextFactory, Executor executor, ByteBufferPool bufferPool, DecoratedObjectFactory objectFactory)
|
||||
{
|
||||
this.httpClient = new HttpClient(sslContextFactory);
|
||||
this.httpClient.setExecutor(getExecutor(executor));
|
||||
this.httpClient.setByteBufferPool(bufferPool);
|
||||
this(new SimpleContainerScope(new WebSocketPolicy(WebSocketBehavior.CLIENT), bufferPool, executor, sslContextFactory, objectFactory));
|
||||
addBean(this.httpClient);
|
||||
|
||||
this.containerScope = new SimpleContainerScope(WebSocketPolicy.newClientPolicy(), bufferPool, objectFactory);
|
||||
|
||||
this.extensionRegistry = new WebSocketExtensionFactory(containerScope);
|
||||
|
||||
this.sessionFactory = new WebSocketSessionFactory(containerScope);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -269,20 +255,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
*/
|
||||
public WebSocketClient(final WebSocketContainerScope scope, SessionFactory sessionFactory, HttpClient httpClient)
|
||||
{
|
||||
WebSocketContainerScope clientScope;
|
||||
if (scope.getPolicy().getBehavior() == WebSocketBehavior.CLIENT)
|
||||
{
|
||||
clientScope = scope;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need to wrap the scope
|
||||
clientScope = new DelegatedContainerScope(WebSocketPolicy.newClientPolicy(), scope);
|
||||
}
|
||||
|
||||
this.containerScope = clientScope;
|
||||
|
||||
if(httpClient == null)
|
||||
if (httpClient == null)
|
||||
{
|
||||
this.httpClient = HttpClientProvider.get(scope);
|
||||
addBean(this.httpClient);
|
||||
|
@ -291,10 +264,14 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
{
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
this.extensionRegistry = new WebSocketExtensionFactory(containerScope);
|
||||
|
||||
this.sessionFactory = sessionFactory;
|
||||
// Ensure we get a Client version of the policy.
|
||||
this.policy = scope.getPolicy().clonePolicy(WebSocketBehavior.CLIENT);
|
||||
// Support Late Binding of Object Factory (for CDI)
|
||||
this.objectFactorySupplier = () -> scope.getObjectFactory();
|
||||
this.extensionRegistry = new WebSocketExtensionFactory(this);
|
||||
|
||||
this.sessionFactory = sessionFactory == null ? new WebSocketSessionFactory(this) : sessionFactory;
|
||||
}
|
||||
|
||||
public Future<Session> connect(Object websocket, URI toUri) throws IOException
|
||||
|
@ -393,6 +370,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
init();
|
||||
|
||||
WebSocketUpgradeRequest wsReq = new WebSocketUpgradeRequest(this,httpClient,request);
|
||||
|
||||
wsReq.setUpgradeListener(upgradeListener);
|
||||
return wsReq.sendAsync();
|
||||
}
|
||||
|
@ -464,21 +442,6 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
return httpClient.getExecutor();
|
||||
}
|
||||
|
||||
// Internal getExecutor for defaulting to internal executor if not provided
|
||||
private Executor getExecutor(final Executor executor)
|
||||
{
|
||||
if (executor == null)
|
||||
{
|
||||
QueuedThreadPool threadPool = new QueuedThreadPool();
|
||||
String name = "WebSocketClient@" + hashCode();
|
||||
threadPool.setName(name);
|
||||
threadPool.setDaemon(true);
|
||||
return threadPool;
|
||||
}
|
||||
|
||||
return executor;
|
||||
}
|
||||
|
||||
public ExtensionFactory getExtensionFactory()
|
||||
{
|
||||
return extensionRegistry;
|
||||
|
@ -503,7 +466,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
@Deprecated
|
||||
public int getMaxBinaryMessageBufferSize()
|
||||
{
|
||||
return getPolicy().getMaxBinaryMessageSize();
|
||||
return getPolicy().getMaxBinaryMessageBufferSize();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -536,7 +499,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
@Deprecated
|
||||
public int getMaxTextMessageBufferSize()
|
||||
{
|
||||
return getPolicy().getMaxTextMessageSize();
|
||||
return getPolicy().getMaxTextMessageBufferSize();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -552,7 +515,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
@Override
|
||||
public DecoratedObjectFactory getObjectFactory()
|
||||
{
|
||||
return this.containerScope.getObjectFactory();
|
||||
return this.objectFactorySupplier.get();
|
||||
}
|
||||
|
||||
public Set<WebSocketSession> getOpenSessions()
|
||||
|
@ -563,7 +526,7 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
@Override
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
return this.containerScope.getPolicy();
|
||||
return this.policy;
|
||||
}
|
||||
|
||||
public SessionFactory getSessionFactory()
|
||||
|
@ -780,11 +743,27 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketCont
|
|||
return stopAtShutdown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof WebSocketClient)) return false;
|
||||
WebSocketClient that = (WebSocketClient) o;
|
||||
return Objects.equals(this.httpClient, that.httpClient) &&
|
||||
Objects.equals(this.policy, that.policy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(httpClient, policy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
final StringBuilder sb = new StringBuilder("WebSocketClient@");
|
||||
sb.append(Integer.toHexString(id));
|
||||
sb.append(Integer.toHexString(hashCode()));
|
||||
sb.append("[httpClient=").append(httpClient);
|
||||
sb.append(",openSessions.size=");
|
||||
sb.append(getOpenSessions().size());
|
||||
|
|
|
@ -335,11 +335,15 @@ public class FrameFlusher extends IteratingCallback
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
int aggSize = -1;
|
||||
ByteBuffer agg = aggregate;
|
||||
if (agg != null)
|
||||
aggSize = agg.position();
|
||||
return String.format("%s@%x[queueSize=%d,aggregateSize=%d,terminated=%s]",
|
||||
getClass().getSimpleName(),
|
||||
hashCode(),
|
||||
getQueueSize(),
|
||||
aggregate == null ? 0 : aggregate.position(),
|
||||
aggSize,
|
||||
terminated);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,9 +25,11 @@ import java.util.concurrent.Executor;
|
|||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.util.DecoratedObjectFactory;
|
||||
import org.eclipse.jetty.util.DeprecationWarning;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
|
||||
|
@ -35,7 +37,7 @@ public class SimpleContainerScope extends ContainerLifeCycle implements WebSocke
|
|||
{
|
||||
private final ByteBufferPool bufferPool;
|
||||
private final DecoratedObjectFactory objectFactory;
|
||||
private final WebSocketPolicy containerPolicy;
|
||||
private final WebSocketPolicy policy;
|
||||
private final Executor executor;
|
||||
protected final List<WebSocketSession.Listener> listeners = new CopyOnWriteArrayList<>();
|
||||
private SslContextFactory sslContextFactory;
|
||||
|
@ -53,26 +55,50 @@ public class SimpleContainerScope extends ContainerLifeCycle implements WebSocke
|
|||
|
||||
public SimpleContainerScope(WebSocketPolicy policy, ByteBufferPool bufferPool, DecoratedObjectFactory objectFactory)
|
||||
{
|
||||
this(policy, bufferPool, null, objectFactory);
|
||||
this(policy, bufferPool, (Executor) null, objectFactory);
|
||||
}
|
||||
|
||||
|
||||
public SimpleContainerScope(WebSocketPolicy policy, ByteBufferPool bufferPool, Executor executor, DecoratedObjectFactory objectFactory)
|
||||
{
|
||||
this.containerPolicy = policy;
|
||||
this(policy, bufferPool, executor, null, objectFactory);
|
||||
}
|
||||
|
||||
public SimpleContainerScope(WebSocketPolicy policy, ByteBufferPool bufferPool, Executor executor, SslContextFactory ssl, DecoratedObjectFactory objectFactory)
|
||||
{
|
||||
this.policy = policy;
|
||||
this.bufferPool = bufferPool;
|
||||
|
||||
if (objectFactory == null)
|
||||
{
|
||||
this.objectFactory = new DecoratedObjectFactory();
|
||||
this.objectFactory.addDecorator(new DeprecationWarning());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.objectFactory = objectFactory;
|
||||
}
|
||||
|
||||
if(ssl == null)
|
||||
{
|
||||
this.sslContextFactory = new SslContextFactory();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.sslContextFactory = ssl;
|
||||
}
|
||||
|
||||
if (executor == null)
|
||||
{
|
||||
QueuedThreadPool threadPool = new QueuedThreadPool();
|
||||
String name = "WebSocketContainer@" + hashCode();
|
||||
String behavior = "Container";
|
||||
if (policy != null)
|
||||
{
|
||||
if (policy.getBehavior() == WebSocketBehavior.CLIENT)
|
||||
behavior = "Client";
|
||||
else if (policy.getBehavior() == WebSocketBehavior.SERVER)
|
||||
behavior = "Server";
|
||||
}
|
||||
String name = String.format("WebSocket%s@%s", behavior, hashCode());
|
||||
threadPool.setName(name);
|
||||
threadPool.setDaemon(true);
|
||||
this.executor = threadPool;
|
||||
|
@ -105,7 +131,7 @@ public class SimpleContainerScope extends ContainerLifeCycle implements WebSocke
|
|||
@Override
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
return this.containerPolicy;
|
||||
return this.policy;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,7 +22,8 @@ import java.util.Set;
|
|||
|
||||
import javax.servlet.ServletContainerInitializer;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
|
||||
public class NativeWebSocketServletContainerInitializer implements ServletContainerInitializer
|
||||
{
|
||||
|
@ -33,14 +34,23 @@ public class NativeWebSocketServletContainerInitializer implements ServletContai
|
|||
NativeWebSocketConfiguration configuration = (NativeWebSocketConfiguration) context.getAttribute(KEY);
|
||||
if (configuration == null)
|
||||
{
|
||||
// Not provided to us, create a new default one.
|
||||
configuration = new NativeWebSocketConfiguration(context);
|
||||
context.setAttribute(KEY, configuration);
|
||||
|
||||
// Attach default configuration to context lifecycle
|
||||
if (context instanceof ContextHandler.Context)
|
||||
{
|
||||
ContextHandler handler = ((ContextHandler.Context)context).getContextHandler();
|
||||
// Let ContextHandler handle configuration lifecycle
|
||||
handler.addManaged(configuration);
|
||||
}
|
||||
}
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException
|
||||
public void onStartup(Set<Class<?>> c, ServletContext ctx)
|
||||
{
|
||||
// initialize
|
||||
getDefaultFrom(ctx);
|
||||
|
|
|
@ -321,17 +321,14 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
{
|
||||
if(this.objectFactory == null)
|
||||
{
|
||||
this.objectFactory = findDecorator();
|
||||
this.objectFactory = findDecoratedObjectFactory();
|
||||
}
|
||||
|
||||
if(this.executor == null)
|
||||
{
|
||||
this.executor = findExecutor();
|
||||
}
|
||||
|
||||
Objects.requireNonNull(this.objectFactory, DecoratedObjectFactory.class.getName());
|
||||
Objects.requireNonNull(this.executor, Executor.class.getName());
|
||||
|
||||
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
|
@ -339,7 +336,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
* Attempt to find the DecoratedObjectFactory that should be used.
|
||||
* @return the DecoratedObjectFactory that should be used. (never null)
|
||||
*/
|
||||
protected DecoratedObjectFactory findDecorator()
|
||||
private DecoratedObjectFactory findDecoratedObjectFactory()
|
||||
{
|
||||
DecoratedObjectFactory objectFactory;
|
||||
|
||||
|
@ -362,30 +359,45 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
* Attempt to find the Executor that should be used.
|
||||
* @return the Executor that should be used. (never null)
|
||||
*/
|
||||
protected Executor findExecutor()
|
||||
private Executor findExecutor()
|
||||
{
|
||||
if(context != null)
|
||||
// Try as bean
|
||||
Executor executor = getBean(Executor.class);
|
||||
if (executor != null)
|
||||
{
|
||||
// Attempt to pull Executor from ServletContext attribute
|
||||
Executor contextExecutor = (Executor) context.getAttribute("org.eclipse.jetty.server.Executor");
|
||||
if(contextExecutor != null)
|
||||
return executor;
|
||||
}
|
||||
|
||||
// Attempt to pull Executor from ServletContext attribute
|
||||
if (context != null)
|
||||
{
|
||||
// Try websocket specific one first
|
||||
Executor contextExecutor = (Executor) context.getAttribute("org.eclipse.jetty.websocket.Executor");
|
||||
if (contextExecutor != null)
|
||||
{
|
||||
return contextExecutor;
|
||||
}
|
||||
|
||||
// Attempt to pull Executor from Jetty Server, via ContextHandler
|
||||
// Try ContextHandler version
|
||||
contextExecutor = (Executor) context.getAttribute("org.eclipse.jetty.server.Executor");
|
||||
if (contextExecutor != null)
|
||||
{
|
||||
return contextExecutor;
|
||||
}
|
||||
|
||||
// Try Executor from Jetty Server
|
||||
ContextHandler contextHandler = ContextHandler.getContextHandler(context);
|
||||
if (contextHandler != null)
|
||||
{
|
||||
contextExecutor = contextHandler.getServer().getThreadPool();
|
||||
if(contextExecutor != null)
|
||||
if (contextExecutor != null) // This should always be true!
|
||||
{
|
||||
return contextExecutor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new one
|
||||
// All else fails, Create a new one
|
||||
QueuedThreadPool threadPool = new QueuedThreadPool();
|
||||
threadPool.setName("WebSocketServerFactory");
|
||||
addManaged(threadPool);
|
||||
|
|
|
@ -250,7 +250,7 @@ public class DelayedStartClientOnServerTest
|
|||
|
||||
List<String> threadNames = getThreadNames(server, (ContainerLifeCycle)container);
|
||||
assertNoHttpClientPoolThreads(threadNames);
|
||||
assertThat("Threads", threadNames, hasItem(containsString("WebSocketContainer@")));
|
||||
assertThat("Threads", threadNames, hasItem(containsString("WebSocketClient@")));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -258,7 +258,7 @@ public class DelayedStartClientOnServerTest
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(timeout = 5000)
|
||||
public void testHttpClientThreads_AfterServerConnectTo() throws Exception
|
||||
{
|
||||
Server server = new Server(0);
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -27,7 +27,7 @@
|
|||
<jsp.version>8.5.24.2</jsp.version>
|
||||
<!-- default values are unsupported, but required to be defined for reactor sanity reasons -->
|
||||
<alpn.version>undefined</alpn.version>
|
||||
<conscrypt.version>1.0.0.RC11</conscrypt.version>
|
||||
<conscrypt.version>1.1.4</conscrypt.version>
|
||||
<asm.version>6.2</asm.version>
|
||||
<jmh.version>1.20</jmh.version>
|
||||
<jmhjar.name>benchmarks</jmhjar.name>
|
||||
|
|
Loading…
Reference in New Issue