Summary: | Can not get all data from InputStream in onDataAvailable | ||
---|---|---|---|
Product: | Tomcat 8 | Reporter: | Long Zou <longzou> |
Component: | Catalina | Assignee: | Tomcat Developers Mailing List <dev> |
Status: | RESOLVED FIXED | ||
Severity: | major | ||
Priority: | P2 | ||
Version: | 8.0.x-trunk | ||
Target Milestone: | ---- | ||
Hardware: | PC | ||
OS: | Mac OS X 10.4 | ||
Attachments: | TestAsyncServlet is the full code by this case. |
Description
Long Zou
2014-06-24 09:45:02 UTC
public void onDataAvailable() throws IOException { byte[] buf = new byte[1024]; int len = 0; try{ while ( _input.isReady() && (len = _input.read(buf)) != -1) { _bufferStream.write(buf, 0, len); } }catch(Exception ex){ logger.debug(ex.getMessage()); } } The client send 1406 bytes. But I can not get all. If I changed the buf size to 2048, I can get all of 1406 bytes. But if I send more than 2048, I can not get all again. 1. Exact version of Tomcat 8.0.x = ? 2. What connector implementation is being used (NIO, NIO2, APR, BIO) ? (See startup logs of your Tomcat, or ask on the Users mailing list) 3. The onDataAvailable() does not guarantee that _all_ data can be read. It just says that _some_ data can be read. If "isReady()" returns false then you are expected to exit from this method, and wait until "onDataAvailable()" is being called the second time. See [1]. [1] http://docs.oracle.com/javaee/7/api/javax/servlet/ReadListener.html#onDataAvailable%28%29 This works - Tomcat's WebSocket implementation is (currently) built on top of Servlet 3.1 async. There are also a number of unit tests that cover this functionality. There is insufficient information provided in this report to enable the problem to be reproduced. Please seek help on the Tomcat users mailing list and only re-open this issue if a) that discussion concludes that there is a bug here and b) you have a reproducible test case (which should be as simple as possible) to demonstrate the issue. 1. I test tomcat 8.0.5 and 8.0.8. 2. Connector is using NIO. 3. I understood the routines. Enclosing my code as below: final class SyncServiceReadListener implements ReadListener { private final AsyncContext _asyncCtx; private final ServletInputStream _input; private final HttpServletResponse _response; private final Locale _locale; private final ByteArrayOutputStream _bufferStream = new ByteArrayOutputStream(); SyncServiceReadListener(ServletInputStream input, HttpServletResponse res, AsyncContext ctx, Locale locale){ _input = input; _asyncCtx = ctx; _response = res; _locale = locale; _serviceResponse = serviceResponse; } public void onDataAvailable() throws IOException { byte[] buf = new byte[1024]; int len = 0; try{ while ( _input.isReady() && (len = _input.read(buf)) != -1) { _bufferStream.write(buf, 0, len); } }catch(Exception ex){ logger.debug(ex.getMessage()); } } public void onAllDataRead() throws IOException { try{ _bufferStream.flush(); _bufferStream.close(); }catch(Exception ex){ logger.debug(ex.getMessage()); } ///By here, the _bufferStream.toByteArray() just returned 1024 bytes. ... } public void onError(Throwable thrwbl) { if( thrwbl != null ) logger.error(thrwbl.getMessage(), thrwbl); _asyncCtx.complete(); } } Hi, I can reproduce this problem with current trunk with the provided non-blocking ByteCounter example. 1) Apply the following patch to your working copy: Index: ByteCounter.java =================================================================== --- ByteCounter.java (revision 1604977) +++ ByteCounter.java (working copy) @@ -81,7 +81,7 @@ private volatile boolean readFinished = false; private volatile long totalBytesRead = 0; - private byte[] buffer = new byte[8192]; + private byte[] buffer = new byte[1024]; private CounterListener(AsyncContext ac, ServletInputStream sis, ServletOutputStream sos) { 2. Build Tomcat and start it with default settings (NIO connector). 3. Open a TCP connection and send the following request (it contains a Request Body with 1406 bytes): POST /examples/servlets/nonblocking/bytecounter HTTP/1.1 Host: localhost Connection: keep-alive Content-Type: text/plain Content-Length: 1406 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd (remove the line breaks so that the body actually contains 1406 characters). Actual Result: HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: text/plain;charset=UTF-8 Content-Length: 28 Date: Tue, 24 Jun 2014 13:59:37 GMT Total bytes written = [1024] Expected Result: HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Content-Type: text/plain;charset=UTF-8 Content-Length: 28 Date: Tue, 24 Jun 2014 14:03:42 GMT Total bytes written = [1406] Created attachment 31748 [details]
TestAsyncServlet is the full code by this case.
Client will send below code by text/json content-type.
{
"key-0" : "AAAAAAAA",
"key-4" : "AAAAAAAA",
"deviceId" : "22C6A9AFE19D4577808FD1589ADF2AA8",
"key-8" : "AAAAAAAA",
"completed" : false,
"key-11" : "AAAAAAAA",
"key-20" : "AAAAAAAA",
"key-13" : "AAAAAAAA",
"key-22" : "AAAAAAAA",
"key-15" : "AAAAAAAA",
"key-24" : "AAAAAAAA",
"key-17" : "AAAAAAAA",
"key-1" : "AAAAAAAA",
"key-19" : "AAAAAAAA",
"key-33" : "AAAAAAAA",
"key-31" : "AAAAAAAA",
"key-35" : "AAAAAAAA",
"key-5" : "AAAAAAAA",
"sessionToken" : "O968K64KIL1KHCF3A62CSTAF00",
"key-37" : "AAAAAAAA",
"key-44" : "AAAAAAAA",
"key-28" : "AAAAAAAA",
"key-9" : "AAAAAAAA",
"key-46" : "AAAAAAAA",
"key-42" : "AAAAAAAA",
"key-48" : "AAAAAAAA",
"key-26" : "AAAAAAAA",
"key-39" : "AAAAAAAA",
"key-40" : "AAAAAAAA",
"count" : 50,
"key-2" : "AAAAAAAA",
"key-6" : "AAAAAAAA",
"key-10" : "AAAAAAAA",
"key-12" : "AAAAAAAA",
"key-21" : "AAAAAAAA",
"key-14" : "AAAAAAAA",
"key-23" : "AAAAAAAA",
"key-16" : "AAAAAAAA",
"key-30" : "AAAAAAAA",
"key-18" : "AAAAAAAA",
"key-32" : "AAAAAAAA",
"key-25" : "AAAAAAAA",
"key-3" : "AAAAAAAA",
"key-34" : "AAAAAAAA",
"key-27" : "AAAAAAAA",
"key-36" : "AAAAAAAA",
"key-29" : "AAAAAAAA",
"key-7" : "AAAAAAAA",
"key-45" : "AAAAAAAA",
"key-43" : "AAAAAAAA",
"key-41" : "AAAAAAAA",
"key-47" : "AAAAAAAA",
"key-38" : "AAAAAAAA",
"key-49" : "AAAAAAAA"
}
There are 1381 bytes.
|