Merge remote-tracking branch 'origin/jetty-9.4.x' into jetty-10.0.x

This commit is contained in:
Joakim Erdfelt 2018-07-03 10:55:22 -05:00
commit 30f6132117
80 changed files with 1686 additions and 389 deletions

64
Jenkinsfile vendored
View File

@ -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.

View File

@ -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);
}
}

View File

@ -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)));
}

View File

@ -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}"]
----

View File

@ -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 FileSystems 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

View File

@ -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 )

View File

@ -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

View File

@ -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)

View File

@ -516,7 +516,7 @@ public class MimeTypes
*/
public static Map<String,String> getAssumedEncodings()
{
return __inferredEncodings;
return __assumedEncodings;
}
@Deprecated

View File

@ -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);

View File

@ -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();
}

View File

@ -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)
{

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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) {}
}
}

View File

@ -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);
}

View File

@ -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,

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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());

View File

@ -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);

View File

@ -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);

View File

@ -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>

View File

@ -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);
}
}
}
}

View File

@ -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()

View File

@ -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);
}
/* ------------------------------------------------------------ */

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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 &gt;= 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 &gt;= 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();
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}

View File

@ -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_);

View File

@ -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()

View File

@ -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;

View File

@ -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())

View File

@ -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);)
{

View File

@ -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());
}
}

View File

@ -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;)
{

View File

@ -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);

View File

@ -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));

View File

@ -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);

View File

@ -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)
{}
}
}
}

View File

@ -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));
}
}
}

View File

@ -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));

View File

@ -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

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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();

View File

@ -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);
}

View File

@ -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

View File

@ -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();
}

View File

@ -59,6 +59,6 @@ public class TestFileInitializer extends FileInitializer
}
StartLog.log("TESTING MODE","Skipping download of " + uri);
return Boolean.TRUE;
return true;
}
}

View File

@ -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;

View File

@ -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()

View File

@ -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);
}
}
};
}

View File

@ -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());

View File

@ -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));
}
/**

View File

@ -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);
}
}
}

View File

@ -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()
{

View File

@ -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));
}
}

View File

@ -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

View File

@ -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:

View File

@ -535,7 +535,7 @@ public class WebAppClassLoader extends URLClassLoader
{
if (ex==null)
ex = e;
else
else if (e != ex)
ex.addSuppressed(e);
}

View File

@ -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;

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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());

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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>