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: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to