Merge remote-tracking branch 'origin/jetty-9.4.x'
This commit is contained in:
commit
579b99c2c9
|
@ -363,9 +363,14 @@ An example of this setup:
|
||||||
[source, plain, subs="{sub-order}"]
|
[source, plain, subs="{sub-order}"]
|
||||||
----
|
----
|
||||||
$ cd /path/to/mybase
|
$ cd /path/to/mybase
|
||||||
|
$ java -jar ../start.jar --create-startd
|
||||||
|
MKDIR : ${jetty.base}/start.d
|
||||||
|
INFO : Base directory was modified
|
||||||
$ java -jar /path/to/jetty-dist/start.jar --add-to-start=ssl
|
$ java -jar /path/to/jetty-dist/start.jar --add-to-start=ssl
|
||||||
INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini
|
INFO : server transitively enabled, ini template available with --add-to-start=server
|
||||||
INFO : ssl initialised in ${jetty.base}/start.d/ssl.ini
|
INFO : ssl initialized in ${jetty.base}/start.d/ssl.ini
|
||||||
|
MKDIR : ${jetty.base}/etc
|
||||||
|
COPY : ${jetty.home}/modules/ssl/keystore to ${jetty.base}/etc/keystore
|
||||||
INFO : Base directory was modified
|
INFO : Base directory was modified
|
||||||
$ tree
|
$ tree
|
||||||
.
|
.
|
||||||
|
@ -394,44 +399,30 @@ jetty.sslContext.keyStorePassword::
|
||||||
[[two-way-authentication]]
|
[[two-way-authentication]]
|
||||||
==== Two Way Authentication
|
==== Two Way Authentication
|
||||||
|
|
||||||
To enable two-way authentication, you first need to activate the ssl module as shown in the previous section.
|
To enable two-way authentication both the `ssl` and `https` modules need to be activated.
|
||||||
|
Once enabled, set the `jetty.sslContext.needClientAuth` property to `true`.
|
||||||
|
|
||||||
First you need load the `ssl` module and `https` module.
|
|
||||||
[source%nowrap,ini,linenums]
|
[source%nowrap,ini,linenums]
|
||||||
.$JETTY_BASE/start.d/ssl.ini
|
.$JETTY_BASE/start.d/ssl.ini
|
||||||
----
|
----
|
||||||
# Module: ssl
|
# Module: ssl
|
||||||
--module=ssl
|
--module=ssl
|
||||||
|
...
|
||||||
jetty.ssl.host=0.0.0.0
|
## whether client certificate authentication is required
|
||||||
jetty.ssl.port=8583
|
|
||||||
jetty.sslContext.keyStorePath=etc/keystore
|
|
||||||
jetty.sslContext.trustStorePath=etc/keystore
|
|
||||||
jetty.sslContext.keyStorePassword=OBF:
|
|
||||||
jetty.sslContext.keyManagerPassword=OBF:
|
|
||||||
jetty.sslContext.trustStorePassword=OBF:
|
|
||||||
jetty.sslContext.trustStoreType=JKS
|
|
||||||
# enable two way authentication
|
|
||||||
jetty.sslContext.needClientAuth=true
|
jetty.sslContext.needClientAuth=true
|
||||||
----
|
...
|
||||||
|
|
||||||
[source%nowrap,ini,linenums]
|
|
||||||
.$JETTY_BASE/start.d/https.ini
|
|
||||||
----
|
|
||||||
# Module: https
|
|
||||||
--module=https
|
|
||||||
----
|
----
|
||||||
|
|
||||||
[[layout-of-keystore-and-truststore]]
|
[[layout-of-keystore-and-truststore]]
|
||||||
===== Layout of `keystore` and `truststore`
|
==== Layout of keystore and truststore
|
||||||
|
|
||||||
`keystore` only contains the server's private key and certificate.
|
The server's private key and certificate are contained within the keystore.
|
||||||
|
|
||||||
[[img-certificate-chain]]
|
[[img-certificate-chain]]
|
||||||
image::images/certificate-chain.png[title="Certificate chain", alt="Certificate chain"]
|
image::images/certificate-chain.png[title="Certificate chain", alt="Certificate chain"]
|
||||||
|
|
||||||
[literal]
|
[literal]
|
||||||
.The structure of KeyStore file
|
.The structure of a KeyStore file
|
||||||
....
|
....
|
||||||
├── PrivateKeyEntry
|
├── PrivateKeyEntry
|
||||||
│ ├── PrivateKey
|
│ ├── PrivateKey
|
||||||
|
@ -447,11 +438,7 @@ image::images/certificate-chain.png[title="Certificate chain", alt="Certificate
|
||||||
|
|
||||||
[TIP]
|
[TIP]
|
||||||
====
|
====
|
||||||
└── PrivateKeyEntry +
|
`PrivateKeyEntry`, `Certificate chain`, `Intermediary CA certificate` and `Root CA certificate` are all optional values.
|
||||||
└── Certificate chain +
|
|
||||||
├── Intermediary CA certificate +
|
|
||||||
└── Root CA certificate +
|
|
||||||
are optional
|
|
||||||
====
|
====
|
||||||
|
|
||||||
[source%nowrap,plain,linenums]
|
[source%nowrap,plain,linenums]
|
||||||
|
@ -709,9 +696,10 @@ KeyIdentifier [
|
||||||
*******************************************
|
*******************************************
|
||||||
----
|
----
|
||||||
|
|
||||||
In addition, you can split `$JETTY/etc/keystore` as two files.
|
Additionally, you can split `$JETTY/etc/keystore` into two files.
|
||||||
One is `$JETTY/etc/keystore` which only contains the server’s private key and certificate,
|
One being `$JETTY/etc/keystore` which only contains the server’s private key and certificate, while the other would be `$JETTY/etc/truststore` which contains intermediary CA and root CA.
|
||||||
the other is `$JETTY/etc/truststore` which contains intermediary CA and root CA.
|
|
||||||
|
An example of this would look like the following:
|
||||||
|
|
||||||
[literal]
|
[literal]
|
||||||
.The structure of `$JETTY/etc/keystore`
|
.The structure of `$JETTY/etc/keystore`
|
||||||
|
@ -759,7 +747,7 @@ setKeyStorePath::
|
||||||
The configured keystore to use for all SSL/TLS in configured Jetty Connector (or Client).
|
The configured keystore to use for all SSL/TLS in configured Jetty Connector (or Client).
|
||||||
____
|
____
|
||||||
[NOTE]
|
[NOTE]
|
||||||
As a keystore is vital security information, it can be desirable to locate the file in a directory with *very* restricted access.
|
As the keystore is vital security information, it recommended the file is located in a directory with *very* restricted access.
|
||||||
____
|
____
|
||||||
|
|
||||||
setKeyStorePassword::
|
setKeyStorePassword::
|
||||||
|
@ -784,7 +772,7 @@ ____
|
||||||
|
|
||||||
____
|
____
|
||||||
[CAUTION]
|
[CAUTION]
|
||||||
The keystore and truststore passwords may also be set using the system properties: `org.eclipse.jetty.ssl.keypassword` `org.eclipse.jetty.ssl.password`.
|
The keystore and truststore passwords may also be set using the system properties: `org.eclipse.jetty.ssl.keypassword` and `org.eclipse.jetty.ssl.password`.
|
||||||
This is _not_ a recommended usage.
|
This is _not_ a recommended usage.
|
||||||
____
|
____
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,12 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.servlet;
|
package org.eclipse.jetty.servlet;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.servlet.AsyncContext;
|
import javax.servlet.AsyncContext;
|
||||||
|
@ -34,6 +37,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.servlet.http.HttpServletResponseWrapper;
|
import javax.servlet.http.HttpServletResponseWrapper;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.http.HttpTester;
|
||||||
import org.eclipse.jetty.server.Handler;
|
import org.eclipse.jetty.server.Handler;
|
||||||
import org.eclipse.jetty.server.HttpChannel;
|
import org.eclipse.jetty.server.HttpChannel;
|
||||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||||
|
@ -43,19 +47,13 @@ import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||||
import org.eclipse.jetty.server.handler.HandlerList;
|
import org.eclipse.jetty.server.handler.HandlerList;
|
||||||
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
import org.eclipse.jetty.util.log.StacklessLogging;
|
import org.eclipse.jetty.util.log.StacklessLogging;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This tests the correct functioning of the AsyncContext
|
* This tests the correct functioning of the AsyncContext
|
||||||
* <p/>
|
* <p/>
|
||||||
|
@ -81,6 +79,14 @@ public class AsyncContextTest
|
||||||
_contextHandler.addServlet(new ServletHolder(new TestServlet()), "/servletPath");
|
_contextHandler.addServlet(new ServletHolder(new TestServlet()), "/servletPath");
|
||||||
_contextHandler.addServlet(new ServletHolder(new TestServlet()), "/path with spaces/servletPath");
|
_contextHandler.addServlet(new ServletHolder(new TestServlet()), "/path with spaces/servletPath");
|
||||||
_contextHandler.addServlet(new ServletHolder(new TestServlet2()), "/servletPath2");
|
_contextHandler.addServlet(new ServletHolder(new TestServlet2()), "/servletPath2");
|
||||||
|
|
||||||
|
ServletHolder testHolder = new ServletHolder(new TestServlet());
|
||||||
|
testHolder.setInitParameter("dispatchPath", "/test2/something%2felse");
|
||||||
|
_contextHandler.addServlet(testHolder, "/test/*");
|
||||||
|
_contextHandler.addServlet(new ServletHolder(new TestServlet2()), "/test2/*");
|
||||||
|
|
||||||
|
_contextHandler.addServlet(new ServletHolder(new SelfDispatchingServlet()), "/self/*");
|
||||||
|
|
||||||
_contextHandler.addServlet(new ServletHolder(new TestStartThrowServlet()), "/startthrow/*");
|
_contextHandler.addServlet(new ServletHolder(new TestStartThrowServlet()), "/startthrow/*");
|
||||||
_contextHandler.addServlet(new ServletHolder(new ForwardingServlet()), "/forward");
|
_contextHandler.addServlet(new ServletHolder(new ForwardingServlet()), "/forward");
|
||||||
_contextHandler.addServlet(new ServletHolder(new AsyncDispatchingServlet()), "/dispatchingServlet");
|
_contextHandler.addServlet(new ServletHolder(new AsyncDispatchingServlet()), "/dispatchingServlet");
|
||||||
|
@ -115,12 +121,14 @@ public class AsyncContextTest
|
||||||
"Host: localhost\r\n" +
|
"Host: localhost\r\n" +
|
||||||
"Connection: close\r\n" +
|
"Connection: close\r\n" +
|
||||||
"\r\n";
|
"\r\n";
|
||||||
String responseString = _connector.getResponse(request);
|
HttpTester.Response response = HttpTester.parseResponse(_connector.getResponse(request));
|
||||||
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||||
|
|
||||||
assertThat(responseString, startsWith("HTTP/1.1 200 "));
|
String responseBody = response.getContent();
|
||||||
assertThat(responseString, containsString("doGet:getServletPath:/servletPath"));
|
|
||||||
assertThat(responseString, containsString("doGet:async:getServletPath:/servletPath"));
|
assertThat(responseBody, containsString("doGet:getServletPath:/servletPath"));
|
||||||
assertThat(responseString, containsString("async:run:attr:servletPath:/servletPath"));
|
assertThat(responseBody, containsString("doGet:async:getServletPath:/servletPath"));
|
||||||
|
assertThat(responseBody, containsString("async:run:attr:servletPath:/servletPath"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -131,12 +139,15 @@ public class AsyncContextTest
|
||||||
"Host: localhost\r\n" +
|
"Host: localhost\r\n" +
|
||||||
"Connection: close\r\n" +
|
"Connection: close\r\n" +
|
||||||
"\r\n";
|
"\r\n";
|
||||||
String responseString = _connector.getResponse(request,10,TimeUnit.MINUTES);
|
HttpTester.Response response = HttpTester.parseResponse(_connector.getResponse(request,10,TimeUnit.MINUTES));
|
||||||
|
|
||||||
assertThat(responseString, startsWith("HTTP/1.1 500 "));
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
|
||||||
assertThat(responseString, containsString("ERROR: /error"));
|
|
||||||
assertThat(responseString, containsString("PathInfo= /IOE"));
|
String responseBody = response.getContent();
|
||||||
assertThat(responseString, containsString("EXCEPTION: org.eclipse.jetty.server.QuietServletException: java.io.IOException: Test"));
|
|
||||||
|
assertThat(responseBody, containsString("ERROR: /error"));
|
||||||
|
assertThat(responseBody, containsString("PathInfo= /IOE"));
|
||||||
|
assertThat(responseBody, containsString("EXCEPTION: org.eclipse.jetty.server.QuietServletException: java.io.IOException: Test"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -147,12 +158,15 @@ public class AsyncContextTest
|
||||||
"Host: localhost\r\n" +
|
"Host: localhost\r\n" +
|
||||||
"Connection: close\r\n" +
|
"Connection: close\r\n" +
|
||||||
"\r\n";
|
"\r\n";
|
||||||
String responseString = _connector.getResponse(request);
|
HttpTester.Response response = HttpTester.parseResponse(_connector.getResponse(request));
|
||||||
|
|
||||||
assertThat(responseString, startsWith("HTTP/1.1 500 "));
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
|
||||||
assertThat(responseString, containsString("ERROR: /error"));
|
|
||||||
assertThat(responseString, containsString("PathInfo= /IOE"));
|
String responseBody = response.getContent();
|
||||||
assertThat(responseString, containsString("EXCEPTION: org.eclipse.jetty.server.QuietServletException: java.io.IOException: Test"));
|
|
||||||
|
assertThat(responseBody, containsString("ERROR: /error"));
|
||||||
|
assertThat(responseBody, containsString("PathInfo= /IOE"));
|
||||||
|
assertThat(responseBody, containsString("EXCEPTION: org.eclipse.jetty.server.QuietServletException: java.io.IOException: Test"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -163,106 +177,169 @@ public class AsyncContextTest
|
||||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||||
"Connection: close\r\n" +
|
"Connection: close\r\n" +
|
||||||
"\r\n";
|
"\r\n";
|
||||||
String responseString = _connector.getResponse(request);
|
HttpTester.Response response = HttpTester.parseResponse(_connector.getResponse(request));
|
||||||
|
|
||||||
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
|
||||||
|
|
||||||
assertEquals("HTTP/1.1 500 Server Error", br.readLine());
|
String responseBody = response.getContent();
|
||||||
readHeader(br);
|
assertThat(responseBody, containsString("ERROR: /error"));
|
||||||
Assert.assertEquals("ERROR: /error", br.readLine());
|
assertThat(responseBody, containsString("PathInfo= /IOE"));
|
||||||
Assert.assertEquals("PathInfo= /IOE", br.readLine());
|
assertThat(responseBody, containsString("EXCEPTION: org.eclipse.jetty.server.QuietServletException: java.io.IOException: Test"));
|
||||||
Assert.assertEquals("EXCEPTION: org.eclipse.jetty.server.QuietServletException: java.io.IOException: Test", br.readLine());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStartFlushCompleteThrow() throws Exception
|
public void testStartFlushCompleteThrow() throws Exception
|
||||||
{
|
{
|
||||||
try(StacklessLogging stackless = new StacklessLogging(HttpChannel.class))
|
try(StacklessLogging ignore = new StacklessLogging(HttpChannel.class))
|
||||||
{
|
{
|
||||||
String request = "GET /ctx/startthrow?flush=true&complete=true HTTP/1.1\r\n" +
|
String request = "GET /ctx/startthrow?flush=true&complete=true HTTP/1.1\r\n" +
|
||||||
"Host: localhost\r\n" +
|
"Host: localhost\r\n" +
|
||||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||||
"Connection: close\r\n" +
|
"Connection: close\r\n" +
|
||||||
"\r\n";
|
"\r\n";
|
||||||
String responseString = _connector.getResponse(request);
|
HttpTester.Response response = HttpTester.parseResponse(_connector.getResponse(request));
|
||||||
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||||
|
|
||||||
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
String responseBody = response.getContent();
|
||||||
|
|
||||||
assertEquals("HTTP/1.1 200 OK",br.readLine());
|
assertThat("error servlet", responseBody, containsString("completeBeforeThrow"));
|
||||||
readHeader(br);
|
|
||||||
|
|
||||||
Assert.assertEquals("error servlet","completeBeforeThrow",br.readLine());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDispatchAsyncContext() throws Exception
|
public void testDispatchAsyncContext() throws Exception
|
||||||
{
|
{
|
||||||
String request = "GET /ctx/servletPath?dispatch=true HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
|
String request = "GET /ctx/servletPath?dispatch=true HTTP/1.1\r\n" +
|
||||||
+ "Connection: close\r\n" + "\r\n";
|
"Host: localhost\r\n" +
|
||||||
String responseString = _connector.getResponse(request);
|
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||||
|
"Connection: close\r\n" +
|
||||||
|
"\r\n";
|
||||||
|
HttpTester.Response response = HttpTester.parseResponse(_connector.getResponse(request));
|
||||||
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||||
|
|
||||||
BufferedReader br = parseHeader(responseString);
|
String responseBody = response.getContent();
|
||||||
|
assertThat("servlet gets right path", responseBody, containsString("doGet:getServletPath:/servletPath2"));
|
||||||
|
assertThat("async context gets right path in get", responseBody, containsString("doGet:async:getServletPath:/servletPath2"));
|
||||||
|
assertThat("servlet path attr is original", responseBody, containsString("async:run:attr:servletPath:/servletPath"));
|
||||||
|
assertThat("path info attr is correct", responseBody, containsString("async:run:attr:pathInfo:null"));
|
||||||
|
assertThat("query string attr is correct", responseBody, containsString("async:run:attr:queryString:dispatch=true"));
|
||||||
|
assertThat("context path attr is correct", responseBody, containsString("async:run:attr:contextPath:/ctx"));
|
||||||
|
assertThat("request uri attr is correct", responseBody, containsString("async:run:attr:requestURI:/ctx/servletPath"));
|
||||||
|
}
|
||||||
|
|
||||||
Assert.assertEquals("servlet gets right path", "doGet:getServletPath:/servletPath2", br.readLine());
|
@Test
|
||||||
Assert.assertEquals("async context gets right path in get", "doGet:async:getServletPath:/servletPath2", br.readLine());
|
public void testDispatchAsyncContext_EncodedUrl() throws Exception
|
||||||
Assert.assertEquals("servlet path attr is original", "async:run:attr:servletPath:/servletPath", br.readLine());
|
{
|
||||||
Assert.assertEquals("path info attr is correct", "async:run:attr:pathInfo:null", br.readLine());
|
String request = "GET /ctx/test/hello%2fthere?dispatch=true HTTP/1.1\r\n" +
|
||||||
Assert.assertEquals("query string attr is correct", "async:run:attr:queryString:dispatch=true", br.readLine());
|
"Host: localhost\r\n" +
|
||||||
Assert.assertEquals("context path attr is correct", "async:run:attr:contextPath:/ctx", br.readLine());
|
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||||
Assert.assertEquals("request uri attr is correct", "async:run:attr:requestURI:/ctx/servletPath", br.readLine());
|
"Connection: close\r\n" +
|
||||||
|
"\r\n";
|
||||||
|
HttpTester.Response response = HttpTester.parseResponse(_connector.getResponse(request));
|
||||||
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||||
|
|
||||||
|
String responseBody = response.getContent();
|
||||||
|
|
||||||
|
// initial values
|
||||||
|
assertThat("servlet gets right path", responseBody, containsString("doGet:getServletPath:/test2"));
|
||||||
|
assertThat("request uri has correct encoding", responseBody, containsString("doGet:getRequestURI:/ctx/test2/something%2felse"));
|
||||||
|
assertThat("request url has correct encoding", responseBody, containsString("doGet:getRequestURL:http://localhost/ctx/test2/something%2felse"));
|
||||||
|
assertThat("path info has correct encoding", responseBody, containsString("doGet:getPathInfo:/something/else"));
|
||||||
|
|
||||||
|
// async values
|
||||||
|
assertThat("async servlet gets right path", responseBody, containsString("doGet:async:getServletPath:/test2"));
|
||||||
|
assertThat("async request uri has correct encoding", responseBody, containsString("doGet:async:getRequestURI:/ctx/test2/something%2felse"));
|
||||||
|
assertThat("async request url has correct encoding", responseBody, containsString("doGet:async:getRequestURL:http://localhost/ctx/test2/something%2felse"));
|
||||||
|
assertThat("async path info has correct encoding", responseBody, containsString("doGet:async:getPathInfo:/something/else"));
|
||||||
|
|
||||||
|
// async run attributes
|
||||||
|
assertThat("async run attr servlet path is original", responseBody, containsString("async:run:attr:servletPath:/test"));
|
||||||
|
assertThat("async run attr path info has correct encoding", responseBody, containsString("async:run:attr:pathInfo:/hello/there"));
|
||||||
|
assertThat("async run attr query string", responseBody, containsString("async:run:attr:queryString:dispatch=true"));
|
||||||
|
assertThat("async run context path", responseBody, containsString("async:run:attr:contextPath:/ctx"));
|
||||||
|
assertThat("async run request uri has correct encoding", responseBody, containsString("async:run:attr:requestURI:/ctx/test/hello%2fthere"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore("See https://github.com/eclipse/jetty.project/issues/1618")
|
||||||
|
public void testDispatchAsyncContext_SelfEncodedUrl() throws Exception
|
||||||
|
{
|
||||||
|
String request = "GET /ctx/self/hello%2fthere?dispatch=true HTTP/1.1\r\n" +
|
||||||
|
"Host: localhost\r\n" +
|
||||||
|
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||||
|
"Connection: close\r\n" +
|
||||||
|
"\r\n";
|
||||||
|
HttpTester.Response response = HttpTester.parseResponse(_connector.getResponse(request));
|
||||||
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||||
|
|
||||||
|
String responseBody = response.getContent();
|
||||||
|
|
||||||
|
assertThat("servlet request uri initial", responseBody, containsString("doGet:REQUEST.requestURI:/ctx/self/hello%2fthere"));
|
||||||
|
assertThat("servlet request uri async", responseBody, containsString("doGet:ASYNC.requestURI:/ctx/self/hello%2fthere"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDispatchAsyncContextEncodedPathAndQueryString() throws Exception
|
public void testDispatchAsyncContextEncodedPathAndQueryString() throws Exception
|
||||||
{
|
{
|
||||||
String request = "GET /ctx/path%20with%20spaces/servletPath?dispatch=true&queryStringWithEncoding=space%20space HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
|
String request = "GET /ctx/path%20with%20spaces/servletPath?dispatch=true&queryStringWithEncoding=space%20space HTTP/1.1\r\n" +
|
||||||
+ "Connection: close\r\n" + "\r\n";
|
"Host: localhost\r\n" +
|
||||||
String responseString = _connector.getResponse(request);
|
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||||
|
"Connection: close\r\n" +
|
||||||
|
"\r\n";
|
||||||
|
HttpTester.Response response = HttpTester.parseResponse(_connector.getResponse(request));
|
||||||
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||||
|
|
||||||
BufferedReader br = parseHeader(responseString);
|
String responseBody = response.getContent();
|
||||||
|
|
||||||
assertThat("servlet gets right path", br.readLine(), equalTo("doGet:getServletPath:/servletPath2"));
|
assertThat("servlet gets right path", responseBody, containsString("doGet:getServletPath:/servletPath2"));
|
||||||
assertThat("async context gets right path in get", br.readLine(), equalTo("doGet:async:getServletPath:/servletPath2"));
|
assertThat("async context gets right path in get", responseBody, containsString("doGet:async:getServletPath:/servletPath2"));
|
||||||
assertThat("servlet path attr is original", br.readLine(), equalTo("async:run:attr:servletPath:/path with spaces/servletPath"));
|
assertThat("servlet path attr is original", responseBody, containsString("async:run:attr:servletPath:/path with spaces/servletPath"));
|
||||||
assertThat("path info attr is correct", br.readLine(), equalTo("async:run:attr:pathInfo:null"));
|
assertThat("path info attr is correct", responseBody, containsString("async:run:attr:pathInfo:null"));
|
||||||
assertThat("query string attr is correct", br.readLine(), equalTo("async:run:attr:queryString:dispatch=true&queryStringWithEncoding=space%20space"));
|
assertThat("query string attr is correct", responseBody, containsString("async:run:attr:queryString:dispatch=true&queryStringWithEncoding=space%20space"));
|
||||||
assertThat("context path attr is correct", br.readLine(), equalTo("async:run:attr:contextPath:/ctx"));
|
assertThat("context path attr is correct", responseBody, containsString("async:run:attr:contextPath:/ctx"));
|
||||||
assertThat("request uri attr is correct", br.readLine(), equalTo("async:run:attr:requestURI:/ctx/path%20with%20spaces/servletPath"));
|
assertThat("request uri attr is correct", responseBody, containsString("async:run:attr:requestURI:/ctx/path%20with%20spaces/servletPath"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSimpleWithContextAsyncContext() throws Exception
|
public void testSimpleWithContextAsyncContext() throws Exception
|
||||||
{
|
{
|
||||||
String request = "GET /ctx/servletPath HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
|
String request = "GET /ctx/servletPath HTTP/1.1\r\n" +
|
||||||
+ "Connection: close\r\n" + "\r\n";
|
"Host: localhost\r\n" +
|
||||||
|
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||||
|
"Connection: close\r\n" +
|
||||||
|
"\r\n";
|
||||||
|
|
||||||
String responseString = _connector.getResponse(request);
|
HttpTester.Response response = HttpTester.parseResponse(_connector.getResponse(request));
|
||||||
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||||
|
|
||||||
BufferedReader br = parseHeader(responseString);
|
String responseBody = response.getContent();
|
||||||
|
|
||||||
Assert.assertEquals("servlet gets right path", "doGet:getServletPath:/servletPath", br.readLine());
|
assertThat("servlet gets right path", responseBody, containsString("doGet:getServletPath:/servletPath"));
|
||||||
Assert.assertEquals("async context gets right path in get", "doGet:async:getServletPath:/servletPath", br.readLine());
|
assertThat("async context gets right path in get", responseBody, containsString("doGet:async:getServletPath:/servletPath"));
|
||||||
Assert.assertEquals("async context gets right path in async", "async:run:attr:servletPath:/servletPath", br.readLine());
|
assertThat("async context gets right path in async", responseBody, containsString("async:run:attr:servletPath:/servletPath"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDispatchWithContextAsyncContext() throws Exception
|
public void testDispatchWithContextAsyncContext() throws Exception
|
||||||
{
|
{
|
||||||
String request = "GET /ctx/servletPath?dispatch=true HTTP/1.1\r\n" + "Host: localhost\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"
|
String request = "GET /ctx/servletPath?dispatch=true HTTP/1.1\r\n" +
|
||||||
+ "Connection: close\r\n" + "\r\n";
|
"Host: localhost\r\n" +
|
||||||
|
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||||
|
"Connection: close\r\n" +
|
||||||
|
"\r\n";
|
||||||
|
|
||||||
String responseString = _connector.getResponse(request);
|
HttpTester.Response response = HttpTester.parseResponse(_connector.getResponse(request));
|
||||||
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||||
|
|
||||||
BufferedReader br = parseHeader(responseString);
|
String responseBody = response.getContent();
|
||||||
|
|
||||||
Assert.assertEquals("servlet gets right path", "doGet:getServletPath:/servletPath2", br.readLine());
|
assertThat("servlet gets right path", responseBody, containsString("doGet:getServletPath:/servletPath2"));
|
||||||
Assert.assertEquals("async context gets right path in get", "doGet:async:getServletPath:/servletPath2", br.readLine());
|
assertThat("async context gets right path in get", responseBody, containsString("doGet:async:getServletPath:/servletPath2"));
|
||||||
Assert.assertEquals("servlet path attr is original", "async:run:attr:servletPath:/servletPath", br.readLine());
|
assertThat("servlet path attr is original", responseBody, containsString("async:run:attr:servletPath:/servletPath"));
|
||||||
Assert.assertEquals("path info attr is correct", "async:run:attr:pathInfo:null", br.readLine());
|
assertThat("path info attr is correct", responseBody, containsString("async:run:attr:pathInfo:null"));
|
||||||
Assert.assertEquals("query string attr is correct", "async:run:attr:queryString:dispatch=true", br.readLine());
|
assertThat("query string attr is correct", responseBody, containsString("async:run:attr:queryString:dispatch=true"));
|
||||||
Assert.assertEquals("context path attr is correct", "async:run:attr:contextPath:/ctx", br.readLine());
|
assertThat("context path attr is correct", responseBody, containsString("async:run:attr:contextPath:/ctx"));
|
||||||
Assert.assertEquals("request uri attr is correct", "async:run:attr:requestURI:/ctx/servletPath", br.readLine());
|
assertThat("request uri attr is correct", responseBody, containsString("async:run:attr:requestURI:/ctx/servletPath"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -277,8 +354,11 @@ public class AsyncContextTest
|
||||||
|
|
||||||
String responseString = _connector.getResponse(request);
|
String responseString = _connector.getResponse(request);
|
||||||
System.err.println(responseString);
|
System.err.println(responseString);
|
||||||
BufferedReader br = parseHeader(responseString);
|
HttpTester.Response response = HttpTester.parseResponse(responseString);
|
||||||
assertThat("!ForwardingServlet", br.readLine(), equalTo("Dispatched back to ForwardingServlet"));
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||||
|
|
||||||
|
String responseBody = response.getContent();
|
||||||
|
assertThat("!ForwardingServlet", responseBody, containsString("Dispatched back to ForwardingServlet"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -292,24 +372,12 @@ public class AsyncContextTest
|
||||||
|
|
||||||
String responseString = _connector.getResponse(request);
|
String responseString = _connector.getResponse(request);
|
||||||
|
|
||||||
BufferedReader br = parseHeader(responseString);
|
HttpTester.Response response = HttpTester.parseResponse(responseString);
|
||||||
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_OK));
|
||||||
|
|
||||||
assertThat("!AsyncDispatchingServlet", br.readLine(), equalTo("Dispatched back to AsyncDispatchingServlet"));
|
String responseBody = response.getContent();
|
||||||
}
|
|
||||||
|
|
||||||
private BufferedReader parseHeader(String responseString) throws IOException
|
assertThat("!AsyncDispatchingServlet", responseBody, containsString("Dispatched back to AsyncDispatchingServlet"));
|
||||||
{
|
|
||||||
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
|
||||||
assertEquals("HTTP/1.1 200 OK", br.readLine());
|
|
||||||
readHeader(br);
|
|
||||||
return br;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readHeader(BufferedReader br) throws IOException
|
|
||||||
{
|
|
||||||
String line = br.readLine();
|
|
||||||
while (line!=null && !line.isEmpty())
|
|
||||||
line = br.readLine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ForwardingServlet extends HttpServlet
|
private class ForwardingServlet extends HttpServlet
|
||||||
|
@ -330,6 +398,28 @@ public class AsyncContextTest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class SelfDispatchingServlet extends HttpServlet
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
|
||||||
|
{
|
||||||
|
DispatcherType dispatcherType = request.getDispatcherType();
|
||||||
|
response.getOutputStream().print("doGet." + dispatcherType.name() + ".requestURI:" + request.getRequestURI() + "\n");
|
||||||
|
|
||||||
|
if (dispatcherType == DispatcherType.ASYNC)
|
||||||
|
{
|
||||||
|
response.getOutputStream().print("Dispatched back to " + SelfDispatchingServlet.class.getSimpleName() + "\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
final AsyncContext asyncContext = request.startAsync(request, response);
|
||||||
|
new Thread(() -> asyncContext.dispatch()).start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class AsyncDispatchingServlet extends HttpServlet
|
private class AsyncDispatchingServlet extends HttpServlet
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
@ -369,13 +459,12 @@ public class AsyncContextTest
|
||||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||||
"Connection: close\r\n" +
|
"Connection: close\r\n" +
|
||||||
"\r\n";
|
"\r\n";
|
||||||
String responseString = _connector.getResponse(request);
|
HttpTester.Response response = HttpTester.parseResponse(_connector.getResponse(request));
|
||||||
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
|
||||||
|
|
||||||
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
String responseBody = response.getContent();
|
||||||
|
|
||||||
assertEquals("HTTP/1.1 500 Server Error", br.readLine());
|
assertThat("error servlet", responseBody, containsString("ERROR: /error"));
|
||||||
readHeader(br);
|
|
||||||
Assert.assertEquals("error servlet", "ERROR: /error", br.readLine());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -386,16 +475,14 @@ public class AsyncContextTest
|
||||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||||
"Connection: close\r\n" +
|
"Connection: close\r\n" +
|
||||||
"\r\n";
|
"\r\n";
|
||||||
String responseString = _connector.getResponse(request);
|
HttpTester.Response response = HttpTester.parseResponse(_connector.getResponse(request));
|
||||||
|
assertThat("Response.status", response.getStatus(), is(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
|
||||||
|
|
||||||
BufferedReader br = new BufferedReader(new StringReader(responseString));
|
String responseBody = response.getContent();
|
||||||
|
|
||||||
assertEquals("HTTP/1.1 500 Server Error", br.readLine());
|
assertThat("error servlet", responseBody, containsString("ERROR: /error"));
|
||||||
readHeader(br);
|
assertThat("error servlet", responseBody, containsString("PathInfo= /500"));
|
||||||
|
assertThat("error servlet", responseBody, containsString("EXCEPTION: java.lang.RuntimeException: TEST"));
|
||||||
Assert.assertEquals("error servlet", "ERROR: /error", br.readLine());
|
|
||||||
Assert.assertEquals("error servlet", "PathInfo= /500", br.readLine());
|
|
||||||
Assert.assertEquals("error servlet", "EXCEPTION: java.lang.RuntimeException: TEST", br.readLine());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DispatchingRunnable implements Runnable
|
private class DispatchingRunnable implements Runnable
|
||||||
|
@ -495,6 +582,17 @@ public class AsyncContextTest
|
||||||
private class TestServlet extends HttpServlet
|
private class TestServlet extends HttpServlet
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
private String dispatchPath = "/servletPath2";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() throws ServletException
|
||||||
|
{
|
||||||
|
String dispatchTo = getServletConfig().getInitParameter("dispatchPath");
|
||||||
|
if (StringUtil.isNotBlank(dispatchTo))
|
||||||
|
{
|
||||||
|
this.dispatchPath = dispatchTo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||||
|
@ -502,13 +600,20 @@ public class AsyncContextTest
|
||||||
if (request.getParameter("dispatch") != null)
|
if (request.getParameter("dispatch") != null)
|
||||||
{
|
{
|
||||||
AsyncContext asyncContext = request.startAsync(request, response);
|
AsyncContext asyncContext = request.startAsync(request, response);
|
||||||
asyncContext.dispatch("/servletPath2");
|
asyncContext.dispatch(dispatchPath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
response.getOutputStream().print("doGet:getServletPath:" + request.getServletPath() + "\n");
|
response.getOutputStream().print("doGet:getServletPath:" + request.getServletPath() + "\n");
|
||||||
|
response.getOutputStream().print("doGet:getRequestURI:" + request.getRequestURI() + "\n");
|
||||||
|
response.getOutputStream().print("doGet:getRequestURL:" + request.getRequestURL() + "\n");
|
||||||
|
response.getOutputStream().print("doGet:getPathInfo:" + request.getPathInfo() + "\n");
|
||||||
AsyncContext asyncContext = request.startAsync(request, response);
|
AsyncContext asyncContext = request.startAsync(request, response);
|
||||||
response.getOutputStream().print("doGet:async:getServletPath:" + ((HttpServletRequest)asyncContext.getRequest()).getServletPath() + "\n");
|
HttpServletRequest asyncRequest = (HttpServletRequest)asyncContext.getRequest();
|
||||||
|
response.getOutputStream().print("doGet:async:getServletPath:" + asyncRequest.getServletPath() + "\n");
|
||||||
|
response.getOutputStream().print("doGet:async:getRequestURI:" + asyncRequest.getRequestURI() + "\n");
|
||||||
|
response.getOutputStream().print("doGet:async:getRequestURL:" + asyncRequest.getRequestURL() + "\n");
|
||||||
|
response.getOutputStream().print("doGet:async:getPathInfo:" + asyncRequest.getPathInfo() + "\n");
|
||||||
asyncContext.start(new AsyncRunnable(asyncContext));
|
asyncContext.start(new AsyncRunnable(asyncContext));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -523,8 +628,15 @@ public class AsyncContextTest
|
||||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||||
{
|
{
|
||||||
response.getOutputStream().print("doGet:getServletPath:" + request.getServletPath() + "\n");
|
response.getOutputStream().print("doGet:getServletPath:" + request.getServletPath() + "\n");
|
||||||
|
response.getOutputStream().print("doGet:getRequestURI:" + request.getRequestURI() + "\n");
|
||||||
|
response.getOutputStream().print("doGet:getRequestURL:" + request.getRequestURL() + "\n");
|
||||||
|
response.getOutputStream().print("doGet:getPathInfo:" + request.getPathInfo() + "\n");
|
||||||
AsyncContext asyncContext = request.startAsync(request, response);
|
AsyncContext asyncContext = request.startAsync(request, response);
|
||||||
response.getOutputStream().print("doGet:async:getServletPath:" + ((HttpServletRequest)asyncContext.getRequest()).getServletPath() + "\n");
|
HttpServletRequest asyncRequest = (HttpServletRequest)asyncContext.getRequest();
|
||||||
|
response.getOutputStream().print("doGet:async:getServletPath:" + asyncRequest.getServletPath() + "\n");
|
||||||
|
response.getOutputStream().print("doGet:async:getRequestURI:" + asyncRequest.getRequestURI() + "\n");
|
||||||
|
response.getOutputStream().print("doGet:async:getRequestURL:" + asyncRequest.getRequestURL() + "\n");
|
||||||
|
response.getOutputStream().print("doGet:async:getPathInfo:" + asyncRequest.getPathInfo() + "\n");
|
||||||
asyncContext.start(new AsyncRunnable(asyncContext));
|
asyncContext.start(new AsyncRunnable(asyncContext));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue