Merge branch 'jetty-9.4.x'

This commit is contained in:
Joakim Erdfelt 2016-12-16 08:38:16 -07:00
commit 1c16964118
13 changed files with 397 additions and 267 deletions

View File

@ -69,6 +69,8 @@ When executed `start.jar` performs the following actions:
==== start.jar Command Line Options
===== Command Line Options
--help::
Obtains the current list of command line options and some basic usage help.
--version::
@ -77,8 +79,6 @@ Shows the list of server classpath entries, and prints version information found
Similar to --version, shows the server classpath.
--list-config::
Lists the resolved configuration that will start Jetty.
+
* Java environment
* Jetty environment
* JVM arguments
@ -89,6 +89,15 @@ Lists the resolved configuration that will start Jetty.
Prints the resolved command line that `start.jar` should use to start a forked instance of Jetty.
--exec::
Starts a forked instance of Jetty.
--exec-properties=<filename>::
Assign a fixed name to the file used to transfer properties to the sub process.
This allows the generated properties file to be saved and reused.
Without this option, a temporary file is used.
--commands=<filename>::
Instructs `start.jar` to use each line of the specified file as arguments on the command line.
===== Debugg and Start Logging
--debug::
Enables debugging output of the startup procedure.
+
@ -98,22 +107,55 @@ For information on logging, please see the section on <<configuring-jetty-loggin
Sends all startup output to the filename specified.
Filename is relative to `${jetty.base}`.
This is useful for capturing startup issues where the Jetty-specific logger has not yet kicked in due to a possible startup configuration error.
===== Module Management
--list-modules::
Lists all the modules defined by the system.
Looks for module files using the link:#startup-base-and-home[normal `${jetty.base}` and `${jetty.home}` resolution logic].
Also lists enabled state based on information present on the command line, and all active startup INI files.
--list-modules=<tag>(,<tag>)*::
List modules by link:#startup-modules[tag.]
Use '*' for all tags.
Prefix a tag with '-' to exclude the tag.
The special tag "internal" is always excluded unless it is explicitly included.
--list-all-modules::
List all modules.
--module=<name>,(<name>)*::
Enables one or more modules by name (use `--list-modules` to see the list of available modules).
This enables all transitive (dependent) modules from the module system as well.
If you use this from the shell command line, it is considered a temporary effect, useful for testing out a scenario.
If you want this module to always be enabled, add this command to your `${jetty.base}/start.ini.`
--create-startd::
Creates a `${jetty.base}/start.d/` directory.
If a `${jetty.base}/start.ini` file already exists, it is copied to the `${jetty.base}/start.d` directory.
--add-to-start=<name>,(<name>)*::
Enables a module by appending lines to the `${jetty.base}/start.ini` file.
The lines that are added are provided by the module-defined INI templates.
Note: Transitive modules are also appended.
If a module contains an .ini template with properties, you can also edit these properties when activating the module.
To do this, simply list the property and its value after the `-add-to-start` command, such as in the following example:
+
[source, screen, subs="{sub-order}"]
....
$ java -jar start.jar --add-to-start=http jetty.http.port=8379 jetty.http.host=1.2.3.4
....
+
Doing this will uncomment the property in the associated .ini file and set it to the value specified.
--update-ini::
Used to update a specified property or properties that exist in an existing .ini file.
Jetty scans the command line, `${jetty.base}` and `${jetty.home}` for .ini files that have the specified property and update it accordingly.
+
[source, screen, subs="{sub-order}"]
....
$ java -jar ../start.jar --update-ini jetty.http.port=8417
ConfigSource <command-line>
ConfigSource ${jetty.base}
INFO : http property updated jetty.http.port=8417
INFO : http updated ${jetty.base}/start.d/http.ini
ConfigSource ${jetty.home}
....
+
--create-startd::
Creates a `${jetty.base}/start.d/` directory.
If a `${jetty.base}/start.ini` file already exists, it is copied to the `${jetty.base}/start.d` directory.
[NOTE]
--
@ -136,6 +178,25 @@ $ dot -Tpng -o modules.png modules.dot
+
See http://graphviz.org/[graphviz.org] for details on http://graphviz.org/content/command-line-invocation[how to post-process this dotty file] into the output best suited for your needs.
--create-files::
Create any missing files that are required by initialized modules.
This may download a file from the network if the module provides a URL.
--skip-file-validation=<modulename>(,<modulename)*::
Disable the [files] section validation of content in the `${jetty.base}` directory for a specific module.
Useful for modules that have downloadable content that is being overridden with alternatives in the `${jetty.base}`` directory.
____
[CAUTION]
This advanced option is for administrators that fully understand the configuration of their `${jetty.base}` and are willing to forego some of the safety checks built into the jetty-start mechanism.
____
--approve-all-licenses::
Approve all license questions.
Useful for enabling modules from a script that does not require user interaction.
===== Startup / Shutdown Command Line
--stop::
Sends a stop signal to the running Jetty instance.
+

View File

@ -253,7 +253,7 @@ If there are multiple entries in the `[tags]` section, it sorts by the first tag
____
[NOTE]
By default, the `--list-modules` command line argument shows all modules that do not include `internal` in the `[tags]` section of the associated `.mod` file.
If you would like to see *all* modules, use `--list-modules=*`
If you would like to see *all* modules, use `--list-all-modules`
____
Here's an example of the `--list-modules` command:

View File

@ -255,187 +255,11 @@ First notice the separation of `${jetty.base}` and `${jetty.home}`.
Notice that you have `--module=<name>` here and there; you have wrapped up the goal of a module (libs, configuration XMLs, and properties) into a single unit, with dependencies on other modules.
You can see the list of modules:
You can see the list of modules by appending `--list-modules` to the command line.
[source, screen, subs="{sub-order}"]
....
[my-base]$ java -jar /home/user/jetty-distribution-{VERSION}/start.jar --list-modules
Jetty All Available Modules:
----------------------------
Module: annotations
LIB: lib/jetty-annotations-${jetty.version}.jar
LIB: lib/annotations/*.jar
XML: etc/jetty-annotations.xml
depends: [plus]
Module: client
LIB: lib/jetty-client-${jetty.version}.jar
depends: []
Module: debug
XML: etc/jetty-debug.xml
depends: [server]
Module: deploy
LIB: lib/jetty-deploy-${jetty.version}.jar
XML: etc/jetty-deploy.xml
depends: [webapp]
enabled: ${jetty.base}/start.ini
Module: ext
LIB: lib/ext/*.jar
depends: []
Module: http
XML: etc/jetty-http.xml
depends: [server]
enabled: ${jetty.base}/start.ini
Module: http2
LIB: lib/http2/*.jar
XML: etc/jetty-http2.xml
depends: [ssl, alpn]
Module: http2c
LIB: lib/http2/*.jar
XML: etc/jetty-http2c.xml
depends: [http]
Module: https
XML: etc/jetty-https.xml
depends: [ssl]
Module: ipaccess
XML: etc/jetty-ipaccess.xml
depends: [server]
Module: jaas
LIB: lib/jetty-jaas-${jetty.version}.jar
XML: etc/jetty-jaas.xml
depends: [server]
Module: jaspi
LIB: lib/jetty-jaspi-${jetty.version}.jar
LIB: lib/jaspi/*.jar
depends: [security]
Module: jmx
LIB: lib/jetty-jmx-${jetty.version}.jar
XML: etc/jetty-jmx.xml
depends: []
Module: jndi
LIB: lib/jetty-jndi-${jetty.version}.jar
LIB: lib/jndi/*.jar
depends: [server]
Module: jsp
LIB: lib/jsp/*.jar
depends: [servlet]
Module: jvm
depends: []
Module: logging
XML: etc/jetty-logging.xml
depends: []
Module: lowresources
XML: etc/jetty-lowresources.xml
depends: [server]
Module: monitor
LIB: lib/jetty-monitor-${jetty.version}.jar
XML: etc/jetty-monitor.xml
depends: [client, server]
Module: npn
depends: []
Module: plus
LIB: lib/jetty-plus-${jetty.version}.jar
XML: etc/jetty-plus.xml
depends: [server, security, jndi]
Module: proxy
LIB: lib/jetty-proxy-${jetty.version}.jar
XML: etc/jetty-proxy.xml
depends: [client, server]
Module: requestlog
XML: etc/jetty-requestlog.xml
depends: [server]
Module: resources
LIB: resources
depends: []
Module: rewrite
LIB: lib/jetty-rewrite-${jetty.version}.jar
XML: etc/jetty-rewrite.xml
depends: [server]
Module: security
LIB: lib/jetty-security-${jetty.version}.jar
depends: [server]
Module: server
LIB: lib/servlet-api-3.1.jar
LIB: lib/jetty-schemas-3.1.jar
LIB: lib/jetty-http-${jetty.version}.jar
LIB: lib/jetty-continuation-${jetty.version}.jar
LIB: lib/jetty-server-${jetty.version}.jar
LIB: lib/jetty-xml-${jetty.version}.jar
LIB: lib/jetty-util-${jetty.version}.jar
LIB: lib/jetty-io-${jetty.version}.jar
XML: etc/jetty.xml
depends: []
enabled: ${jetty.base}/start.ini
Module: servlet
LIB: lib/jetty-servlet-${jetty.version}.jar
depends: [server]
Module: servlets
LIB: lib/jetty-servlets-${jetty.version}.jar
depends: [servlet]
Module: setuid
LIB: lib/setuid/jetty-setuid-java-1.0.1.jar
XML: etc/jetty-setuid.xml
depends: [server]
Module: ssl
XML: etc/jetty-ssl.xml
depends: [server]
enabled: ${jetty.base}/start.ini
Module: stats
XML: etc/jetty-stats.xml
depends: [server]
Module: webapp
LIB: lib/jetty-webapp-${jetty.version}.jar
depends: [servlet]
Module: websocket
LIB: lib/websocket/*.jar
depends: [annotations]
Module: xinetd
XML: etc/jetty-xinetd.xml
depends: [server]
Jetty Active Module Tree:
-------------------------
+ Module: server [enabled]
+ Module: http [enabled]
+ Module: servlet [transitive]
+ Module: ssl [enabled]
+ Module: webapp [transitive]
+ Module: deploy [enabled]
[my-base] $ java -jar ../jetty-distribution-{VERSION}/start.jar --list-modules
....
These are the modules by name, the libraries they bring in, the XML configurations they use, the other modules they depend on (even optional ones), and if the module is in use, where it was enabled.
@ -458,6 +282,7 @@ ____
Notice that your `${jetty.base}/start.ini` has no references to the XML files.
That's because the module system and its graph of dependencies now dictate all of the XML files, and their load order.
Much more information on modules can be found in the section on link:#startup-modules[Managing Startup Modules.]
[[parameterizing]]
===== Parameters

View File

@ -53,7 +53,7 @@ The Jetty distribution uses the following configuration files to instantiate, in
____
[NOTE]
--
As of Jetty 9 it is the `ini` files located in the Jetty base directory (if different from Jetty home) that are typically edited to change the configuration (e.g. change ports).
It is the `ini` files located in the Jetty base directory (if different from Jetty home) that are typically edited to change the configuration (e.g. change ports).
--
____

View File

@ -26,7 +26,6 @@ http://download.eclipse.org/jetty
____
It is available in both zip and gzip formats; download the one most appropriate for your system.
Notice that there are a number of other files with extensions of .sha or .md5 which are checksum files.
When you download and unpack the binary, it is extracted into a directory called `jetty-distribution-VERSION.`
Put this directory in a convenient location.
The rest of the instructions in this documentation refer to this location as either `JETTY_HOME` or as `$(jetty.home).`
@ -34,7 +33,8 @@ The rest of the instructions in this documentation refer to this location as eit
[[distribution-content]]
==== Distribution Content
A quick rundown of the distribution's contents follows. The top-level directory contains:
A summary of the distribution's contents follows.
The top-level directory contains:
.Contents
[width="80%",cols="40%,60%",options="header"]
@ -50,8 +50,42 @@ A quick rundown of the distribution's contents follows. The top-level directory
|modules/ |Directory of module definitions
|notice.html |License information and exceptions
|resources/ |Directory containing additional resources for classpath, activated via configuration
|start.d/ |Directory of *.ini files containing arguments that are added to the effective command line (see start.ini)
|start.ini |File containing the arguments that are added to the effective command line (modules, properties and XML configuration files)
|start.jar |Jar that invokes Jetty (see also xref:quickstart-running-jetty[])
|webapps/ |Directory containing webapps that run under the default configuration of Jetty
|=======================================================================
[[jetty-home-downloading]]
==== Downloading the Jetty-Home Distribution
Jetty-Home is an alternate version of the distribution that contains only the necessary items to host a Jetty distribution.
It is intended for advanced users who are already familiar with Jetty and want to download a smaller distribution package.
Jetty-Home can be downloaded from the Maven Central repository:
____
*Jetty-Home*
http://central.maven.org/maven2/org/eclipse/jetty/jetty-home/
____
Like the main Jetty distribution, Jetty-Home is available in both zip and gzip formats; download the one most appropriate for your system.
Notice that there are a number of other files with extensions of .sha or .md5 which are checksum files.
When you download and unpack the binary, it is extracted into a directory called `jetty-home-VERSION.`
Put this directory in a convenient location.
[[jetty-home-distribution-content]]
==== Distribution Content
A summary of the Jetty-Home's distribution contents follows.
The top-level directory contains:
.Contents
[width="80%",cols="40%,60%",options="header"]
|=======================================================================
|Location |Description |license-eplv10-aslv20.html |License file for Jetty
|VERSION.txt |Release information
|etc/ |Directory for Jetty XML configuration files
|lib/ |All the JAR files necessary to run Jetty
|modules/ |Directory of module definitions
|notice.html |License information and exceptions
|start.jar |Jar that invokes Jetty (see also xref:quickstart-running-jetty[])
|=======================================================================

View File

@ -24,6 +24,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Predicate;
import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.Trie;
@ -81,6 +82,11 @@ public class PathMappings<E> implements Iterable<MappedResource<E>>, Dumpable
_suffixMap.clear();
}
public void removeIf(Predicate<MappedResource<E>> predicate)
{
_mappings.removeIf(predicate);
}
/**
* Return a list of MappedResource matches for the specified path.
*

View File

@ -80,8 +80,6 @@ import org.eclipse.jetty.util.thread.Invocable;
public class SslConnection extends AbstractConnection
{
private static final Logger LOG = Log.getLogger(SslConnection.class);
private static final ByteBuffer __FILL_CALLED_FLUSH= BufferUtil.allocate(0);
private static final ByteBuffer __FLUSH_CALLED_FILL= BufferUtil.allocate(0);
private final List<SslHandshakeListener> handshakeListeners = new ArrayList<>();
private final ByteBufferPool _bufferPool;
@ -634,9 +632,10 @@ public class SslConnection extends AbstractConnection
HandshakeStatus unwrapHandshakeStatus = unwrapResult.getHandshakeStatus();
Status unwrapResultStatus = unwrapResult.getStatus();
// Extra check on unwrapResultStatus == OK with zero length buffer is due
// to SSL client on android (see bug #454773)
_underFlown = unwrapResultStatus == Status.BUFFER_UNDERFLOW || unwrapResultStatus == Status.OK && unwrapResult.bytesConsumed()==0 && unwrapResult.bytesProduced()==0;
// Extra check on unwrapResultStatus == OK with zero bytes consumed
// or produced is due to an SSL client on Android (see bug #454773).
_underFlown = unwrapResultStatus == Status.BUFFER_UNDERFLOW ||
unwrapResultStatus == Status.OK && unwrapResult.bytesConsumed() == 0 && unwrapResult.bytesProduced() == 0;
if (_underFlown)
{
@ -730,15 +729,17 @@ public class SslConnection extends AbstractConnection
{
// If we are called from flush()
// return to let it do the wrapping.
if (buffer == __FLUSH_CALLED_FILL)
if (_flushRequiresFillToProgress)
return 0;
_fillRequiresFlushToProgress = true;
flush(__FILL_CALLED_FLUSH);
flush(BufferUtil.EMPTY_BUFFER);
if (BufferUtil.isEmpty(_encryptedOutput))
{
// The flush wrote all the encrypted bytes so continue to fill
// The flush wrote all the encrypted bytes so continue to fill.
_fillRequiresFlushToProgress = false;
if (_underFlown)
break decryption;
continue;
}
else
@ -961,11 +962,11 @@ public class SslConnection extends AbstractConnection
case NEED_UNWRAP:
// Ah we need to fill some data so we can write.
// So if we were not called from fill and the app is not reading anyway
if (appOuts[0]!=__FILL_CALLED_FLUSH && !getFillInterest().isInterested())
if (!_fillRequiresFlushToProgress && !getFillInterest().isInterested())
{
// Tell the onFillable method that there might be a write to complete
_flushRequiresFillToProgress = true;
fill(__FLUSH_CALLED_FILL);
fill(BufferUtil.EMPTY_BUFFER);
// Check if after the fill() we need to wrap again
if (_sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_WRAP)
continue;

View File

@ -31,6 +31,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
@ -46,6 +47,7 @@ import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.DispatcherType;
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
@ -55,10 +57,13 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.server.LocalConnector.LocalEndPoint;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.MultiPartInputStreamParser;
import org.eclipse.jetty.util.Utf8Appendable;
@ -833,6 +838,77 @@ public class RequestTest
}
@Test
@Ignore("See issue #1175")
public void testMultiPartFormDataReadInputThenParams() throws Exception
{
final File tmpdir = MavenTestingUtils.getTargetTestingDir("multipart");
FS.ensureEmpty(tmpdir);
Handler handler = new AbstractHandler()
{
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException,
ServletException
{
if (baseRequest.getDispatcherType() != DispatcherType.REQUEST)
return;
// Fake a @MultiPartConfig'd servlet endpoint
MultipartConfigElement multipartConfig = new MultipartConfigElement(tmpdir.getAbsolutePath());
request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, multipartConfig);
// Normal processing
baseRequest.setHandled(true);
// Fake the commons-fileupload behavior
int length = request.getContentLength();
InputStream in = request.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
IO.copy(in, out, length); // KEY STEP (Don't Change!) commons-fileupload does not read to EOF
// Record what happened as servlet response headers
response.setIntHeader("x-request-content-length", request.getContentLength());
response.setIntHeader("x-request-content-read", out.size());
String foo = request.getParameter("foo"); // uri query parameter
String bar = request.getParameter("bar"); // form-data content parameter
response.setHeader("x-foo", foo == null ? "null" : foo);
response.setHeader("x-bar", bar == null ? "null" : bar);
}
};
_server.stop();
_server.setHandler(handler);
_server.start();
String multipart = "--AaBbCc\r\n"+
"content-disposition: form-data; name=\"bar\"\r\n"+
"\r\n"+
"BarContent\r\n"+
"--AaBbCc\r\n"+
"content-disposition: form-data; name=\"stuff\"\r\n"+
"Content-Type: text/plain;charset=ISO-8859-1\r\n"+
"\r\n"+
"000000000000000000000000000000000000000000000000000\r\n"+
"--AaBbCc--\r\n";
String request="POST /?foo=FooUri HTTP/1.1\r\n"+
"Host: whatever\r\n"+
"Content-Type: multipart/form-data; boundary=\"AaBbCc\"\r\n"+
"Content-Length: "+multipart.getBytes().length+"\r\n"+
"Connection: close\r\n"+
"\r\n"+
multipart;
HttpTester.Response response = HttpTester.parseResponse(_connector.getResponse(request));
// It should always be possible to read query string
assertThat("response.x-foo", response.get("x-foo"), is("FooUri"));
// Not possible to read request content parameters?
assertThat("response.x-bar", response.get("x-bar"), is("null")); // TODO: should this work?
}
@Test
public void testPartialRead() throws Exception
{
@ -855,27 +931,26 @@ public class RequestTest
_server.setHandler(handler);
_server.start();
String requests="GET / HTTP/1.1\r\n"+
"Host: whatever\r\n"+
"Content-Type: text/plane\r\n"+
"Content-Length: "+10+"\r\n"+
"\r\n"+
"0123456789\r\n"+
"GET / HTTP/1.1\r\n"+
"Host: whatever\r\n"+
"Content-Type: text/plane\r\n"+
"Content-Length: "+10+"\r\n"+
"Connection: close\r\n"+
"\r\n"+
"ABCDEFGHIJ\r\n";
String request="GET / HTTP/1.1\r\n"+
"Host: whatever\r\n"+
"Content-Type: text/plane\r\n"+
"Content-Length: "+10+"\r\n"+
"\r\n"+
"0123456789\r\n"+
"GET / HTTP/1.1\r\n"+
"Host: whatever\r\n"+
"Content-Type: text/plane\r\n"+
"Content-Length: "+10+"\r\n"+
"Connection: close\r\n"+
"\r\n"+
"ABCDEFGHIJ\r\n";
LocalEndPoint endp = _connector.executeRequest(requests);
String response = endp.getResponse()+endp.getResponse();
String responses = _connector.getResponses(request);
int index=response.indexOf("read="+(int)'0');
int index=responses.indexOf("read="+(int)'0');
assertTrue(index>0);
index=response.indexOf("read="+(int)'A',index+7);
index=responses.indexOf("read="+(int)'A',index+7);
assertTrue(index>0);
}

View File

@ -100,17 +100,6 @@ Module Management:
amended in the generated file by specifying those
properties on the command line.
FS.ensureDirectoryExists(startDir);
FS.ensureDirectoryExists(startDir);
modules that the specified module depends on are also
.
If the directory ${jetty.base}/start.d
exists then <modulename>.ini files are created within
that directory, otherwise then enabling configuration
is appended to the ${jetty.base}/start.ini file.
Lines that are added come from the ini template that
the module itself maintains.
Note: not all modules have ini templates and thus may
be transitively enabled and not explicitly enabled in
a ini file.

View File

@ -32,7 +32,7 @@
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-unixsocket</artifactId>
<version>0.8</version>
<version>0.15</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>

View File

@ -60,7 +60,7 @@ public class NativeWebSocketConfiguration extends ContainerLifeCycle implements
@Override
public void doStop() throws Exception
{
mappings.reset();
mappings.removeIf((mapped) -> !(mapped.getResource() instanceof PersistedWebSocketCreator));
super.doStop();
}
@ -111,13 +111,23 @@ public class NativeWebSocketConfiguration extends ContainerLifeCycle implements
/**
* Manually add a WebSocket mapping.
* <p>
* If mapping is added before this configuration is started, then it is persisted through
* stop/start of this configuration's lifecycle. Otherwise it will be removed when
* this configuration is stopped.
* </p>
*
* @param pathSpec the pathspec to respond on
* @param creator the websocket creator to activate on the provided mapping.
*/
public void addMapping(PathSpec pathSpec, WebSocketCreator creator)
{
mappings.put(pathSpec, creator);
WebSocketCreator wsCreator = creator;
if (!isRunning())
{
wsCreator = new PersistedWebSocketCreator(creator);
}
mappings.put(pathSpec, wsCreator);
}
/**
@ -170,4 +180,26 @@ public class NativeWebSocketConfiguration extends ContainerLifeCycle implements
}
});
}
private class PersistedWebSocketCreator implements WebSocketCreator
{
private final WebSocketCreator delegate;
public PersistedWebSocketCreator(WebSocketCreator delegate)
{
this.delegate = delegate;
}
@Override
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
{
return delegate.createWebSocket(req, resp);
}
@Override
public String toString()
{
return "Persisted[" + super.toString() + "]";
}
}
}

View File

@ -34,6 +34,7 @@ import javax.servlet.DispatcherType;
import org.eclipse.jetty.http.pathmap.ServletPathSpec;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.toolchain.test.EventQueue;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
@ -127,13 +128,43 @@ public class WebSocketUpgradeFilterTest
NativeWebSocketConfiguration configuration = new NativeWebSocketConfiguration(context.getServletContext());
configuration.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
configuration.addMapping(new ServletPathSpec("/info/*"), infoCreator);
context.getServletContext().setAttribute(NativeWebSocketConfiguration.class.getName(), configuration);
context.setAttribute(NativeWebSocketConfiguration.class.getName(), configuration);
server13.start();
return server13;
}});
// Embedded WSUF, added as filter, apply app-ws configuration via wsuf constructor
cases.add(new Object[]{"wsuf/addFilter/WSUF Constructor configure", new ServerProvider()
{
@Override
public Server newServer() throws Exception
{
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0);
server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server.setHandler(context);
NativeWebSocketConfiguration configuration = new NativeWebSocketConfiguration(context.getServletContext());
configuration.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
configuration.addMapping(new ServletPathSpec("/info/*"), infoCreator);
context.addBean(configuration, true);
FilterHolder wsufHolder = new FilterHolder(new WebSocketUpgradeFilter(configuration));
context.addFilter(wsufHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
server.start();
return server;
}
}});
// Embedded WSUF, added as filter, apply app-ws configuration via ServletContextListener
cases.add(new Object[]{"wsuf.configureContext/ServletContextListener configure", (ServerProvider) () ->
@ -235,7 +266,7 @@ public class WebSocketUpgradeFilterTest
}
@Test
public void testConfiguration() throws Exception
public void testNormalConfiguration() throws Exception
{
URI destUri = serverUri.resolve("/info/");
@ -255,4 +286,45 @@ public class WebSocketUpgradeFilterTest
assertThat("payload", payload, containsString("session.maxTextMessageSize=" + (10 * 1024 * 1024)));
}
}
@Test
public void testStopStartOfHandler() throws Exception
{
URI destUri = serverUri.resolve("/info/");
try (BlockheadClient client = new BlockheadClient(destUri))
{
client.connect();
client.sendStandardRequest();
client.expectUpgradeResponse();
client.write(new TextFrame().setPayload("hello 1"));
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1000, TimeUnit.MILLISECONDS);
String payload = frames.poll().getPayloadAsUTF8();
// If we can connect and send a text message, we know that the endpoint was
// added properly, and the response will help us verify the policy configuration too
assertThat("payload", payload, containsString("session.maxTextMessageSize=" + (10 * 1024 * 1024)));
}
server.getHandler().stop();
server.getHandler().start();
try (BlockheadClient client = new BlockheadClient(destUri))
{
client.connect();
client.sendStandardRequest();
client.expectUpgradeResponse();
client.write(new TextFrame().setPayload("hello 2"));
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1000, TimeUnit.MILLISECONDS);
String payload = frames.poll().getPayloadAsUTF8();
// If we can connect and send a text message, we know that the endpoint was
// added properly, and the response will help us verify the policy configuration too
assertThat("payload", payload, containsString("session.maxTextMessageSize=" + (10 * 1024 * 1024)));
}
}
}

View File

@ -33,6 +33,7 @@ import java.util.stream.IntStream;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -510,6 +511,40 @@ public class HttpClientTest extends AbstractTest
Assert.assertEquals(1, completes.get());
}
@Test
public void testHEADResponds200() throws Exception
{
testHEAD(servletPath, HttpStatus.OK_200);
}
@Test
public void testHEADResponds404() throws Exception
{
testHEAD("/notMapped", HttpStatus.NOT_FOUND_404);
}
private void testHEAD(String path, int status) throws Exception
{
byte[] data = new byte[1024];
new Random().nextBytes(data);
start(new HttpServlet()
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.getOutputStream().write(data);
}
});
ContentResponse response = client.newRequest(newURI())
.method(HttpMethod.HEAD)
.path(path)
.send();
Assert.assertEquals(status, response.getStatus());
Assert.assertEquals(0, response.getContent().length);
}
private void sleep(long time) throws IOException
{
try