* Issue #4713 Async dispatch with query. + Preserve the entire URI with query when startAsync(req,res) is used. + merge any query string from dispatch path with either original query or preserved query from forward Signed-off-by: Greg Wilkins <gregw@webtide.com> * Issue #4713 asyncDispatch with query parameters Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
parent
fa54c74946
commit
e3d670d61d
|
@ -760,15 +760,15 @@ public class HttpURI
|
|||
_decodedPath = path;
|
||||
}
|
||||
|
||||
public void setPathQuery(String path)
|
||||
public void setPathQuery(String pathQuery)
|
||||
{
|
||||
_uri = null;
|
||||
_path = null;
|
||||
_decodedPath = null;
|
||||
_param = null;
|
||||
_fragment = null;
|
||||
if (path != null)
|
||||
parse(State.PATH, path);
|
||||
if (pathQuery != null)
|
||||
parse(State.PATH, pathQuery);
|
||||
}
|
||||
|
||||
public void setQuery(String query)
|
||||
|
|
|
@ -25,6 +25,7 @@ import javax.servlet.ServletContext;
|
|||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpURI;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler.Context;
|
||||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
|
||||
|
@ -32,6 +33,7 @@ public class AsyncContextEvent extends AsyncEvent implements Runnable
|
|||
{
|
||||
private final Context _context;
|
||||
private final AsyncContextState _asyncContext;
|
||||
private final HttpURI _baseURI;
|
||||
private volatile HttpChannelState _state;
|
||||
private ServletContext _dispatchContext;
|
||||
private String _dispatchPath;
|
||||
|
@ -39,11 +41,17 @@ public class AsyncContextEvent extends AsyncEvent implements Runnable
|
|||
private Throwable _throwable;
|
||||
|
||||
public AsyncContextEvent(Context context, AsyncContextState asyncContext, HttpChannelState state, Request baseRequest, ServletRequest request, ServletResponse response)
|
||||
{
|
||||
this (context, asyncContext, state, baseRequest, request, response, null);
|
||||
}
|
||||
|
||||
public AsyncContextEvent(Context context, AsyncContextState asyncContext, HttpChannelState state, Request baseRequest, ServletRequest request, ServletResponse response, HttpURI baseURI)
|
||||
{
|
||||
super(null, request, response, null);
|
||||
_context = context;
|
||||
_asyncContext = asyncContext;
|
||||
_state = state;
|
||||
_baseURI = baseURI;
|
||||
|
||||
// If we haven't been async dispatched before
|
||||
if (baseRequest.getAttribute(AsyncContext.ASYNC_REQUEST_URI) == null)
|
||||
|
@ -74,6 +82,11 @@ public class AsyncContextEvent extends AsyncEvent implements Runnable
|
|||
}
|
||||
}
|
||||
|
||||
public HttpURI getBaseURI()
|
||||
{
|
||||
return _baseURI;
|
||||
}
|
||||
|
||||
public ServletContext getSuspendedContext()
|
||||
{
|
||||
return _context;
|
||||
|
@ -94,14 +107,6 @@ public class AsyncContextEvent extends AsyncEvent implements Runnable
|
|||
return _dispatchContext == null ? _context : _dispatchContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The path in the context (encoded with possible query string)
|
||||
*/
|
||||
public String getPath()
|
||||
{
|
||||
return _dispatchPath;
|
||||
}
|
||||
|
||||
public void setTimeoutTask(Scheduler.Task task)
|
||||
{
|
||||
_timeoutTask = task;
|
||||
|
@ -137,6 +142,14 @@ public class AsyncContextEvent extends AsyncEvent implements Runnable
|
|||
_dispatchContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The path in the context (encoded with possible query string)
|
||||
*/
|
||||
public String getDispatchPath()
|
||||
{
|
||||
return _dispatchPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param path encoded URI
|
||||
*/
|
||||
|
|
|
@ -1598,7 +1598,10 @@ public class Request implements HttpServletRequest
|
|||
{
|
||||
MetaData.Request metadata = _metaData;
|
||||
if (metadata != null)
|
||||
{
|
||||
metadata.setURI(uri);
|
||||
_queryParameters = null;
|
||||
}
|
||||
}
|
||||
|
||||
public UserIdentity getUserIdentity()
|
||||
|
@ -2178,17 +2181,8 @@ public class Request implements HttpServletRequest
|
|||
HttpChannelState state = getHttpChannelState();
|
||||
if (_async == null)
|
||||
_async = new AsyncContextState(state);
|
||||
AsyncContextEvent event = new AsyncContextEvent(_context, _async, state, this, servletRequest, servletResponse);
|
||||
AsyncContextEvent event = new AsyncContextEvent(_context, _async, state, this, servletRequest, servletResponse, getHttpURI());
|
||||
event.setDispatchContext(getServletContext());
|
||||
|
||||
String uri = unwrap(servletRequest).getRequestURI();
|
||||
if (_contextPath != null && uri.startsWith(_contextPath))
|
||||
uri = uri.substring(_contextPath.length());
|
||||
else
|
||||
// TODO probably need to strip encoded context from requestURI, but will do this for now:
|
||||
uri = URIUtil.encodePath(URIUtil.addPaths(getServletPath(), getPathInfo()));
|
||||
|
||||
event.setDispatchPath(uri);
|
||||
state.startAsync(event);
|
||||
return _async;
|
||||
}
|
||||
|
@ -2391,7 +2385,7 @@ public class Request implements HttpServletRequest
|
|||
setQueryString(oldQuery);
|
||||
else if (oldQuery == null)
|
||||
setQueryString(newQuery);
|
||||
else
|
||||
else if (oldQueryParams.keySet().stream().anyMatch(newQueryParams.keySet()::contains))
|
||||
{
|
||||
// Build the new merged query string, parameters in the
|
||||
// new query string hide parameters in the old query string.
|
||||
|
@ -2413,6 +2407,10 @@ public class Request implements HttpServletRequest
|
|||
}
|
||||
setQueryString(mergedQuery.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
setQueryString(newQuery + '&' + oldQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,8 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
|
|||
import org.eclipse.jetty.util.Attributes;
|
||||
import org.eclipse.jetty.util.Jetty;
|
||||
import org.eclipse.jetty.util.MultiException;
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.Uptime;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
|
@ -563,22 +565,74 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
{
|
||||
final HttpChannelState state = channel.getRequest().getHttpChannelState();
|
||||
final AsyncContextEvent event = state.getAsyncContextEvent();
|
||||
|
||||
final Request baseRequest = channel.getRequest();
|
||||
final String path = event.getPath();
|
||||
final HttpURI baseUri = event.getBaseURI();
|
||||
String encodedPathQuery = event.getDispatchPath();
|
||||
|
||||
if (path != null)
|
||||
if (encodedPathQuery == null && baseUri == null)
|
||||
{
|
||||
// this is a dispatch with a path
|
||||
ServletContext context = event.getServletContext();
|
||||
String query = baseRequest.getQueryString();
|
||||
baseRequest.setURIPathQuery(URIUtil.addEncodedPaths(context == null ? null : URIUtil.encodePath(context.getContextPath()), path));
|
||||
HttpURI uri = baseRequest.getHttpURI();
|
||||
baseRequest.setPathInfo(uri.getDecodedPath());
|
||||
if (uri.getQuery() != null)
|
||||
baseRequest.mergeQueryParameters(query, uri.getQuery(), true); //we have to assume dispatch path and query are UTF8
|
||||
// Simple case, no request modification or merging needed
|
||||
handleAsync(channel, event, baseRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
// this is a dispatch with either a provided URI and/or a dispatched path
|
||||
// We will have to modify the request and then revert
|
||||
final ServletContext context = event.getServletContext();
|
||||
final HttpURI oldUri = baseRequest.getHttpURI();
|
||||
final String oldQuery = baseRequest.getQueryString();
|
||||
final MultiMap<String> oldQueryParams = baseRequest.getQueryParameters();
|
||||
try
|
||||
{
|
||||
baseRequest.resetParameters();
|
||||
HttpURI newUri = baseUri == null ? new HttpURI(oldUri) : baseUri;
|
||||
if (encodedPathQuery == null)
|
||||
{
|
||||
baseRequest.setHttpURI(newUri);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (context != null && !StringUtil.isEmpty(context.getContextPath()))
|
||||
encodedPathQuery = URIUtil.addEncodedPaths(URIUtil.encodePath(context.getContextPath()), encodedPathQuery);
|
||||
|
||||
if (newUri.getQuery() == null)
|
||||
{
|
||||
// parse new path and query
|
||||
newUri.setPathQuery(encodedPathQuery);
|
||||
baseRequest.setHttpURI(newUri);
|
||||
}
|
||||
else
|
||||
{
|
||||
// do we have a new query in the encodedPathQuery
|
||||
int q = encodedPathQuery.indexOf('?');
|
||||
if (q < 0)
|
||||
{
|
||||
// No query, so we can just set the encoded path
|
||||
newUri.setPath(encodedPathQuery);
|
||||
baseRequest.setHttpURI(newUri);
|
||||
}
|
||||
else
|
||||
{
|
||||
newUri.setPath(encodedPathQuery.substring(0, q));
|
||||
baseRequest.setHttpURI(newUri);
|
||||
baseRequest.mergeQueryParameters(oldQuery, encodedPathQuery.substring(q + 1), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
baseRequest.setPathInfo(newUri.getDecodedPath());
|
||||
handleAsync(channel, event, baseRequest);
|
||||
}
|
||||
finally
|
||||
{
|
||||
baseRequest.setHttpURI(oldUri);
|
||||
baseRequest.setQueryParameters(oldQueryParams);
|
||||
baseRequest.resetParameters();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleAsync(HttpChannel channel, AsyncContextEvent event, Request baseRequest) throws IOException, ServletException
|
||||
{
|
||||
final String target = baseRequest.getPathInfo();
|
||||
final HttpServletRequest request = Request.unwrap(event.getSuppliedRequest());
|
||||
final HttpServletResponse response = Response.unwrap(event.getSuppliedResponse());
|
||||
|
|
|
@ -163,7 +163,7 @@ public class AsyncServletTest
|
|||
String response = process("sleep=200", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?sleep=200",
|
||||
"initial"));
|
||||
assertContains("SLEPT", response);
|
||||
assertFalse(__history.contains("onTimeout"));
|
||||
|
@ -173,7 +173,7 @@ public class AsyncServletTest
|
|||
@Test
|
||||
public void testNonAsync() throws Exception
|
||||
{
|
||||
String response = process("", null);
|
||||
String response = process(null, null);
|
||||
assertThat(response, Matchers.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
|
@ -186,7 +186,7 @@ public class AsyncServletTest
|
|||
public void testAsyncNotSupportedNoAsync() throws Exception
|
||||
{
|
||||
_expectedCode = "200 ";
|
||||
String response = process("noasync", "", null);
|
||||
String response = process("noasync", null, null);
|
||||
assertThat(response, Matchers.startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/noasync/info",
|
||||
|
@ -205,9 +205,9 @@ public class AsyncServletTest
|
|||
String response = process("noasync", "start=200", null);
|
||||
assertThat(response, Matchers.startsWith("HTTP/1.1 500 "));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/noasync/info",
|
||||
"REQUEST /ctx/noasync/info?start=200",
|
||||
"initial",
|
||||
"ERROR /ctx/error/custom",
|
||||
"ERROR /ctx/error/custom?start=200",
|
||||
"!initial"
|
||||
));
|
||||
|
||||
|
@ -224,11 +224,11 @@ public class AsyncServletTest
|
|||
String response = process("start=200", null);
|
||||
assertThat(response, Matchers.startsWith("HTTP/1.1 500 Server Error"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=200",
|
||||
"initial",
|
||||
"start",
|
||||
"onTimeout",
|
||||
"ERROR /ctx/error/custom",
|
||||
"ERROR /ctx/error/custom?start=200",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
|
||||
|
@ -241,12 +241,12 @@ public class AsyncServletTest
|
|||
String response = process("start=200&timeout=dispatch", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=200&timeout=dispatch",
|
||||
"initial",
|
||||
"start",
|
||||
"onTimeout",
|
||||
"dispatch",
|
||||
"ASYNC /ctx/path/info",
|
||||
"ASYNC /ctx/path/info?start=200&timeout=dispatch",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
|
||||
|
@ -260,12 +260,12 @@ public class AsyncServletTest
|
|||
String response = process("start=200&timeout=error", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 500 Server Error"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=200&timeout=error",
|
||||
"initial",
|
||||
"start",
|
||||
"onTimeout",
|
||||
"error",
|
||||
"ERROR /ctx/error/custom",
|
||||
"ERROR /ctx/error/custom?start=200&timeout=error",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
|
||||
|
@ -278,7 +278,7 @@ public class AsyncServletTest
|
|||
String response = process("start=200&timeout=complete", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=200&timeout=complete",
|
||||
"initial",
|
||||
"start",
|
||||
"onTimeout",
|
||||
|
@ -294,11 +294,11 @@ public class AsyncServletTest
|
|||
String response = process("start=200&dispatch=10", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=200&dispatch=10",
|
||||
"initial",
|
||||
"start",
|
||||
"dispatch",
|
||||
"ASYNC /ctx/path/info",
|
||||
"ASYNC /ctx/path/info?start=200&dispatch=10",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
assertFalse(__history.contains("onTimeout"));
|
||||
|
@ -310,11 +310,11 @@ public class AsyncServletTest
|
|||
String response = process("start=200&dispatch=0", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=200&dispatch=0",
|
||||
"initial",
|
||||
"start",
|
||||
"dispatch",
|
||||
"ASYNC /ctx/path/info",
|
||||
"ASYNC /ctx/path/info?start=200&dispatch=0",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
}
|
||||
|
@ -326,11 +326,11 @@ public class AsyncServletTest
|
|||
String response = process("start=200&throw=1", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 500 Server Error"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=200&throw=1",
|
||||
"initial",
|
||||
"start",
|
||||
"onError",
|
||||
"ERROR /ctx/error/custom",
|
||||
"ERROR /ctx/error/custom?start=200&throw=1",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
assertContains("ERROR DISPATCH: /ctx/error/custom", response);
|
||||
|
@ -342,7 +342,7 @@ public class AsyncServletTest
|
|||
String response = process("start=200&complete=50", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=200&complete=50",
|
||||
"initial",
|
||||
"start",
|
||||
"complete",
|
||||
|
@ -358,7 +358,7 @@ public class AsyncServletTest
|
|||
String response = process("start=200&complete=0", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=200&complete=0",
|
||||
"initial",
|
||||
"start",
|
||||
"complete",
|
||||
|
@ -374,16 +374,16 @@ public class AsyncServletTest
|
|||
String response = process("start=1000&dispatch=10&start2=1000&dispatch2=10", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=1000&dispatch=10&start2=1000&dispatch2=10",
|
||||
"initial",
|
||||
"start",
|
||||
"dispatch",
|
||||
"ASYNC /ctx/path/info",
|
||||
"ASYNC /ctx/path/info?start=1000&dispatch=10&start2=1000&dispatch2=10",
|
||||
"!initial",
|
||||
"onStartAsync",
|
||||
"start",
|
||||
"dispatch",
|
||||
"ASYNC /ctx/path/info",
|
||||
"ASYNC /ctx/path/info?start=1000&dispatch=10&start2=1000&dispatch2=10",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
assertContains("DISPATCHED", response);
|
||||
|
@ -395,11 +395,11 @@ public class AsyncServletTest
|
|||
String response = process("start=1000&dispatch=10&start2=1000&complete2=10", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=1000&dispatch=10&start2=1000&complete2=10",
|
||||
"initial",
|
||||
"start",
|
||||
"dispatch",
|
||||
"ASYNC /ctx/path/info",
|
||||
"ASYNC /ctx/path/info?start=1000&dispatch=10&start2=1000&complete2=10",
|
||||
"!initial",
|
||||
"onStartAsync",
|
||||
"start",
|
||||
|
@ -415,16 +415,16 @@ public class AsyncServletTest
|
|||
String response = process("start=1000&dispatch=10&start2=10", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 500 Server Error"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=1000&dispatch=10&start2=10",
|
||||
"initial",
|
||||
"start",
|
||||
"dispatch",
|
||||
"ASYNC /ctx/path/info",
|
||||
"ASYNC /ctx/path/info?start=1000&dispatch=10&start2=10",
|
||||
"!initial",
|
||||
"onStartAsync",
|
||||
"start",
|
||||
"onTimeout",
|
||||
"ERROR /ctx/error/custom",
|
||||
"ERROR /ctx/error/custom?start=1000&dispatch=10&start2=10",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
assertContains("ERROR DISPATCH: /ctx/error/custom", response);
|
||||
|
@ -436,16 +436,16 @@ public class AsyncServletTest
|
|||
String response = process("start=10&start2=1000&dispatch2=10", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=10&start2=1000&dispatch2=10",
|
||||
"initial",
|
||||
"start",
|
||||
"onTimeout",
|
||||
"ERROR /ctx/error/custom",
|
||||
"ERROR /ctx/error/custom?start=10&start2=1000&dispatch2=10",
|
||||
"!initial",
|
||||
"onStartAsync",
|
||||
"start",
|
||||
"dispatch",
|
||||
"ASYNC /ctx/path/info",
|
||||
"ASYNC /ctx/path/info?start=10&start2=1000&dispatch2=10",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
assertContains("DISPATCHED", response);
|
||||
|
@ -457,11 +457,11 @@ public class AsyncServletTest
|
|||
String response = process("start=10&start2=1000&complete2=10", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=10&start2=1000&complete2=10",
|
||||
"initial",
|
||||
"start",
|
||||
"onTimeout",
|
||||
"ERROR /ctx/error/custom",
|
||||
"ERROR /ctx/error/custom?start=10&start2=1000&complete2=10",
|
||||
"!initial",
|
||||
"onStartAsync",
|
||||
"start",
|
||||
|
@ -478,16 +478,16 @@ public class AsyncServletTest
|
|||
|
||||
String response = process("start=10&start2=10", null);
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=10&start2=10",
|
||||
"initial",
|
||||
"start",
|
||||
"onTimeout",
|
||||
"ERROR /ctx/path/error",
|
||||
"ERROR /ctx/path/error?start=10&start2=10",
|
||||
"!initial",
|
||||
"onStartAsync",
|
||||
"start",
|
||||
"onTimeout",
|
||||
"ERROR /ctx/path/error",
|
||||
"ERROR /ctx/path/error?start=10&start2=10",
|
||||
"!initial",
|
||||
"onComplete")); // Error Page Loop!
|
||||
assertContains("AsyncContext timeout", response);
|
||||
|
@ -499,11 +499,11 @@ public class AsyncServletTest
|
|||
String response = process("wrap=true&start=200&dispatch=20", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?wrap=true&start=200&dispatch=20",
|
||||
"initial",
|
||||
"start",
|
||||
"dispatch",
|
||||
"ASYNC /ctx/path/info",
|
||||
"ASYNC /ctx/path/info?wrap=true&start=200&dispatch=20",
|
||||
"wrapped REQ RSP",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
|
@ -516,11 +516,11 @@ public class AsyncServletTest
|
|||
String response = process("start=200&dispatch=20&path=/p%20th3", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=200&dispatch=20&path=/p%20th3",
|
||||
"initial",
|
||||
"start",
|
||||
"dispatch",
|
||||
"ASYNC /ctx/p%20th3",
|
||||
"ASYNC /ctx/p%20th3?start=200&dispatch=20&path=/p%20th3",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
assertContains("DISPATCHED", response);
|
||||
|
@ -532,13 +532,13 @@ public class AsyncServletTest
|
|||
String response = process("fwd", "start=200&dispatch=20", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"FWD REQUEST /ctx/fwd/info",
|
||||
"FORWARD /ctx/path1",
|
||||
"FWD REQUEST /ctx/fwd/info?start=200&dispatch=20",
|
||||
"FORWARD /ctx/path1?forward=true&start=200&dispatch=20",
|
||||
"initial",
|
||||
"start",
|
||||
"dispatch",
|
||||
"FWD ASYNC /ctx/fwd/info",
|
||||
"FORWARD /ctx/path1",
|
||||
"FWD ASYNC /ctx/fwd/info?start=200&dispatch=20",
|
||||
"FORWARD /ctx/path1?forward=true&start=200&dispatch=20",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
assertContains("DISPATCHED", response);
|
||||
|
@ -550,12 +550,12 @@ public class AsyncServletTest
|
|||
String response = process("fwd", "start=200&dispatch=20&path=/path2", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"FWD REQUEST /ctx/fwd/info",
|
||||
"FORWARD /ctx/path1",
|
||||
"FWD REQUEST /ctx/fwd/info?start=200&dispatch=20&path=/path2",
|
||||
"FORWARD /ctx/path1?forward=true&start=200&dispatch=20&path=/path2",
|
||||
"initial",
|
||||
"start",
|
||||
"dispatch",
|
||||
"ASYNC /ctx/path2",
|
||||
"ASYNC /ctx/path2?start=200&dispatch=20&path=/path2",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
assertContains("DISPATCHED", response);
|
||||
|
@ -567,12 +567,12 @@ public class AsyncServletTest
|
|||
String response = process("fwd", "wrap=true&start=200&dispatch=20", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"FWD REQUEST /ctx/fwd/info",
|
||||
"FORWARD /ctx/path1",
|
||||
"FWD REQUEST /ctx/fwd/info?wrap=true&start=200&dispatch=20",
|
||||
"FORWARD /ctx/path1?forward=true&wrap=true&start=200&dispatch=20",
|
||||
"initial",
|
||||
"start",
|
||||
"dispatch",
|
||||
"ASYNC /ctx/path1",
|
||||
"ASYNC /ctx/path1?forward=true&wrap=true&start=200&dispatch=20",
|
||||
"wrapped REQ RSP",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
|
@ -585,12 +585,12 @@ public class AsyncServletTest
|
|||
String response = process("fwd", "wrap=true&start=200&dispatch=20&path=/path2", null);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"FWD REQUEST /ctx/fwd/info",
|
||||
"FORWARD /ctx/path1",
|
||||
"FWD REQUEST /ctx/fwd/info?wrap=true&start=200&dispatch=20&path=/path2",
|
||||
"FORWARD /ctx/path1?forward=true&wrap=true&start=200&dispatch=20&path=/path2",
|
||||
"initial",
|
||||
"start",
|
||||
"dispatch",
|
||||
"ASYNC /ctx/path2",
|
||||
"ASYNC /ctx/path2?forward=true&wrap=true&start=200&dispatch=20&path=/path2",
|
||||
"wrapped REQ RSP",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
|
@ -619,12 +619,12 @@ public class AsyncServletTest
|
|||
__latch.await(1, TimeUnit.SECONDS);
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
assertThat(__history, contains(
|
||||
"REQUEST /ctx/path/info",
|
||||
"REQUEST /ctx/path/info?start=2000&dispatch=1500",
|
||||
"initial",
|
||||
"start",
|
||||
"async-read=10",
|
||||
"dispatch",
|
||||
"ASYNC /ctx/path/info",
|
||||
"ASYNC /ctx/path/info?start=2000&dispatch=1500",
|
||||
"!initial",
|
||||
"onComplete"));
|
||||
}
|
||||
|
@ -685,10 +685,10 @@ public class AsyncServletTest
|
|||
@Override
|
||||
public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
historyAdd("FWD " + request.getDispatcherType() + " " + request.getRequestURI());
|
||||
historyAdd("FWD " + request.getDispatcherType() + " " + URIUtil.addPathQuery(request.getRequestURI(), request.getQueryString()));
|
||||
if (request instanceof ServletRequestWrapper || response instanceof ServletResponseWrapper)
|
||||
historyAdd("wrapped" + ((request instanceof ServletRequestWrapper) ? " REQ" : "") + ((response instanceof ServletResponseWrapper) ? " RSP" : ""));
|
||||
request.getServletContext().getRequestDispatcher("/path1").forward(request, response);
|
||||
request.getServletContext().getRequestDispatcher("/path1?forward=true").forward(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -711,7 +711,7 @@ public class AsyncServletTest
|
|||
// ignored
|
||||
}
|
||||
|
||||
historyAdd(request.getDispatcherType() + " " + request.getRequestURI());
|
||||
historyAdd(request.getDispatcherType() + " " + URIUtil.addPathQuery(request.getRequestURI(),request.getQueryString()));
|
||||
if (request instanceof ServletRequestWrapper || response instanceof ServletResponseWrapper)
|
||||
historyAdd("wrapped" + ((request instanceof ServletRequestWrapper) ? " REQ" : "") + ((response instanceof ServletResponseWrapper) ? " RSP" : ""));
|
||||
|
||||
|
|
|
@ -714,6 +714,20 @@ public class URIUtil
|
|||
return buf.toString();
|
||||
}
|
||||
|
||||
/** Add a path and a query string
|
||||
* @param path The path which may already contain contain a query
|
||||
* @param query The query string or null if no query to be added
|
||||
* @return The path with any non null query added after a '?' or '&' as appropriate.
|
||||
*/
|
||||
public static String addPathQuery(String path, String query)
|
||||
{
|
||||
if (query == null)
|
||||
return path;
|
||||
if (path.indexOf('?') >= 0)
|
||||
return path + '&' + query;
|
||||
return path + '?' + query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a URI, attempt to get the last segment.
|
||||
* <p>
|
||||
|
|
Loading…
Reference in New Issue