Bug 56172

Summary: AjpNioProtocol sometimes corrupts (ignores) the request body
Product: Tomcat 8 Reporter: Amund Elstad <amund.elstad>
Component: ConnectorsAssignee: Tomcat Developers Mailing List <dev>
Severity: normal    
Priority: P2    
Version: 8.0.x-trunk   
Target Milestone: ----   
Hardware: PC   
OS: All   

Description Amund Elstad 2014-02-21 09:53:40 UTC
Tomcat sometimes fails to read the request body when using the AjpNioProtocol 
connector. The symptom of this is the log message

ERROR org.apache.coyote.ajp.AjpMessage - Invalid message received with 
signature  ...

The cause of this problem is the fact that the read-method in  AjpNioProcessor may read more than the requested number of bytes, if more than one readSocket call is required.

Thus, reading of an ajp-message can also wrongly read some or all of the next message(s) (if any). Reading of the next messages will then most likely fail with a signature error, or the content will be corrupt.

This problem is unlikely to happen unless the FORWARD_REQUEST message is larger than a network packet, and there is a request body with Content-Length > 0, so that first body chunk message immediately follows the FORWARD_REQUEST message.

I have reproduced and solved this problem with Tomcat 7.0.42, but looking at the source code I believe the problem should be present in trunk as well.

Description of patch to fix the problem:

The read-method may have to make several calls to readSocket to read the
requested number of bytes. Alter the maximum bytes read per call so that 
the total bytes read is never more than requested.

Index: org/apache/coyote/ajp/AjpNioProcessor.java
--- org/apache/coyote/ajp/AjpNioProcessor.java  (revisjon 1570107)
+++ org/apache/coyote/ajp/AjpNioProcessor.java  (arbeidskopi)
@@ -155,7 +155,7 @@
         boolean block = blockFirstRead;

         while (read < n) {
-            res = readSocket(buf, read + pos, n, block);
+            res = readSocket(buf, read + pos, n - read, block);
             if (res > 0) {
                 read += res;
             } else if (res == 0 && !block) {
Comment 1 Mark Thomas 2014-02-21 12:14:11 UTC
Thanks for the high quality bug report. A good description of the problem, analysis of the root cause and a patch. We couldn't really ask for more. Thanks!

The patch has been applied to 8.0.x and will be included in 8.0.4 onwards. It has also been applied to 7.0.x for 7.0.53 onwards.