* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* @version $Id$
*/
public class CoyoteAdapter implements Adapter {
-
+
private static final Log log = LogFactory.getLog(CoyoteAdapter.class);
// -------------------------------------------------------------- Constants
public static final int ADAPTER_NOTES = 1;
- protected static final boolean ALLOW_BACKSLASH =
+ protected static final boolean ALLOW_BACKSLASH =
Boolean.valueOf(System.getProperty("org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH", "false")).booleanValue();
// -------------------------------------------------------- Adapter Methods
-
+
/**
* Event method.
- *
+ *
* @return false to indicate an error, expected or not
*/
@Override
- public boolean event(org.apache.coyote.Request req,
+ public boolean event(org.apache.coyote.Request req,
org.apache.coyote.Response res, SocketStatus status) {
Request request = (Request) req.getNote(ADAPTER_NOTES);
if (request.getWrapper() == null) {
return false;
}
-
+
boolean error = false;
boolean read = false;
try {
}
req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName());
-
+
// Calling the container
connector.getService().getContainer().getPipeline().getFirst().event(request, response, request.getEvent());
}
}
}
-
+
@Override
public boolean asyncDispatch(org.apache.coyote.Request req,
org.apache.coyote.Response res, SocketStatus status) throws Exception {
// Error or timeout - need to tell listeners the request is over
// Have to test this first since state may change while in this
// method and this is only required if entering this method in
- // this state
+ // this state
Context ctxt = (Context) request.getMappingData().context;
if (ctxt != null) {
ctxt.fireRequestDestroyEvent(request);
request.recycle();
response.recycle();
} else {
- // Clear converters so that the minimum amount of memory
+ // Clear converters so that the minimum amount of memory
// is used by this processor
request.clearEncoders();
response.clearEncoders();
}
return success;
}
-
+
/**
* Service method.
*/
@Override
- public void service(org.apache.coyote.Request req,
+ public void service(org.apache.coyote.Request req,
org.apache.coyote.Response res)
throws Exception {
boolean comet = false;
boolean async = false;
-
+
try {
- // Parse and set Catalina and configuration specific
+ // Parse and set Catalina and configuration specific
// request parameters
req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName());
boolean postParseSuccess = postParseRequest(req, request, res, response);
request.recycle();
response.recycle();
} else {
- // Clear converters so that the minimum amount of memory
+ // Clear converters so that the minimum amount of memory
// is used by this processor
request.clearEncoders();
response.clearEncoders();
Request request = (Request) req.getNote(ADAPTER_NOTES);
Response response = (Response) res.getNote(ADAPTER_NOTES);
-
+
if (request == null) {
// Create objects
request = connector.createRequest();
req.getParameters().setQueryStringEncoding
(connector.getURIEncoding());
}
-
+
try {
// Log at the lowest level available. logAccess() will be
// automatically called on parent containers.
response.recycle();
}
}
-
-
+
+
@Override
public String getDomain() {
return connector.getDomain();
/**
* Parse additional request parameters.
*/
- protected boolean postParseRequest(org.apache.coyote.Request req,
+ protected boolean postParseRequest(org.apache.coyote.Request req,
Request request,
- org.apache.coyote.Response res,
+ org.apache.coyote.Response res,
Response response)
throws Exception {
- // XXX the processor may have set a correct scheme and port prior to this point,
+ // XXX the processor may have set a correct scheme and port prior to this point,
// in ajp13 protocols dont make sense to get the port from the connector...
// otherwise, use connector configuration
if (! req.scheme().isNull()) {
request.setSecure(connector.getSecure());
}
- // FIXME: the code below doesnt belongs to here,
- // this is only have sense
+ // FIXME: the code below doesnt belongs to here,
+ // this is only have sense
// in Http11, not in ajp13..
// At this point the Host header has been processed.
- // Override if the proxyPort/proxyHost are set
+ // Override if the proxyPort/proxyHost are set
String proxyName = connector.getProxyName();
int proxyPort = connector.getProxyPort();
if (proxyPort != 0) {
// Copy the raw URI to the decodedURI
MessageBytes decodedURI = req.decodedURI();
decodedURI.duplicate(req.requestURI());
-
+
// Parse the path parameters. This will:
// - strip out the path parameters
// - convert the decodedURI to bytes
parsePathParameters(req, request);
-
+
// URI decoding
// %xx decoding of the URL
try {
//reset mapping data, should prolly be done elsewhere
request.getMappingData().recycle();
}
-
+
boolean mapRequired = true;
String version = null;
-
+
while (mapRequired) {
if (version != null) {
// Once we have a version - that is it
}
return false;
}
-
+
// Now we have the context, we can parse the session ID from the URL
// (if any). Need to do this before we redirect in case we need to
// include the session id in the redirect
String sessionID = null;
if (request.getServletContext().getEffectiveSessionTrackingModes()
.contains(SessionTrackingMode.URL)) {
-
+
// Get the session ID if there was one
sessionID = request.getPathParameter(
ApplicationSessionCookieConfig.getSessionUriParamName(
// Look for session ID in cookies and SSL session
parseSessionCookiesId(req, request);
parseSessionSslId(request);
-
+
sessionID = request.getRequestedSessionId();
-
+
if (mapRequired) {
if (sessionID == null) {
// No session means no possibility of needing to remap
// Set version so second time through mapping the
// correct context is found
version = ctxt.getWebappVersion();
- // Reset mapping
+ // Reset mapping
request.getMappingData().recycle();
break;
}
// No matching context found. No need to re-map
mapRequired = false;
}
- }
+ }
}
}
}
// Filter trace method
- if (!connector.getAllowTrace()
+ if (!connector.getAllowTrace()
&& req.method().equalsIgnoreCase("TRACE")) {
Wrapper wrapper = request.getWrapper();
String header = null;
}
}
}
- }
+ }
res.setStatus(405);
res.addHeader("Allow", header);
res.setMessage("TRACE method is not allowed");
* of the form /path;name=value;name2=value2/ etc. Currently only really
* interested in the session ID that will be in this form. Other parameters
* can safely be ignored.
- *
+ *
* @param req
* @param request
*/
// Extract path param from decoded request URI
byte[] buf = uriBC.getBuffer();
for (int i = 0; i < end - start - pathParamEnd; i++) {
- buf[start + semicolon + i]
+ buf[start + semicolon + i]
= buf[start + i + pathParamEnd];
}
uriBC.setBytes(buf, start,
end - start - pathParamEnd + semicolon);
} else {
if (charset != null) {
- pv = new String(uriBC.getBuffer(), start + pathParamStart,
+ pv = new String(uriBC.getBuffer(), start + pathParamStart,
(end - start) - pathParamStart, charset);
}
uriBC.setEnd(start + semicolon);
int equals = pv.indexOf('=');
if (equals > -1) {
String name = pv.substring(0, equals);
- String value = pv.substring(equals + 1);
+ String value = pv.substring(equals + 1);
request.addPathParameter(name, value);
if (log.isDebugEnabled()) {
log.debug(sm.getString("coyoteAdapter.debug", "equals",
semicolon = uriBC.indexOf(';', semicolon);
}
}
-
-
+
+
/**
* Look for SSL session ID if required. Only look for SSL Session ID if it
* is the only tracking method enabled.
request.setRequestedSessionSSL(true);
}
}
-
-
+
+
/**
* Parse session id in URL.
*/
Context context = (Context) request.getMappingData().context;
if (context != null && !context.getServletContext()
.getEffectiveSessionTrackingModes().contains(
- SessionTrackingMode.COOKIE))
+ SessionTrackingMode.COOKIE)) {
return;
-
+ }
+
// Parse session id from cookies
Cookies serverCookies = req.getCookies();
int count = serverCookies.getCookieCount();
- if (count <= 0)
+ if (count <= 0) {
return;
+ }
String sessionCookieName =
ApplicationSessionCookieConfig.getSessionCookieName(context);
(scookie.getValue().toString());
request.setRequestedSessionCookie(true);
request.setRequestedSessionURL(false);
- if (log.isDebugEnabled())
+ if (log.isDebugEnabled()) {
log.debug(" Requested cookie session id is " +
request.getRequestedSessionId());
+ }
} else {
if (!request.isRequestedSessionIdValid()) {
// Replace the session id until one is valid
/**
* Character conversion of the URI.
*/
- protected void convertURI(MessageBytes uri, Request request)
+ protected void convertURI(MessageBytes uri, Request request)
throws Exception {
ByteChunk bc = uri.getByteChunk();
if (conv != null) {
try {
conv.convert(bc, cc, cc.getBuffer().length - cc.getEnd());
- uri.setChars(cc.getBuffer(), cc.getStart(),
+ uri.setChars(cc.getBuffer(), cc.getStart(),
cc.getLength());
return;
} catch (IOException e) {
protected void convertMB(MessageBytes mb) {
// This is of course only meaningful for bytes
- if (mb.getType() != MessageBytes.T_BYTES)
+ if (mb.getType() != MessageBytes.T_BYTES) {
return;
-
+ }
+
ByteChunk bc = mb.getByteChunk();
CharChunk cc = mb.getCharChunk();
int length = bc.getLength();
* This method normalizes "\", "//", "/./" and "/../". This method will
* return false when trying to go above the root, or if the URI contains
* a null byte.
- *
+ *
* @param uriMB URI to be normalized
*/
public static boolean normalize(MessageBytes uriMB) {
int end = uriBC.getEnd();
// An empty URL is not acceptable
- if (start == end)
+ if (start == end) {
return false;
+ }
// URL * is acceptable
- if ((end - start == 1) && b[start] == (byte) '*')
- return true;
+ if ((end - start == 1) && b[start] == (byte) '*') {
+ return true;
+ }
int pos = 0;
int index = 0;
// Note: It is possible to extend the URI by 1 without any side effect
// as the next character is a non-significant WS.
if (((end - start) >= 2) && (b[end - 1] == (byte) '.')) {
- if ((b[end - 2] == (byte) '/')
- || ((b[end - 2] == (byte) '.')
+ if ((b[end - 2] == (byte) '/')
+ || ((b[end - 2] == (byte) '.')
&& (b[end - 3] == (byte) '/'))) {
b[end] = (byte) '/';
end++;
// Resolve occurrences of "/./" in the normalized path
while (true) {
index = uriBC.indexOf("/./", 0, 3, index);
- if (index < 0)
+ if (index < 0) {
break;
- copyBytes(b, start + index, start + index + 2,
+ }
+ copyBytes(b, start + index, start + index + 2,
end - start - index - 2);
end = end - 2;
uriBC.setEnd(end);
// Resolve occurrences of "/../" in the normalized path
while (true) {
index = uriBC.indexOf("/../", 0, 4, index);
- if (index < 0)
+ if (index < 0) {
break;
+ }
// Prevent from going outside our context
- if (index == 0)
+ if (index == 0) {
return false;
+ }
int index2 = -1;
for (pos = start + index - 1; (pos >= 0) && (index2 < 0); pos --) {
if (b[pos] == (byte) '/') {
* Check that the URI is normalized following character decoding.
* <p>
* This method checks for "\", 0, "//", "/./" and "/../". This method will
- * return false if sequences that are supposed to be normalized are still
+ * return false if sequences that are supposed to be normalized are still
* present in the URI.
- *
+ *
* @param uriMB URI to be checked (should be chars)
*/
public static boolean checkNormalize(MessageBytes uriMB) {
// Check for ending with "/." or "/.."
if (((end - start) >= 2) && (c[end - 1] == '.')) {
- if ((c[end - 2] == '/')
- || ((c[end - 2] == '.')
+ if ((c[end - 2] == '/')
+ || ((c[end - 2] == '.')
&& (c[end - 3] == '/'))) {
return false;
}
/**
- * Copy an array of bytes to a different position. Used during
+ * Copy an array of bytes to a different position. Used during
* normalization.
*/
protected static void copyBytes(byte[] b, int dest, int src, int len) {
public void testBug49528() throws Exception {
// Setup Tomcat instance
Tomcat tomcat = getTomcatInstance();
-
+
// Must have a real docBase - just use temp
- Context ctx =
+ Context ctx =
tomcat.addContext("", System.getProperty("java.io.tmpdir"));
Bug49528Servlet servlet = new Bug49528Servlet();
-
+
Wrapper wrapper = Tomcat.addServlet(ctx, "servlet", servlet);
wrapper.setAsyncSupported(true);
ctx.addServletMapping("/", "servlet");
-
+
TesterAccessLogValve alv = new TesterAccessLogValve();
ctx.getPipeline().addValve(alv);
-
+
tomcat.start();
-
+
// Call the servlet once
ByteChunk bc = getUrl("http://localhost:" + getPort() + "/");
assertEquals("OK", bc.toString());
public void testBug49567() throws Exception {
// Setup Tomcat instance
Tomcat tomcat = getTomcatInstance();
-
+
// Must have a real docBase - just use temp
- Context ctx =
+ Context ctx =
tomcat.addContext("", System.getProperty("java.io.tmpdir"));
Bug49567Servlet servlet = new Bug49567Servlet();
-
+
Wrapper wrapper = Tomcat.addServlet(ctx, "servlet", servlet);
wrapper.setAsyncSupported(true);
ctx.addServletMapping("/", "servlet");
-
+
TesterAccessLogValve alv = new TesterAccessLogValve();
ctx.getPipeline().addValve(alv);
-
+
tomcat.start();
-
+
// Call the servlet once
ByteChunk bc = getUrl("http://localhost:" + getPort() + "/");
assertEquals("OK", bc.toString());
public void testAsyncStartNoComplete() throws Exception {
// Setup Tomcat instance
Tomcat tomcat = getTomcatInstance();
-
+
// Minimise pauses during test
tomcat.getConnector().setAttribute(
"connectionTimeout", Integer.valueOf(3000));
-
+
// Must have a real docBase - just use temp
- Context ctx =
+ Context ctx =
tomcat.addContext("", System.getProperty("java.io.tmpdir"));
AsyncStartNoCompleteServlet servlet =
new AsyncStartNoCompleteServlet();
-
+
Wrapper wrapper = Tomcat.addServlet(ctx, "servlet", servlet);
wrapper.setAsyncSupported(true);
ctx.addServletMapping("/", "servlet");
-
+
TesterAccessLogValve alv = new TesterAccessLogValve();
ctx.getPipeline().addValve(alv);
-
+
tomcat.start();
-
+
// Call the servlet the first time
ByteChunk bc1 = getUrl("http://localhost:" + getPort() +
"/?echo=run1");
ByteChunk bc2 = getUrl("http://localhost:" + getPort() +
"/?echo=run2");
assertEquals("OK-run2", bc2.toString());
-
+
// Check the access log
validateAccessLog(alv, 2, 200,
AsyncStartNoCompleteServlet.ASYNC_TIMEOUT,
public void testAsyncStartWithComplete() throws Exception {
// Setup Tomcat instance
Tomcat tomcat = getTomcatInstance();
-
+
// Must have a real docBase - just use temp
- Context ctx =
+ Context ctx =
tomcat.addContext("", System.getProperty("java.io.tmpdir"));
AsyncStartWithCompleteServlet servlet =
new AsyncStartWithCompleteServlet();
-
+
Wrapper wrapper = Tomcat.addServlet(ctx, "servlet", servlet);
wrapper.setAsyncSupported(true);
ctx.addServletMapping("/", "servlet");
-
+
TesterAccessLogValve alv = new TesterAccessLogValve();
ctx.getPipeline().addValve(alv);
-
+
tomcat.start();
-
+
// Call the servlet once
ByteChunk bc = getUrl("http://localhost:" + getPort() + "/");
assertEquals("OK", bc.toString());
// Check the access log
validateAccessLog(alv, 1, 200, 0, REQUEST_TIME);
}
-
+
/*
* NOTE: This servlet is only intended to be used in single-threaded tests.
*/
private static class Bug49528Servlet extends HttpServlet {
private static final long serialVersionUID = 1L;
-
+
private volatile boolean done = false;
-
+
private StringBuilder result;
-
+
public static final long THREAD_SLEEP_TIME = 1000;
public String getResult() {
protected void doGet(final HttpServletRequest req,
final HttpServletResponse resp)
throws ServletException, IOException {
-
+
result = new StringBuilder();
result.append('1');
result.append(req.isAsyncStarted());
req.startAsync().setTimeout(10000);
result.append('2');
result.append(req.isAsyncStarted());
-
+
req.getAsyncContext().start(new Runnable() {
@Override
public void run() {
private static class Bug49567Servlet extends HttpServlet {
private static final long serialVersionUID = 1L;
-
+
private volatile boolean done = false;
-
+
private StringBuilder result;
-
+
public static final long THREAD_SLEEP_TIME = 1000;
public String getResult() {
protected void doGet(final HttpServletRequest req,
final HttpServletResponse resp)
throws ServletException, IOException {
-
+
result = new StringBuilder();
result.append('1');
result.append(req.isAsyncStarted());
req.startAsync();
result.append('2');
result.append(req.isAsyncStarted());
-
+
req.getAsyncContext().start(new Runnable() {
@Override
public void run() {
req.getMethod();
}
}
-
+
private static class AsyncStartNoCompleteServlet extends HttpServlet {
public static final long ASYNC_TIMEOUT = 1000;
-
+
private static final long serialVersionUID = 1L;
-
+
@Override
protected void doGet(final HttpServletRequest req,
final HttpServletResponse resp)
throws ServletException, IOException {
-
+
String echo = req.getParameter("echo");
AsyncContext actxt = req.startAsync();
resp.setContentType("text/plain");
private static class AsyncStartWithCompleteServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
-
+
@Override
protected void doGet(final HttpServletRequest req,
final HttpServletResponse resp)
throws ServletException, IOException {
-
+
AsyncContext actxt = req.startAsync();
actxt.setTimeout(3000);
resp.setContentType("text/plain");
throws Exception {
// Setup Tomcat instance
Tomcat tomcat = getTomcatInstance();
-
+
// Must have a real docBase - just use temp
File docBase = new File(System.getProperty("java.io.tmpdir"));
-
+
// Create the folder that will trigger the redirect
File foo = new File(docBase, "async");
addDeleteOnTearDown(foo);
if (!foo.mkdirs() && !foo.isDirectory()) {
fail("Unable to create async directory in docBase");
}
-
+
Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
TimeoutServlet timeout =
TesterAccessLogValve alv = new TesterAccessLogValve();
ctx.getPipeline().addValve(alv);
-
+
tomcat.start();
ByteChunk res = new ByteChunk();
try {
REQUEST_TIME);
}
}
-
+
private static class TimeoutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
- private boolean completeOnTimeout;
- private String dispatchUrl;
+ private final boolean completeOnTimeout;
+ private final String dispatchUrl;
public static final long ASYNC_TIMEOUT = 3000;
this.completeOnTimeout = completeOnTimeout;
this.dispatchUrl = dispatchUrl;
}
-
+
@Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (req.isAsyncSupported()) {
resp.getWriter().print("TimeoutServletGet-");
final AsyncContext ac = req.startAsync();
ac.setTimeout(ASYNC_TIMEOUT);
-
+
ac.addListener(new TrackingListener(
false, completeOnTimeout, dispatchUrl));
- } else
+ } else {
resp.getWriter().print("FAIL: Async unsupported");
+ }
}
}
public void testDispatchWithThreadMultiple() throws Exception {
doTestDispatch(5, true);
}
-
+
private void doTestDispatch(int iter, boolean useThread) throws Exception {
// Setup Tomcat instance
Tomcat tomcat = getTomcatInstance();
-
+
// Must have a real docBase - just use temp
File docBase = new File(System.getProperty("java.io.tmpdir"));
-
+
Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
DispatchingServlet dispatch = new DispatchingServlet(false, false);
TesterAccessLogValve alv = new TesterAccessLogValve();
ctx.getPipeline().addValve(alv);
-
+
tomcat.start();
-
+
StringBuilder url = new StringBuilder(48);
url.append("http://localhost:");
url.append(getPort());
url.append("&useThread=y");
}
ByteChunk res = getUrl(url.toString());
-
+
StringBuilder expected = new StringBuilder("requestInitialized-");
int loop = iter;
while (loop > 0) {
expected.append("NonAsyncServletGet-");
expected.append("requestDestroyed");
assertEquals(expected.toString(), res.toString());
-
+
// Check the access log
validateAccessLog(alv, 1, 200, 0, REQUEST_TIME);
}
-
+
private static class DispatchingServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final String ITER_PARAM = "iter";
private boolean addTrackingListener = false;
private boolean completeOnError = false;
-
+
public DispatchingServlet(boolean addTrackingListener,
boolean completeOnError) {
this.addTrackingListener = addTrackingListener;
this.completeOnError = completeOnError;
}
-
+
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
final AsyncContext ctxt = req.startAsync();
if (addTrackingListener) {
TrackingListener listener =
- new TrackingListener(completeOnError, true, null);
+ new TrackingListener(completeOnError, true, null);
ctxt.addListener(listener);
}
Runnable run = new Runnable() {
public void testListeners() throws Exception {
// Setup Tomcat instance
Tomcat tomcat = getTomcatInstance();
-
+
// Must have a real docBase - just use temp
File docBase = new File(System.getProperty("java.io.tmpdir"));
-
+
Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
TrackingServlet tracking = new TrackingServlet();
TesterAccessLogValve alv = new TesterAccessLogValve();
ctx.getPipeline().addValve(alv);
-
+
tomcat.start();
-
+
StringBuilder url = new StringBuilder(48);
url.append("http://localhost:");
url.append(getPort());
url.append("/stage1");
ByteChunk res = getUrl(url.toString());
-
+
assertEquals(
"DispatchingServletGet-DispatchingServletGet-onStartAsync-" +
"TimeoutServletGet-onStartAsync-onTimeout-onComplete-",
private static class TrackingServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
-
+
private static volatile boolean first = true;
-
+
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
TrackingServlet.first = false;
final AsyncContext ctxt = req.startAsync();
- TrackingListener listener = new TrackingListener(false, true, null);
+ TrackingListener listener = new TrackingListener(false, true, null);
ctxt.addListener(listener);
ctxt.setTimeout(3000);
}
private static class TrackingListener implements AsyncListener {
-
- private boolean completeOnError;
- private boolean completeOnTimeout;
- private String dispatchUrl;
-
+
+ private final boolean completeOnError;
+ private final boolean completeOnTimeout;
+ private final String dispatchUrl;
+
public TrackingListener(boolean completeOnError,
boolean completeOnTimeout, String dispatchUrl) {
this.completeOnError = completeOnError;
@Override
public void onComplete(AsyncEvent event) throws IOException {
- ServletResponse resp = event.getAsyncContext().getResponse();
+ ServletResponse resp = event.getAsyncContext().getResponse();
resp.getWriter().write("onComplete-");
resp.flushBuffer();
}
@Override
public void onTimeout(AsyncEvent event) throws IOException {
- ServletResponse resp = event.getAsyncContext().getResponse();
+ ServletResponse resp = event.getAsyncContext().getResponse();
resp.getWriter().write("onTimeout-");
resp.flushBuffer();
if (completeOnTimeout){
@Override
public void onError(AsyncEvent event) throws IOException {
- ServletResponse resp = event.getAsyncContext().getResponse();
+ ServletResponse resp = event.getAsyncContext().getResponse();
resp.getWriter().write("onError-");
resp.flushBuffer();
if (completeOnError) {
@Override
public void onStartAsync(AsyncEvent event) throws IOException {
- ServletResponse resp = event.getAsyncContext().getResponse();
+ ServletResponse resp = event.getAsyncContext().getResponse();
resp.getWriter().write("onStartAsync-");
resp.flushBuffer();
}
}
-
+
public static class TrackingRequestListener
implements ServletRequestListener {
throws Exception {
doTestDispatchError(5, true, true);
}
-
+
private void doTestDispatchError(int iter, boolean useThread,
boolean completeOnError)
throws Exception {
// Setup Tomcat instance
Tomcat tomcat = getTomcatInstance();
-
+
// Must have a real docBase - just use temp
File docBase = new File(System.getProperty("java.io.tmpdir"));
-
+
Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
DispatchingServlet dispatch =
TesterAccessLogValve alv = new TesterAccessLogValve();
ctx.getPipeline().addValve(alv);
-
+
tomcat.start();
-
+
StringBuilder url = new StringBuilder(48);
url.append("http://localhost:");
url.append(getPort());
url.append("&useThread=y");
}
ByteChunk res = getUrl(url.toString());
-
+
StringBuilder expected = new StringBuilder("requestInitialized-");
int loop = iter;
while (loop > 0) {
}
expected.append("ErrorServletGet-onError-onComplete-requestDestroyed");
assertEquals(expected.toString(), res.toString());
-
+
// Check the access log
validateAccessLog(alv, 1, 200, 0, REQUEST_TIME);
}
-
+
private static class ErrorServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public ErrorServlet(boolean flush) {
this.flush = flush;
}
-
+
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
public void testBug50352() throws Exception {
// Setup Tomcat instance
Tomcat tomcat = getTomcatInstance();
-
+
// Must have a real docBase - just use temp
File docBase = new File(System.getProperty("java.io.tmpdir"));
-
+
Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
AsyncStartRunnable servlet = new AsyncStartRunnable();
TesterAccessLogValve alv = new TesterAccessLogValve();
ctx.getPipeline().addValve(alv);
-
+
tomcat.start();
-
+
ByteChunk res = getUrl("http://localhost:" + getPort() + "/");
-
+
assertEquals("Runnable-onComplete-", res.toString());
// Check the access log
validateAccessLog(alv, 1, 200, AsyncStartRunnable.THREAD_SLEEP_TIME,
AsyncStartRunnable.THREAD_SLEEP_TIME + REQUEST_TIME);
}
-
+
private static final class AsyncStartRunnable extends HttpServlet {
-
+
private static final long serialVersionUID = 1L;
public static final long THREAD_SLEEP_TIME = 3000;
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
-
+
final AsyncContext asyncContext =
request.startAsync(request, response);
public void testBug50753() throws Exception {
// Setup Tomcat instance
Tomcat tomcat = getTomcatInstance();
-
+
// Must have a real docBase - just use temp
- Context ctx =
+ Context ctx =
tomcat.addContext("", System.getProperty("java.io.tmpdir"));
Bug50753Servlet servlet = new Bug50753Servlet();
-
+
Wrapper wrapper = Tomcat.addServlet(ctx, "servlet", servlet);
wrapper.setAsyncSupported(true);
ctx.addServletMapping("/", "servlet");
-
+
TesterAccessLogValve alv = new TesterAccessLogValve();
ctx.getPipeline().addValve(alv);
-
+
tomcat.start();
-
+
// Call the servlet once
Map<String,List<String>> headers =
new LinkedHashMap<String,List<String>>();
assertNotNull(testHeader);
assertEquals(1, testHeader.size());
assertEquals("xyz",testHeader.get(0));
-
+
// Check the access log
validateAccessLog(alv, 1, 200, Bug50753Servlet.THREAD_SLEEP_TIME,
Bug50753Servlet.THREAD_SLEEP_TIME + REQUEST_TIME);
protected void doGet(HttpServletRequest req,
final HttpServletResponse resp)
throws ServletException, IOException {
- final AsyncContext ctx = req.startAsync();
- ctx.start(new Runnable() {
+ final AsyncContext ctx = req.startAsync();
+ ctx.start(new Runnable() {
@Override
- public void run() {
- try {
- Thread.sleep(THREAD_SLEEP_TIME);
- resp.setHeader("A", "xyz");
- resp.setContentType("text/plain");
- resp.setContentLength("OK".getBytes().length);
- resp.getWriter().print("OK");
- ctx.complete();
- } catch (Exception e) {
+ public void run() {
+ try {
+ Thread.sleep(THREAD_SLEEP_TIME);
+ resp.setHeader("A", "xyz");
+ resp.setContentType("text/plain");
+ resp.setContentLength("OK".getBytes().length);
+ resp.getWriter().print("OK");
+ ctx.complete();
+ } catch (Exception e) {
e.printStackTrace();
- }
- }
- });
+ }
+ }
+ });
}
}
public void testErrorHandling() throws Exception {
// Setup Tomcat instance
Tomcat tomcat = getTomcatInstance();
-
+
// Must have a real docBase - just use temp
File docBase = new File(System.getProperty("java.io.tmpdir"));
-
+
Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
ErrorServlet error = new ErrorServlet(false);
TesterAccessLogValve alv = new TesterAccessLogValve();
ctx.getPipeline().addValve(alv);
-
+
tomcat.start();
-
+
StringBuilder url = new StringBuilder(48);
url.append("http://localhost:");
url.append(getPort());
url.append("/error");
-
+
int rc = getUrl(url.toString(), new ByteChunk(), null);
-
+
assertEquals(500, rc);
-
+
// Without this test may complete before access log has a chance to log
// the request
Thread.sleep(REQUEST_TIME);
-
+
// Check the access log
validateAccessLog(alv, 1, 500, 0, REQUEST_TIME);
}
private void validateAccessLog(TesterAccessLogValve alv, int count,
int status, long minTime, long maxTime) throws Exception {
List<Entry> entries = alv.getEntries();
-
+
// Wait (but not too long) until all expected entries appear (access log
// entry will be made after response has been returned to user)
for (int i = 0; i < 10 && entries.size() < count; i++) {
Thread.sleep(100);
}
-
+
assertEquals(count, entries.size());
for (int j = 0; j < count; j++) {
Entry entry = entries.get(j);
public void testCommitOnComplete() throws Exception {
// Setup Tomcat instance
Tomcat tomcat = getTomcatInstance();
-
+
// Must have a real docBase - just use temp
File docBase = new File(System.getProperty("java.io.tmpdir"));
-
+
Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
AsyncStatusServlet asyncStatusServlet =
TesterAccessLogValve alv = new TesterAccessLogValve();
ctx.getPipeline().addValve(alv);
-
+
tomcat.start();
-
+
StringBuilder url = new StringBuilder(48);
url.append("http://localhost:");
url.append(getPort());
url.append("/asyncStatusServlet");
-
+
int rc = getUrl(url.toString(), new ByteChunk(), null);
-
+
assertEquals(HttpServletResponse.SC_BAD_REQUEST, rc);
-
+
// Without this test may complete before access log has a chance to log
// the request
Thread.sleep(REQUEST_TIME);
-
+
// Check the access log
validateAccessLog(alv, 1, HttpServletResponse.SC_BAD_REQUEST, 0,
REQUEST_TIME);
public AsyncStatusServlet(int status) {
this.status = status;
}
-
+
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
-
+
AsyncContext actxt = req.startAsync();
resp.setStatus(status);
actxt.complete();
public void testBug51197() throws Exception {
// Setup Tomcat instance
Tomcat tomcat = getTomcatInstance();
-
+
// Must have a real docBase - just use temp
File docBase = new File(System.getProperty("java.io.tmpdir"));
-
+
Context ctx = tomcat.addContext("", docBase.getAbsolutePath());
AsyncErrorServlet asyncErrorServlet =
TesterAccessLogValve alv = new TesterAccessLogValve();
ctx.getPipeline().addValve(alv);
-
+
tomcat.start();
-
+
StringBuilder url = new StringBuilder(48);
url.append("http://localhost:");
url.append(getPort());
url.append("/asyncErrorServlet");
-
+
int rc = getUrl(url.toString(), new ByteChunk(), null);
-
+
assertEquals(HttpServletResponse.SC_BAD_REQUEST, rc);
-
+
// Without this test may complete before access log has a chance to log
// the request
Thread.sleep(REQUEST_TIME);
-
+
// Check the access log
validateAccessLog(alv, 1, HttpServletResponse.SC_BAD_REQUEST, TIMEOUT,
TIMEOUT + TIMEOUT_MARGIN + REQUEST_TIME);
public AsyncErrorServlet(int status) {
this.status = status;
}
-
+
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
-
+
final AsyncContext actxt = req.startAsync();
actxt.setTimeout(TIMEOUT);
actxt.start(new Runnable() {