Bug 56172 - AjpNioProtocol sometimes corrupts (ignores) the request body
Summary: AjpNioProtocol sometimes corrupts (ignores) the request body
Alias: None
Product: Tomcat 8
Classification: Unclassified
Component: Connectors (show other bugs)
Version: 8.0.x-trunk
Hardware: PC All
: P2 normal (vote)
Target Milestone: ----
Assignee: Tomcat Developers Mailing List
Depends on:
Reported: 2014-02-21 09:53 UTC by Amund Elstad
Modified: 2014-02-21 12:14 UTC (History)
0 users


Note You need to log in before you can comment on or make changes to this bug.
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.