Hi,
I think I found a problem in the way Tomcat parses the POST Http Request. It
might be related to issues n°40860, 31523 and 42347 submitted to bugzilla
<https://issues.apache.org/bugzilla>.
I am running on a JBoss 4.0.4 GA server on a windows platform. I know it uses a
5.5.x tomcat, but I don't know exactly which version.
Symptoms :
When I submit a POST request, sometimes one parameter get lost. I can tell
using Eclipse's TCP/IP proxy that the value was submitted in the request.
Analysis:
The POST request looks like that and is 15kB long:
<<
-----------------------------7de35e1c190e9e
Content-Disposition: form-data; name="autoScroll"
0,0
-----------------------------7de35e1c190e9e
Content-Disposition: form-data; name="principal:arbre::focused"
false
-----------------------------7de35e1c190e9e
Content-Disposition: form-data; name="principal:arbre::expandedNodes"
>>
Using remote debugging, I found that a MultipartStream object analyses the
request using a 4KB buffer; this buffer is fed by a 8kB buffer used by a
ByteChunk object.
The pattern "-----------------------------7de35e1c190e9e" is called 'boundary'.
and is repeated for each field. I noted that the hex part of the boundary may
not be the same length from one POST to another, I think that is why the
problem does not always occur.
when MultipartStream arrives at the end of its buffer and there is not enough
bytes left to read the next boundary, it moves the few unread bytes to the
beginning of the buffer, then loads the next chunk of data from the ByteChunk
object (see MultipartStream$ItemInputStream.makeAvailable())
ex : the buffer ends with "false\n\r----". These bytes are moved to the start
of the buffer, so that the buffer now starts with
"false\n\r-----------------------------7de35e1c190e9e[...]" and the code can
now read the boundary.
In this example, after parsing the first 4096 bytes, we now parse the
(4096-11)=4085 next bytes (because we still have the 11 last bytes from the
first chunk.
At the end of the second chunk : the buffer now ends with something like
"0,0\n\r--" (7 bytes) and we need the next chunk of data to read the next
boundary. Tomcats asks the ByteChunk object for the next (4096-7) bytes, but
there are only 11 available (8kB-4kB-4085 bytes). So MultipartStream only sees
a 18 bytes-long data, which is not enough to read the boundary. As a
consequence, the field is skipped and is value is lost.
So the problem, I think, relies in the ByteChunk.substract method, when the
available bytes in the buffer are not enough to fill the MultipartStream need.
This method should attempt to read the next chunk of data if available.
Solution :
Here is the modification I suggest in the code:
<<
public int substract( byte src[], int off, int len )
throws IOException {
if ((end - start) == 0) {
if (in == null)
return -1;
int n = in.realReadBytes( buff, 0, buff.length );
if (n < 0)
return -1;
}
int n = len;
if (len > getLength()) {
n = getLength();
}
System.arraycopy(buff, start, src, off, n);
start += n;
// Start of modification - add
if (n<len) {
// not enough data in the buffer. We want more!
int n2 = substract(src, off+n, len-n);
if (n2>0) {
return n+n2;
}
}
// End of modification
return n;
}
>>
below is a part of the stack trace to the point where I located the problem:
Daemon Thread [http-0.0.0.0-8080-5] (Suspended (breakpoint at line 404 in
ByteChunk))
ByteChunk.substract(byte[], int, int) line: 404
InputBuffer.read(byte[], int, int) line: 299
CoyoteInputStream.read(byte[], int, int) line: 192
MultipartStream$ItemInputStream.makeAvailable() line: 959
MultipartStream$ItemInputStream.read(byte[], int, int) line: 887
MultipartStream$ItemInputStream(InputStream).read(byte[]) line: 89
Streams.copy(InputStream, OutputStream, boolean, byte[]) line: 94
Streams.copy(InputStream, OutputStream, boolean) line: 64
MultipartStream.readBodyData(OutputStream) line: 593
MultipartStream.discardBodyData() line: 619
MultipartStream.skipPreamble() line: 638
FileUploadBase$FileItemIteratorImpl.findNextItem() line: 844
FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase,
RequestContext) line: 825
DiskFileUpload(FileUploadBase).getItemIterator(RequestContext) line:
323
DiskFileUpload(FileUploadBase).parseRequest(RequestContext) line: 341
DiskFileUpload(FileUploadBase).parseRequest(HttpServletRequest) line:
302
MultipartRequestWrapper.parseRequest() line: 85
MultipartRequestWrapper.getParameter(String) line: 181
RequestParameterMap.getAttribute(String) line: 42
Can anybody tell me if this is a known problem? Maybe it has been solved some
other way. I know Tomcat 5.5 if rather old...
Thanks,
Didier DUQUENNOY
Consultez nos sites internet :
http://www.sofaxis.com
http://www.sofcap-sofcah.com
Sofaxis disclaimer : http://www.sofaxis.com/disclaimer-1.html
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]