Missing 0-length chunk to mark the end of a response

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Missing 0-length chunk to mark the end of a response

John.E.Gregg-2
All,

Hopefully I can explain this clearly...

The short question is that my client is sometimes not getting the 0-length chunk at the end of the response from Tomcat, so my connections don't get reused.

My Tomcat server is version 7.0.81.  JDK is 1.8.0_144.  I have a Jersey client, version 2.25, connecting to it from another Tomcat server.  I noticed that inbound connections to the server are not getting reused properly.  I think the reason has to do with the fact that Tomcat is using chunked output but is not sending the 0-length chunk that signals the end of the response, even though the response is completed/successful.

My Tomcat server has 3 connectors: one plain HTTP, one SSL, and one SSL + mutual authentication (2-way SSL.)  With plain HTTP, I always get the 0-length chunk.  I verified this both with the remote debugger and TCPMon.  With the other two connectors, I don't get the 0-length chunk with the Jersey client, though I do see it with some other clients.  I can't use TCPMon with SSL, but with the same breakpoints as with non-SSL I see that there is no 0-length chunk.

Setting a breakpoint on ChunkedInputStream line 326 on the client side and printing the chunk sizes, I get this output for 2 responses over plain HTTP:

chunk size: 8192
chunk size: 1312
chunk size: 0
chunk size: 8192
chunk size: 1312
chunk size: 0

And for SSL:

chunk size: 8192
chunk size: 1312
chunk size: 8192
chunk size: 1312

When there is no 0-length chunk, the processRaw() method exits on line 304.  When there is, it exits on line 457.

In all scenarios, the client uses HTTP/1.1 and sends the Connection: keep-alive header.  Adding "%{Connection}i %{Connection}o" to my access valve gives me this in the log:

keep-alive -

When I run tests from a load generator directly against the server, the chunking occurs and the connections get reused as expected.

Here is my plain HTTP connector:

<Connector port="7150"
                protocol="HTTP/1.1"
                connectionTimeout="3000"
                enableLookups="false"
                acceptCount="150"
                redirectPort="8443"
                maxThreads="80"
                maxKeepAliveRequests="100"
                />

Here is one of my SSL connectors:

<Connector port="7154"
        protocol="HTTP/1.1"
        SSLEnabled="true"
        maxThreads="160"
        maxKeepAliveRequests="100"
        keepAliveTimeout="10000"
        scheme="https"
        secure="true"
        clientAuth="true"
        sslProtocol="TLS"
        sslEnabledProtocols="TLSv1,TLSv1.1,TLSv1.2"
        keystoreFile="${keystoreFile}"
        keystorePass="${keystorePassword}"
        keyAlias="banana"
        truststoreFile="${truststoreFile}"
        truststorePass="${truststorePassword}"
        allowUnsafeLegacyRenegotiation="false"
        ciphers="blah blah blah"
/>

Any ideas?

Thanks

John



Reply | Threaded
Open this post in threaded view
|

Re: Missing 0-length chunk to mark the end of a response

markt
On 16/10/17 23:08, [hidden email] wrote:

> All,
>
> Hopefully I can explain this clearly...
>
> The short question is that my client is sometimes not getting the 0-length chunk at the end of the response from Tomcat, so my connections don't get reused.
>
> My Tomcat server is version 7.0.81.  JDK is 1.8.0_144.  I have a Jersey client, version 2.25, connecting to it from another Tomcat server.  I noticed that inbound connections to the server are not getting reused properly.  I think the reason has to do with the fact that Tomcat is using chunked output but is not sending the 0-length chunk that signals the end of the response, even though the response is completed/successful.
>
> My Tomcat server has 3 connectors: one plain HTTP, one SSL, and one SSL + mutual authentication (2-way SSL.)  With plain HTTP, I always get the 0-length chunk.  I verified this both with the remote debugger and TCPMon.  With the other two connectors, I don't get the 0-length chunk with the Jersey client, though I do see it with some other clients.  I can't use TCPMon with SSL, but with the same breakpoints as with non-SSL I see that there is no 0-length chunk.
>
> Setting a breakpoint on ChunkedInputStream line 326 on the client side and printing the chunk sizes, I get this output for 2 responses over plain HTTP:
>
> chunk size: 8192
> chunk size: 1312
> chunk size: 0
> chunk size: 8192
> chunk size: 1312
> chunk size: 0
>
> And for SSL:
>
> chunk size: 8192
> chunk size: 1312
> chunk size: 8192
> chunk size: 1312
>
> When there is no 0-length chunk, the processRaw() method exits on line 304.  When there is, it exits on line 457.
>
> In all scenarios, the client uses HTTP/1.1 and sends the Connection: keep-alive header.  Adding "%{Connection}i %{Connection}o" to my access valve gives me this in the log:
>
> keep-alive -
>
> When I run tests from a load generator directly against the server, the chunking occurs and the connections get reused as expected.
>
> Here is my plain HTTP connector:
>
> <Connector port="7150"
>                 protocol="HTTP/1.1"
>                 connectionTimeout="3000"
>                 enableLookups="false"
>                 acceptCount="150"
>                 redirectPort="8443"
>                 maxThreads="80"
>                 maxKeepAliveRequests="100"
>                 />
>
> Here is one of my SSL connectors:
>
> <Connector port="7154"
>         protocol="HTTP/1.1"
>         SSLEnabled="true"
>         maxThreads="160"
>         maxKeepAliveRequests="100"
>         keepAliveTimeout="10000"
>         scheme="https"
>         secure="true"
>         clientAuth="true"
>         sslProtocol="TLS"
>         sslEnabledProtocols="TLSv1,TLSv1.1,TLSv1.2"
>         keystoreFile="${keystoreFile}"
>         keystorePass="${keystorePassword}"
>         keyAlias="banana"
>         truststoreFile="${truststoreFile}"
>         truststorePass="${truststorePassword}"
>         allowUnsafeLegacyRenegotiation="false"
>         ciphers="blah blah blah"
> />
>
> Any ideas?

Try putting some breakpoints on the server side code and see if you can
track down why the writing of the final chunk gets triggered under HTTP
but not HTTPS.

Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]