Author: markt
Date: Wed Apr 24 11:43:30 2013
New Revision: 1471372
URL: http://svn.apache.org/r1471372
Log:
Protect against AsyncListeners that throw RuntimeExceptions (they should
normally only throw IOExceptions).
Includes a test case.
Modified:
tomcat/tc7.0.x/trunk/ (props changed)
tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/AsyncContextImpl.java
tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestAsyncContextImpl.java
tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
Propchange: tomcat/tc7.0.x/trunk/
------------------------------------------------------------------------------
Merged /tomcat/trunk:r1471371
Modified:
tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/AsyncContextImpl.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/AsyncContextImpl.java?rev=1471372&r1=1471371&r2=1471372&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/AsyncContextImpl.java
(original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/AsyncContextImpl.java
Wed Apr 24 11:43:30 2013
@@ -117,9 +117,10 @@ public class AsyncContextImpl implements
for (AsyncListenerWrapper listener : listenersCopy) {
try {
listener.fireOnComplete(event);
- } catch (IOException ioe) {
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
log.warn("onComplete() failed for listener of type [" +
- listener.getClass().getName() + "]", ioe);
+ listener.getClass().getName() + "]", t);
}
}
} finally {
@@ -148,9 +149,10 @@ public class AsyncContextImpl implements
for (AsyncListenerWrapper listener : listenersCopy) {
try {
listener.fireOnTimeout(event);
- } catch (IOException ioe) {
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
log.warn("onTimeout() failed for listener of type [" +
- listener.getClass().getName() + "]", ioe);
+ listener.getClass().getName() + "]", t);
}
}
request.getCoyoteRequest().action(
@@ -328,9 +330,10 @@ public class AsyncContextImpl implements
for (AsyncListenerWrapper listener : listenersCopy) {
try {
listener.fireOnStartAsync(event);
- } catch (IOException ioe) {
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
log.warn("onStartAsync() failed for listener of type [" +
- listener.getClass().getName() + "]", ioe);
+ listener.getClass().getName() + "]", t);
}
}
listeners.clear();
@@ -393,9 +396,10 @@ public class AsyncContextImpl implements
for (AsyncListenerWrapper listener : listenersCopy) {
try {
listener.fireOnError(errorEvent);
- } catch (IOException ioe) {
+ } catch (Throwable t2) {
+ ExceptionUtils.handleThrowable(t);
log.warn("onError() failed for listener of type [" +
- listener.getClass().getName() + "]", ioe);
+ listener.getClass().getName() + "]", t2);
}
}
}
Modified:
tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestAsyncContextImpl.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestAsyncContextImpl.java?rev=1471372&r1=1471371&r2=1471372&view=diff
==============================================================================
---
tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestAsyncContextImpl.java
(original)
+++
tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestAsyncContextImpl.java
Wed Apr 24 11:43:30 2013
@@ -1189,7 +1189,7 @@ public class TestAsyncContextImpl extend
private static final long serialVersionUID = 1L;
- private int status = 200;
+ private int status;
public AsyncStatusServlet(int status) {
this.status = status;
@@ -1629,4 +1629,108 @@ public class TestAsyncContextImpl extend
}
}
}
+
+ @Test
+ public void testBug54178() 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());
+
+ Bug54178ServletA bug54178ServletA = new Bug54178ServletA();
+ Wrapper wrapper =
+ Tomcat.addServlet(ctx, "bug54178ServletA", bug54178ServletA);
+ wrapper.setAsyncSupported(true);
+ ctx.addServletMapping("/bug54178ServletA", "bug54178ServletA");
+
+ Bug54178ServletB bug54178ServletB = new Bug54178ServletB();
+ Tomcat.addServlet(ctx, "bug54178ServletB", bug54178ServletB);
+ ctx.addServletMapping("/bug54178ServletB", "bug54178ServletB");
+
+ tomcat.start();
+
+ ByteChunk body = new ByteChunk();
+ int rc = -1;
+
+ try {
+ rc = getUrl("http://localhost:" + getPort() + "/bug54178ServletA?"
+
+ Bug54178ServletA.PARAM_NAME + "=bar",
+ body, null);
+ } catch (IOException ioe) {
+ // This may happen if test fails. Output the exception in case it
is
+ // useful and let asserts handle the failure
+ ioe.printStackTrace();
+ }
+
+ assertEquals(HttpServletResponse.SC_OK, rc);
+
+ body.recycle();
+
+ rc = getUrl("http://localhost:" + getPort() + "/bug54178ServletB",
+ body, null);
+
+ assertEquals(HttpServletResponse.SC_OK, rc);
+ assertEquals("OK", body.toString());
+ }
+
+ private static class Bug54178ServletA extends HttpServlet {
+
+ public static final String PARAM_NAME = "foo";
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+
+ req.getParameter(PARAM_NAME);
+ AsyncContext actxt = req.startAsync();
+ actxt.addListener(new Bug54178AsyncListener());
+ actxt.complete();
+ }
+ }
+
+ private static class Bug54178ServletB extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+
+ resp.setContentType("text/plain");
+ PrintWriter pw = resp.getWriter();
+ String result = req.getParameter(Bug54178ServletA.PARAM_NAME);
+ if (result == null) {
+ pw.write("OK");
+ } else {
+ pw.write("FAIL");
+ }
+ }
+ }
+
+ private static class Bug54178AsyncListener implements AsyncListener {
+
+ @Override
+ public void onComplete(AsyncEvent event) throws IOException {
+ throw new RuntimeException("Testing Bug54178");
+ }
+
+ @Override
+ public void onTimeout(AsyncEvent event) throws IOException {
+ // NO-OP
+ }
+
+ @Override
+ public void onError(AsyncEvent event) throws IOException {
+ // NO-OP
+ }
+
+ @Override
+ public void onStartAsync(AsyncEvent event) throws IOException {
+ // NO-OP
+ }
+ }
}
Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1471372&r1=1471371&r2=1471372&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Wed Apr 24 11:43:30 2013
@@ -63,6 +63,11 @@
(markt)
</update>
<fix>
+ <bug>54178</bug>: Protect against <code>AsyncListener</code>
+ implementations that throw <code>RuntimeException</code>s in response
to
+ an event. (markt)
+ </fix>
+ <fix>
<bug>54851</bug>: When scanning for web fragments, directories without
any web-fragment.xml should not impact the status of distributable
element. Patch provided by Trask Stalnaker. (violetagg)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]