Bug 57157 - out.setWriteListener in runnable of AsyncContext.start(runnable) cause response failed
Summary: out.setWriteListener in runnable of AsyncContext.start(runnable) cause respon...
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 8
Classification: Unclassified
Component: Catalina (show other bugs)
Version: 8.0.14
Hardware: PC Linux
: P2 normal (vote)
Target Milestone: ----
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-10-28 09:24 UTC by Zen Zhong
Modified: 2014-10-29 12:33 UTC (History)
1 user (show)



Attachments
related java code files (3.14 KB, application/zip)
2014-10-28 09:24 UTC, Zen Zhong
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Zen Zhong 2014-10-28 09:24:23 UTC
Created attachment 32157 [details]
related java code files

stack trace:
28-Oct-2014 11:56:26.891 SEVERE [http-nio-8080-exec-5] org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun 
 java.lang.NullPointerException
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1538)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1523)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:744)

related code:
TextReadListener
	public synchronized void onAllDataRead() throws IOException {
		logger.debug("onAllDataRead", new Exception("onAllDataRead"));
		final String text = (buf != null ? buf.toString("UTF-8") : "");
		logger.debug("onAllDataRead> text={}", text);
		HttpServletRequest req = (HttpServletRequest) asyncCtx.getRequest();
		logger.debug("onAllDataRead> uri={}, User-Agent={}, params={}", req.getRequestURI(),
				req.getHeader("User-Agent"), req.getParameterMap());
		final ServletOutputStream out = asyncCtx.getResponse().getOutputStream();
		asyncCtx.start(new Runnable() {
			@Override
			public void run() {
				try {
					logger.debug("start sleep");
					TimeUnit.SECONDS.sleep(1);
					logger.debug("sleep finished, start writing");
					WriteListener writeListener = new TextWriteListener(("test" + text).getBytes("UTF-8"), asyncCtx,
							out);
					out.setWriteListener(writeListener);
				} catch (Throwable e) {
					logger.error("impossible ex", e);
				}
			}
		});
	}

If I just invoke out.setWriteListener in onAllDataRead method (not in asyncCtx.start), then that's ok.

Detailed java code is in attachment
Comment 1 Mark Thomas 2014-10-29 12:33:03 UTC
Thanks for the report.

The NPE was triggered by some faulty error handling which has been fixed in 8.0.x for 8.0.15 onwards.

With the error handling fixed it was clear that Tomcat was not allowing calls to AsyncContext.start(Runnable) during non-blocking reads and writes. I can see no reason for that restriction - it looks like an oversight when the non-blocking IO support was added - so I have removed it. This fix has also been made in 8.0.x and will be in 8.0.15 onwards.