tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Filip Hanik - Dev Lists <devli...@hanik.com>
Subject Re: Comet processor blocks if chunk includes final CRLF
Date Wed, 12 Dec 2007 17:41:33 GMT
hi Chris, Paul Dumais just posted the same issue. I've been bit by it 
too, I'm gonna review the spec again, and see if and how we can make 
adjustments to the code

Filip

Chris Pettitt wrote:
> Hello,
>
> I'm using Tomcat 6.0.14 and its CometProcessor to create a long
> running connection between an HTTP client and my server. The client
> posts requests to the server using chunked transfer encoding (each
> chunk is a complete XML request processed by the servlet).
>
> I'm using a servlet that is heavily derived from the
> example[1] on Tomcat's website. I've found that this implementation
> blocks the worker thread - which I would not expect - if the client
> sends a complete chunk and then wait some time before sending the next
> chunk.
>
> I'm using the W3C specification[2] of a chunk:
>
>     chunk-size CRLF
>     chunk-data CRLF
>
> Surprisingly, if I send a chunk that does not include the last CRLF,
> then the CometProcessor works correctly and does not block.
>
> My analysis of the blocking condition follows:
>
> ChunkedInputFilter.doRead() reads everything in the chunk except the
> last CRLF. It defers reading of the last CRLF until the next read()
> call by setting needCRLFParse to true at line 157. Calling
> ChunkedInputFilter.available() before receiving new data will
> therefore return 2, because the CRLF at the end of the chunk have not
> yet been read.
>
> The implementation of
> org.apache.catalina.connector.InputBuffer.available() always delegates
> to coyoteRequest.getAvailable() (in my environment, state is not
> BYTE_STATE or CHAR_STATE during this call).
>
>     // org.apache.catalina.connector.InputBuffer, ~ line 260
>     public int available() {
>         int available = 0;
>         if (state == BYTE_STATE) {
>             available = bb.getLength();
>         } else if (state == CHAR_STATE) {
>             available = cb.getLength();
>         }
>         if (available == 0) {
>             coyoteRequest.action(ActionCode.ACTION_AVAILABLE, null);
>             available = (coyoteRequest.getAvailable() > 0) ? 1 : 0; //
>  <--- delegates here
>         }
>         return available;
>     }
>
> The value that is returned by coyoteRequest.getAvailable() is set by
> Http11NioProcessor (see processing of ActionCode.ACTION_AVAILABLE at
> line 1218) to the value returned by its inputBuffer.available(). This
> method delegates to the ChunkedInputFilter, which returns 2,
> indicating two available bytes (CR, LF). Ultimately the
> InputBuffer.available() method above returns 1, because
> coyoteRequest.getAvailable() returned a non-zero value.
>
> Because in.available() in the attached servlet is non-zero, the
> servlet calls read() again. This time the call blocks, because when it
> calls read ChunkedInputFilter.doRead() finishes reading the CRLF it
> has in its buffer, it calls parseChunkHeader which makes a blocking
> call to readBytes().
>
> Is this misuse of CometProcessor? Is there best practice guidance
> for managing long running connections with multiple requests with
> Tomcat?
>
> Thanks,
> Chris
>
> [1]: http://tomcat.apache.org/tomcat-6.0-doc/aio.html
> [2]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1
>
> ---------------------------------------------------------------------
> To start a new topic, e-mail: users@tomcat.apache.org
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>
>
>
>   


---------------------------------------------------------------------
To start a new topic, e-mail: users@tomcat.apache.org
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Mime
View raw message