Bug 63949 - ERR_INCOMPLETE_CHUNKED_ENCODING errors when using NIO Connector with HTTPS
Summary: ERR_INCOMPLETE_CHUNKED_ENCODING errors when using NIO Connector with HTTPS
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 9
Classification: Unclassified
Component: Util (show other bugs)
Version: 9.0.20
Hardware: Macintosh All
: P2 normal (vote)
Target Milestone: -----
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-11-21 17:58 UTC by justin.wong
Modified: 2019-11-23 14:49 UTC (History)
0 users



Attachments
patch for NioEndpoint to use pool writes when blocking & non-blocking (1.24 KB, patch)
2019-11-21 17:58 UTC, justin.wong
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description justin.wong 2019-11-21 17:58:51 UTC
Created attachment 36892 [details]
patch for NioEndpoint to use pool writes when blocking & non-blocking

Product: Tomcat 9.0.20+
Component: tomcat/java/org/apache/tomcat/util/net/NioEndpoint.java
Platform: macOS Mojave 10.14.6
Java version: 1.8.0_202 (Oracle Corporation)

Using the NIO Connector with SSL, I am seeing issues with the chunked responses. It's been sporadic, but repeatable with my application within 20 attempts (though usually just the first after a fresh start is enough). Tried on 8.5.40 and 8.5.47, and did not experience the issue. 

It shows up in Chrome as: 

> net::ERR_INCOMPLETE_CHUNKED_ENCODING

Going back to older Tomcat versions, we were able to narrow it down to 9.0.20 being the first version with the issue, specifically this commit: 

https://github.com/apache/tomcat/commit/4377d2db40

With the move to a straight write during non-blocking writes, the case for a non-blocking write with a shared selector is different. By reverting back to a pool write, I was able to make fix the issue. 

Attached patch applies to master branch, commit 0872b1a498610b008acbdaa719895ae15370359a.
Comment 1 Remy Maucherat 2019-11-21 20:03:14 UTC
-1 for the patch, you're doing a blocking write, so it "works". We'll examine the issue eventually, but it most likely works fine as is.
If it is non blocking, the "selector" was not doing any magic, it simply does a non blocking write, hence the patch.
Comment 2 Remy Maucherat 2019-11-22 10:33:51 UTC
The previous code was using a write loop, that's the only difference I can see and you can try it.
Such as:
--- a/java/org/apache/tomcat/util/net/NioEndpoint.java
+++ b/java/org/apache/tomcat/util/net/NioEndpoint.java
@@ -1273,9 +1273,13 @@
                 // registered for write once as both container and user code can trigger
                 // write registration.
             } else {
-                if (socket.write(from) == -1) {
-                    throw new EOFException();
-                }
+                int n = 0;
+                do {
+                    n = socket.write(from);
+                    if (n == -1) {
+                        throw new EOFException();
+                    }
+                } while (n > 0 && from.hasRemaining());
             }
             updateLastWrite();
         }

If you are still experiencing an issue, please provide a test case (there's an extensive non blocking write test in the Tomcat testsuite, which is not failing).
Comment 3 justin.wong 2019-11-22 15:51:11 UTC
Made that change, and don't have the problem anymore. 

Would adding that write loop back in be a possibility? 

Thanks,
Justin
Comment 4 Remy Maucherat 2019-11-22 16:05:05 UTC
Ok, sorry for the trouble, the loop seemed only useful for blocking mode so I didn't add it. The fix will be in Tomcat 9.0.30.
Comment 5 justin.wong 2019-11-23 14:49:19 UTC
Thanks for the fast turn around!