CVE-2017-5647
Description
A bug in the handling of the pipelined requests in Apache Tomcat 9.0.0.M1 to 9.0.0.M18, 8.5.0 to 8.5.12, 8.0.0.RC1 to 8.0.42, 7.0.0 to 7.0.76, and 6.0.0 to 6.0.52, when send file was used, results in the pipelined request being lost when send file processing of the previous request completed. This could result in responses appearing to be sent for the wrong request. For example, a user agent that sent requests A, B and C could see the correct response for request A, the response for request C for request B and no response for request C.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.apache.tomcat:tomcatMaven | >= 9.0.0.M1, < 9.0.0.M19 | 9.0.0.M19 |
org.apache.tomcat:tomcatMaven | >= 8.5.0, < 8.5.13 | 8.5.13 |
org.apache.tomcat:tomcatMaven | >= 8.0.0, < 8.0.43 | 8.0.43 |
org.apache.tomcat:tomcatMaven | >= 7.0.0, < 7.0.77 | 7.0.77 |
org.apache.tomcat:tomcatMaven | >= 6.0.0, < 6.0.53 | 6.0.53 |
Affected products
206cpe:2.3:a:apache:tomcat:6.0.0:*:*:*:*:*:*:*+ 204 more
- cpe:2.3:a:apache:tomcat:6.0.0:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.2:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.3:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.4:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.5:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.6:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.7:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.8:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.9:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.10:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.11:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.12:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.13:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.14:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.15:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.16:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.17:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.18:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.19:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.20:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.21:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.22:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.23:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.24:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.25:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.26:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.27:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.28:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.28:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.29:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.29:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.30:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.31:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.32:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.33:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.34:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.35:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.36:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.37:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.38:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.39:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.40:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.41:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.42:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.43:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.44:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.45:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.46:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.47:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.48:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.49:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.50:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.51:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:6.0.52:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.0:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.2:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.3:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.4:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.5:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.6:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.7:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.8:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.9:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.10:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.11:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.12:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.13:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.14:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.15:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.16:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.17:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.18:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.19:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.20:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.21:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.22:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.23:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.24:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.25:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.26:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.27:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.41:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.73:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.74:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.75:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.76:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.0:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.0:rc1:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.2:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.3:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.4:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.5:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.23:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.24:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.25:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.26:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.27:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.28:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.29:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.30:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.31:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.32:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.33:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.34:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.35:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.36:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.37:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.38:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.39:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.40:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.41:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.42:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.0:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.2:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.3:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.4:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.5:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.6:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.7:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.8:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.9:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.12:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone1:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone10:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone11:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone12:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone13:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.30:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.31:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.32:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.33:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.34:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.35:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.36:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.37:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.38:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.39:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.40:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.42:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.43:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.44:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.45:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.46:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.47:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.48:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.49:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.50:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.51:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.52:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.53:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.54:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.55:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.56:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.57:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.58:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.59:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.60:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.61:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.62:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.63:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.64:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.65:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.66:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.67:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.68:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.69:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.70:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.71:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:7.0.72:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.6:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.7:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.8:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.9:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.10:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.11:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.12:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.13:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.14:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.15:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.16:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.17:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.18:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.19:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.20:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.21:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.0.22:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.10:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:8.5.11:*:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone14:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone15:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone16:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone17:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone18:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone2:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone3:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone4:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone5:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone6:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone7:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone8:*:*:*:*:*:*
- cpe:2.3:a:apache:tomcat:9.0.0:milestone9:*:*:*:*:*:*
- Apache Software Foundation/Apache Tomcatv5Range: 9.0.0.M1 to 9.0.0.M18
Patches
4a4efd3ca1ccbImprove sendfile handling when requests are pipelined.
7 files changed · +111 −25
java/org/apache/coyote/AbstractProtocol.java+3 −4 modified@@ -693,10 +693,9 @@ public SocketState process(SocketWrapper<S> wrapper, release(wrapper, processor, false, true); } else if (state == SocketState.SENDFILE) { // Sendfile in progress. If it fails, the socket will be - // closed. If it works, the socket will be re-added to the - // poller - connections.remove(socket); - release(wrapper, processor, false, false); + // closed. If it works, the socket either be added to the + // poller (or equivalent) to await more data or processed + // if there are any pipe-lined requests remaining. } else if (state == SocketState.UPGRADED) { // Need to keep the connection associated with the processor connections.put(socket, processor);
java/org/apache/coyote/http11/Http11AprProcessor.java+10 −1 modified@@ -38,6 +38,7 @@ import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.AprEndpoint; import org.apache.tomcat.util.net.SSLSupport; +import org.apache.tomcat.util.net.SendfileKeepAliveState; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; @@ -211,7 +212,15 @@ protected boolean breakKeepAliveLoop(SocketWrapper<Long> socketWrapper) { // Do sendfile as needed: add socket to sendfile and end if (sendfileData != null && !getErrorState().isError()) { sendfileData.socket = socketWrapper.getSocket().longValue(); - sendfileData.keepAlive = keepAlive; + if (keepAlive) { + if (getInputBuffer().available() == 0) { + sendfileData.keepAliveState = SendfileKeepAliveState.OPEN; + } else { + sendfileData.keepAliveState = SendfileKeepAliveState.PIPELINED; + } + } else { + sendfileData.keepAliveState = SendfileKeepAliveState.NONE; + } switch (((AprEndpoint)endpoint).getSendfile().add(sendfileData)) { case DONE: return false;
java/org/apache/coyote/http11/Http11NioProcessor.java+10 −1 modified@@ -37,6 +37,7 @@ import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.net.SecureNioChannel; +import org.apache.tomcat.util.net.SendfileKeepAliveState; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; @@ -275,7 +276,15 @@ protected boolean breakKeepAliveLoop(SocketWrapper<NioChannel> socketWrapper) { // Do sendfile as needed: add socket to sendfile and end if (sendfileData != null && !getErrorState().isError()) { ((KeyAttachment) socketWrapper).setSendfileData(sendfileData); - sendfileData.keepAlive = keepAlive; + if (keepAlive) { + if (getInputBuffer().available() == 0) { + sendfileData.keepAliveState = SendfileKeepAliveState.OPEN; + } else { + sendfileData.keepAliveState = SendfileKeepAliveState.PIPELINED; + } + } else { + sendfileData.keepAliveState = SendfileKeepAliveState.NONE; + } SelectionKey key = socketWrapper.getSocket().getIOChannel().keyFor( socketWrapper.getSocket().getPoller().getSelector()); //do the first write on this thread, might as well
java/org/apache/tomcat/util/net/AprEndpoint.java+25 −12 modified@@ -2106,7 +2106,7 @@ public static class SendfileData { // Position public long pos; // KeepAlive flag - public boolean keepAlive; + public SendfileKeepAliveState keepAliveState = SendfileKeepAliveState.NONE; } @@ -2349,20 +2349,33 @@ public void run() { state.pos = state.pos + nw; if (state.pos >= state.end) { remove(state); - if (state.keepAlive) { + switch (state.keepAliveState) { + case NONE: { + // Close the socket since this is + // the end of the not keep-alive request. + closeSocket(state.socket); + break; + } + case PIPELINED: { // Destroy file descriptor pool, which should close the file Pool.destroy(state.fdpool); - Socket.timeoutSet(state.socket, - getSoTimeout() * 1000); - // If all done put the socket back in the - // poller for processing of further requests - getPoller().add( - state.socket, getKeepAliveTimeout(), + Socket.timeoutSet(state.socket, getSoTimeout() * 1000); + // Process the pipelined request data + if (!processSocket(state.socket, SocketStatus.OPEN_READ)) { + closeSocket(state.socket); + } + break; + } + case OPEN: { + // Destroy file descriptor pool, which should close the file + Pool.destroy(state.fdpool); + Socket.timeoutSet(state.socket, getSoTimeout() * 1000); + // Put the socket back in the poller for + // processing of further requests + getPoller().add(state.socket, getKeepAliveTimeout(), true, false); - } else { - // Close the socket since this is - // the end of not keep-alive request. - closeSocket(state.socket); + break; + } } } }
java/org/apache/tomcat/util/net/NioEndpoint.java+21 −7 modified@@ -1383,16 +1383,30 @@ public SendfileState processSendfile(SelectionKey sk, KeyAttachment attachment, // responsible for registering the socket for the // appropriate event(s) if sendfile completes. if (!calledByProcessor) { - if ( sd.keepAlive ) { - if (log.isDebugEnabled()) { - log.debug("Connection is keep alive, registering back for OP_READ"); - } - reg(sk,attachment,SelectionKey.OP_READ); - } else { + switch (sd.keepAliveState) { + case NONE: { if (log.isDebugEnabled()) { log.debug("Send file connection is being closed"); } cancelledKey(sk,SocketStatus.STOP,false); + break; + } + case PIPELINED: { + if (log.isDebugEnabled()) { + log.debug("Connection is keep alive, processing pipe-lined data"); + } + if (!processSocket(sc, SocketStatus.OPEN_READ, true)) { + cancelledKey(sk, SocketStatus.DISCONNECT, false); + } + break; + } + case OPEN: { + if (log.isDebugEnabled()) { + log.debug("Connection is keep alive, registering back for OP_READ"); + } + reg(sk, attachment, SelectionKey.OP_READ); + break; + } } } return SendfileState.DONE; @@ -1836,6 +1850,6 @@ public static class SendfileData { public volatile long pos; public volatile long length; // KeepAlive flag - public volatile boolean keepAlive; + public SendfileKeepAliveState keepAliveState = SendfileKeepAliveState.NONE; } }
java/org/apache/tomcat/util/net/SendfileKeepAliveState.java+39 −0 added@@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.net; + +public enum SendfileKeepAliveState { + + /** + * Keep-alive is not in use. The socket can be closed when the response has + * been written. + */ + NONE, + + /** + * Keep-alive is in use and there is pipelined data in the input buffer to + * be read as soon as the current response has been written. + */ + PIPELINED, + + /** + * Keep-alive is in use. The socket should be added to the poller (or + * equivalent) to await more data as soon as the current response has been + * written. + */ + OPEN +}
webapps/docs/changelog.xml+3 −0 modified@@ -83,6 +83,9 @@ configuration attributes and internal code. Based on a patch by Michael Osipov. (markt) </fix> + <fix> + Improve sendfile handling when requests are pipelined. (markt) + </fix> </changelog> </subsection> <subsection name="Jasper">
ec10b8c785d1Improve sendfile handling when requests are pipelined.
9 files changed · +136 −36
java/org/apache/coyote/AbstractProtocol.java+3 −4 modified@@ -747,10 +747,9 @@ public SocketState process(SocketWrapper<S> wrapper, release(wrapper, processor, false, true); } else if (state == SocketState.SENDFILE) { // Sendfile in progress. If it fails, the socket will be - // closed. If it works, the socket will be re-added to the - // poller - connections.remove(socket); - release(wrapper, processor, false, false); + // closed. If it works, the socket either be added to the + // poller (or equivalent) to await more data or processed + // if there are any pipe-lined requests remaining. } else if (state == SocketState.UPGRADED) { // Don't add sockets back to the poller if this was a // non-blocking write otherwise the poller may trigger
java/org/apache/coyote/http11/Http11AprProcessor.java+10 −1 modified@@ -38,6 +38,7 @@ import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.AprEndpoint; import org.apache.tomcat.util.net.SSLSupport; +import org.apache.tomcat.util.net.SendfileKeepAliveState; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; @@ -198,7 +199,15 @@ protected boolean breakKeepAliveLoop(SocketWrapper<Long> socketWrapper) { // Do sendfile as needed: add socket to sendfile and end if (sendfileData != null && !getErrorState().isError()) { sendfileData.socket = socketWrapper.getSocket().longValue(); - sendfileData.keepAlive = keepAlive; + if (keepAlive) { + if (getInputBuffer().available(false) == 0) { + sendfileData.keepAliveState = SendfileKeepAliveState.OPEN; + } else { + sendfileData.keepAliveState = SendfileKeepAliveState.PIPELINED; + } + } else { + sendfileData.keepAliveState = SendfileKeepAliveState.NONE; + } switch (((AprEndpoint)endpoint).getSendfile().add(sendfileData)) { case DONE: return false;
java/org/apache/coyote/http11/Http11Nio2Processor.java+10 −1 modified@@ -37,6 +37,7 @@ import org.apache.tomcat.util.net.Nio2Endpoint; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.net.SecureNio2Channel; +import org.apache.tomcat.util.net.SendfileKeepAliveState; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; @@ -280,7 +281,15 @@ protected boolean breakKeepAliveLoop(SocketWrapper<Nio2Channel> socketWrapper) { // Do sendfile as needed: add socket to sendfile and end if (sendfileData != null && !getErrorState().isError()) { ((Nio2Endpoint.Nio2SocketWrapper) socketWrapper).setSendfileData(sendfileData); - sendfileData.keepAlive = keepAlive; + if (keepAlive) { + if (getInputBuffer().available(false) == 0) { + sendfileData.keepAliveState = SendfileKeepAliveState.OPEN; + } else { + sendfileData.keepAliveState = SendfileKeepAliveState.PIPELINED; + } + } else { + sendfileData.keepAliveState = SendfileKeepAliveState.NONE; + } switch (((Nio2Endpoint) endpoint).processSendfile( (Nio2Endpoint.Nio2SocketWrapper) socketWrapper)) { case DONE:
java/org/apache/coyote/http11/Http11NioProcessor.java+10 −1 modified@@ -37,6 +37,7 @@ import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.net.SecureNioChannel; +import org.apache.tomcat.util.net.SendfileKeepAliveState; import org.apache.tomcat.util.net.SocketStatus; import org.apache.tomcat.util.net.SocketWrapper; @@ -278,7 +279,15 @@ protected boolean breakKeepAliveLoop(SocketWrapper<NioChannel> socketWrapper) { // Do sendfile as needed: add socket to sendfile and end if (sendfileData != null && !getErrorState().isError()) { ((KeyAttachment) socketWrapper).setSendfileData(sendfileData); - sendfileData.keepAlive = keepAlive; + if (keepAlive) { + if (getInputBuffer().available(false) == 0) { + sendfileData.keepAliveState = SendfileKeepAliveState.OPEN; + } else { + sendfileData.keepAliveState = SendfileKeepAliveState.PIPELINED; + } + } else { + sendfileData.keepAliveState = SendfileKeepAliveState.NONE; + } SelectionKey key = socketWrapper.getSocket().getIOChannel().keyFor( socketWrapper.getSocket().getPoller().getSelector()); //do the first write on this thread, might as well
java/org/apache/tomcat/util/net/AprEndpoint.java+25 −12 modified@@ -2078,7 +2078,7 @@ public static class SendfileData { // Position public long pos; // KeepAlive flag - public boolean keepAlive; + public SendfileKeepAliveState keepAliveState = SendfileKeepAliveState.NONE; } @@ -2321,20 +2321,33 @@ public void run() { state.pos = state.pos + nw; if (state.pos >= state.end) { remove(state); - if (state.keepAlive) { + switch (state.keepAliveState) { + case NONE: { + // Close the socket since this is + // the end of the not keep-alive request. + closeSocket(state.socket); + break; + } + case PIPELINED: { // Destroy file descriptor pool, which should close the file Pool.destroy(state.fdpool); - Socket.timeoutSet(state.socket, - getSoTimeout() * 1000); - // If all done put the socket back in the - // poller for processing of further requests - getPoller().add( - state.socket, getKeepAliveTimeout(), + Socket.timeoutSet(state.socket, getSoTimeout() * 1000); + // Process the pipelined request data + if (!processSocket(state.socket, SocketStatus.OPEN_READ)) { + closeSocket(state.socket); + } + break; + } + case OPEN: { + // Destroy file descriptor pool, which should close the file + Pool.destroy(state.fdpool); + Socket.timeoutSet(state.socket, getSoTimeout() * 1000); + // Put the socket back in the poller for + // processing of further requests + getPoller().add(state.socket, getKeepAliveTimeout(), Poll.APR_POLLIN); - } else { - // Close the socket since this is - // the end of not keep-alive request. - closeSocket(state.socket); + break; + } } } }
java/org/apache/tomcat/util/net/Nio2Endpoint.java+15 −10 modified@@ -914,17 +914,22 @@ public void completed(Integer nWrite, SendfileData attachment) { } catch (IOException e) { // Ignore } - if (attachment.keepAlive) { - if (!isInline()) { - awaitBytes(attachment.socket); - } else { - attachment.doneInline = true; - } + if (isInline()) { + attachment.doneInline = true; } else { - if (!isInline()) { + switch (attachment.keepAliveState) { + case NONE: { processSocket(attachment.socket, SocketStatus.DISCONNECT, false); - } else { - attachment.doneInline = true; + break; + } + case PIPELINED: { + processSocket(attachment.socket, SocketStatus.OPEN_READ, true); + break; + } + case OPEN: { + awaitBytes(attachment.socket); + break; + } } } return; @@ -1162,7 +1167,7 @@ public static class SendfileData { public long pos; public long length; // KeepAlive flag - public boolean keepAlive; + public SendfileKeepAliveState keepAliveState = SendfileKeepAliveState.NONE; // Internal use only private Nio2SocketWrapper socket; private ByteBuffer buffer;
java/org/apache/tomcat/util/net/NioEndpoint.java+21 −7 modified@@ -1214,16 +1214,30 @@ public SendfileState processSendfile(SelectionKey sk, KeyAttachment attachment, // responsible for registering the socket for the // appropriate event(s) if sendfile completes. if (!calledByProcessor) { - if (sd.keepAlive) { - if (log.isDebugEnabled()) { - log.debug("Connection is keep alive, registering back for OP_READ"); - } - reg(sk,attachment,SelectionKey.OP_READ); - } else { + switch (sd.keepAliveState) { + case NONE: { if (log.isDebugEnabled()) { log.debug("Send file connection is being closed"); } cancelledKey(sk,SocketStatus.STOP); + break; + } + case PIPELINED: { + if (log.isDebugEnabled()) { + log.debug("Connection is keep alive, processing pipe-lined data"); + } + if (!processSocket(attachment, SocketStatus.OPEN_READ, true)) { + cancelledKey(sk, SocketStatus.DISCONNECT); + } + break; + } + case OPEN: { + if (log.isDebugEnabled()) { + log.debug("Connection is keep alive, registering back for OP_READ"); + } + reg(sk, attachment, SelectionKey.OP_READ); + break; + } } } return SendfileState.DONE; @@ -1589,6 +1603,6 @@ public static class SendfileData { public volatile long pos; public volatile long length; // KeepAlive flag - public volatile boolean keepAlive; + public SendfileKeepAliveState keepAliveState = SendfileKeepAliveState.NONE; } }
java/org/apache/tomcat/util/net/SendfileKeepAliveState.java+39 −0 added@@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.net; + +public enum SendfileKeepAliveState { + + /** + * Keep-alive is not in use. The socket can be closed when the response has + * been written. + */ + NONE, + + /** + * Keep-alive is in use and there is pipelined data in the input buffer to + * be read as soon as the current response has been written. + */ + PIPELINED, + + /** + * Keep-alive is in use. The socket should be added to the poller (or + * equivalent) to await more data as soon as the current response has been + * written. + */ + OPEN +}
webapps/docs/changelog.xml+3 −0 modified@@ -75,6 +75,9 @@ configuration attributes and internal code. Based on a patch by Michael Osipov. (markt) </fix> + <fix> + Improve sendfile handling when requests are pipelined. (markt) + </fix> </changelog> </subsection> <subsection name="Jasper">
f5e06b8c743bImprove sendfile handling when requests are pipelined.
8 files changed · +118 −34
java/org/apache/coyote/AbstractProtocol.java+3 −4 modified@@ -933,10 +933,9 @@ public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) { wrapper.registerReadInterest(); } else if (state == SocketState.SENDFILE) { // Sendfile in progress. If it fails, the socket will be - // closed. If it works, the socket will be re-added to the - // poller - connections.remove(socket); - release(processor); + // closed. If it works, the socket either be added to the + // poller (or equivalent) to await more data or processed + // if there are any pipe-lined requests remaining. } else if (state == SocketState.UPGRADED) { // Don't add sockets back to the poller if this was a // non-blocking write otherwise the poller may trigger
java/org/apache/coyote/http11/Http11Processor.java+10 −1 modified@@ -58,6 +58,7 @@ import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.net.SendfileDataBase; +import org.apache.tomcat.util.net.SendfileKeepAliveState; import org.apache.tomcat.util.net.SendfileState; import org.apache.tomcat.util.net.SocketWrapperBase; import org.apache.tomcat.util.res.StringManager; @@ -1612,7 +1613,15 @@ private SendfileState processSendfile(SocketWrapperBase<?> socketWrapper) { SendfileState result = SendfileState.DONE; // Do sendfile as needed: add socket to sendfile and end if (sendfileData != null && !getErrorState().isError()) { - sendfileData.keepAlive = keepAlive; + if (keepAlive) { + if (available(false) == 0) { + sendfileData.keepAliveState = SendfileKeepAliveState.OPEN; + } else { + sendfileData.keepAliveState = SendfileKeepAliveState.PIPELINED; + } + } else { + sendfileData.keepAliveState = SendfileKeepAliveState.NONE; + } result = socketWrapper.processSendfile(sendfileData); switch (result) { case ERROR:
java/org/apache/tomcat/util/net/AprEndpoint.java+24 −11 modified@@ -2144,20 +2144,33 @@ public void run() { state.length -= nw; if (state.length == 0) { remove(state); - if (state.keepAlive) { + switch (state.keepAliveState) { + case NONE: { + // Close the socket since this is + // the end of the not keep-alive request. + closeSocket(state.socket); + break; + } + case PIPELINED: { // Destroy file descriptor pool, which should close the file Pool.destroy(state.fdpool); - Socket.timeoutSet(state.socket, - getSoTimeout() * 1000); - // If all done put the socket back in the - // poller for processing of further requests - getPoller().add( - state.socket, getKeepAliveTimeout(), + Socket.timeoutSet(state.socket, getSoTimeout() * 1000); + // Process the pipelined request data + if (!processSocket(state.socket, SocketEvent.OPEN_READ)) { + closeSocket(state.socket); + } + break; + } + case OPEN: { + // Destroy file descriptor pool, which should close the file + Pool.destroy(state.fdpool); + Socket.timeoutSet(state.socket, getSoTimeout() * 1000); + // Put the socket back in the poller for + // processing of further requests + getPoller().add(state.socket, getKeepAliveTimeout(), Poll.APR_POLLIN); - } else { - // Close the socket since this is - // the end of not keep-alive request. - closeSocket(state.socket); + break; + } } } }
java/org/apache/tomcat/util/net/Nio2Endpoint.java+16 −9 modified@@ -536,17 +536,24 @@ public void completed(Integer nWrite, SendfileData attachment) { } catch (IOException e) { // Ignore } - if (attachment.keepAlive) { - if (!isInline()) { + if (isInline()) { + attachment.doneInline = true; + } else { + switch (attachment.keepAliveState) { + case NONE: { + getEndpoint().processSocket(Nio2SocketWrapper.this, + SocketEvent.DISCONNECT, false); + break; + } + case PIPELINED: { + getEndpoint().processSocket(Nio2SocketWrapper.this, + SocketEvent.OPEN_READ, true); + break; + } + case OPEN: { awaitBytes(); - } else { - attachment.doneInline = true; + break; } - } else { - if (!isInline()) { - getEndpoint().processSocket(Nio2SocketWrapper.this, SocketEvent.DISCONNECT, false); - } else { - attachment.doneInline = true; } } return;
java/org/apache/tomcat/util/net/NioEndpoint.java+20 −6 modified@@ -924,16 +924,30 @@ public SendfileState processSendfile(SelectionKey sk, NioSocketWrapper socketWra // responsible for registering the socket for the // appropriate event(s) if sendfile completes. if (!calledByProcessor) { - if (sd.keepAlive) { - if (log.isDebugEnabled()) { - log.debug("Connection is keep alive, registering back for OP_READ"); - } - reg(sk,socketWrapper,SelectionKey.OP_READ); - } else { + switch (sd.keepAliveState) { + case NONE: { if (log.isDebugEnabled()) { log.debug("Send file connection is being closed"); } close(sc, sk); + break; + } + case PIPELINED: { + if (log.isDebugEnabled()) { + log.debug("Connection is keep alive, processing pipe-lined data"); + } + if (!processSocket(socketWrapper, SocketEvent.OPEN_READ, true)) { + close(sc, sk); + } + break; + } + case OPEN: { + if (log.isDebugEnabled()) { + log.debug("Connection is keep alive, registering back for OP_READ"); + } + reg(sk,socketWrapper,SelectionKey.OP_READ); + break; + } } } return SendfileState.DONE;
java/org/apache/tomcat/util/net/SendfileDataBase.java+3 −3 modified@@ -21,10 +21,10 @@ public abstract class SendfileDataBase { /** * Is the current request being processed on a keep-alive connection? This * determines if the socket is closed once the send file completes or if - * processing continues with the next request on the connection (or waiting - * for that next request to arrive). + * processing continues with the next request on the connection or waiting + * for that next request to arrive. */ - public boolean keepAlive; + public SendfileKeepAliveState keepAliveState = SendfileKeepAliveState.NONE; /** * The full path to the file that contains the data to be written to the
java/org/apache/tomcat/util/net/SendfileKeepAliveState.java+39 −0 added@@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.net; + +public enum SendfileKeepAliveState { + + /** + * Keep-alive is not in use. The socket can be closed when the response has + * been written. + */ + NONE, + + /** + * Keep-alive is in use and there is pipelined data in the input buffer to + * be read as soon as the current response has been written. + */ + PIPELINED, + + /** + * Keep-alive is in use. The socket should be added to the poller (or + * equivalent) to await more data as soon as the current response has been + * written. + */ + OPEN +}
webapps/docs/changelog.xml+3 −0 modified@@ -127,6 +127,9 @@ subsequent requests experiencing an <code>IllegalStateException</code>. (markt) </fix> + <fix> + Improve sendfile handling when requests are pipelined. (markt) + </fix> </changelog> </subsection> <subsection name="Jasper">
864aa1199ad2Improve sendfile handling when requests are pipelined.
8 files changed · +118 −34
java/org/apache/coyote/AbstractProtocol.java+3 −4 modified@@ -868,10 +868,9 @@ public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) { wrapper.registerReadInterest(); } else if (state == SocketState.SENDFILE) { // Sendfile in progress. If it fails, the socket will be - // closed. If it works, the socket will be re-added to the - // poller - connections.remove(socket); - release(processor); + // closed. If it works, the socket either be added to the + // poller (or equivalent) to await more data or processed + // if there are any pipe-lined requests remaining. } else if (state == SocketState.UPGRADED) { // Don't add sockets back to the poller if this was a // non-blocking write otherwise the poller may trigger
java/org/apache/coyote/http11/Http11Processor.java+10 −1 modified@@ -55,6 +55,7 @@ import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; import org.apache.tomcat.util.net.SSLSupport; import org.apache.tomcat.util.net.SendfileDataBase; +import org.apache.tomcat.util.net.SendfileKeepAliveState; import org.apache.tomcat.util.net.SendfileState; import org.apache.tomcat.util.net.SocketWrapperBase; import org.apache.tomcat.util.res.StringManager; @@ -1312,7 +1313,15 @@ private SendfileState processSendfile(SocketWrapperBase<?> socketWrapper) { SendfileState result = SendfileState.DONE; // Do sendfile as needed: add socket to sendfile and end if (sendfileData != null && !getErrorState().isError()) { - sendfileData.keepAlive = keepAlive; + if (keepAlive) { + if (available(false) == 0) { + sendfileData.keepAliveState = SendfileKeepAliveState.OPEN; + } else { + sendfileData.keepAliveState = SendfileKeepAliveState.PIPELINED; + } + } else { + sendfileData.keepAliveState = SendfileKeepAliveState.NONE; + } result = socketWrapper.processSendfile(sendfileData); switch (result) { case ERROR:
java/org/apache/tomcat/util/net/AprEndpoint.java+24 −11 modified@@ -2064,20 +2064,33 @@ public void run() { state.length -= nw; if (state.length == 0) { remove(state); - if (state.keepAlive) { + switch (state.keepAliveState) { + case NONE: { + // Close the socket since this is + // the end of the not keep-alive request. + closeSocket(state.socket); + break; + } + case PIPELINED: { // Destroy file descriptor pool, which should close the file Pool.destroy(state.fdpool); - Socket.timeoutSet(state.socket, - getConnectionTimeout() * 1000); - // If all done put the socket back in the - // poller for processing of further requests - getPoller().add( - state.socket, getKeepAliveTimeout(), + Socket.timeoutSet(state.socket, getConnectionTimeout() * 1000); + // Process the pipelined request data + if (!processSocket(state.socket, SocketEvent.OPEN_READ)) { + closeSocket(state.socket); + } + break; + } + case OPEN: { + // Destroy file descriptor pool, which should close the file + Pool.destroy(state.fdpool); + Socket.timeoutSet(state.socket, getConnectionTimeout() * 1000); + // Put the socket back in the poller for + // processing of further requests + getPoller().add(state.socket, getKeepAliveTimeout(), Poll.APR_POLLIN); - } else { - // Close the socket since this is - // the end of not keep-alive request. - closeSocket(state.socket); + break; + } } } }
java/org/apache/tomcat/util/net/Nio2Endpoint.java+16 −9 modified@@ -447,17 +447,24 @@ public void completed(Integer nWrite, SendfileData attachment) { } catch (IOException e) { // Ignore } - if (attachment.keepAlive) { - if (!isInline()) { + if (isInline()) { + attachment.doneInline = true; + } else { + switch (attachment.keepAliveState) { + case NONE: { + getEndpoint().processSocket(Nio2SocketWrapper.this, + SocketEvent.DISCONNECT, false); + break; + } + case PIPELINED: { + getEndpoint().processSocket(Nio2SocketWrapper.this, + SocketEvent.OPEN_READ, true); + break; + } + case OPEN: { awaitBytes(); - } else { - attachment.doneInline = true; + break; } - } else { - if (!isInline()) { - getEndpoint().processSocket(Nio2SocketWrapper.this, SocketEvent.DISCONNECT, false); - } else { - attachment.doneInline = true; } } return;
java/org/apache/tomcat/util/net/NioEndpoint.java+20 −6 modified@@ -837,16 +837,30 @@ public SendfileState processSendfile(SelectionKey sk, NioSocketWrapper socketWra // responsible for registering the socket for the // appropriate event(s) if sendfile completes. if (!calledByProcessor) { - if (sd.keepAlive) { - if (log.isDebugEnabled()) { - log.debug("Connection is keep alive, registering back for OP_READ"); - } - reg(sk,socketWrapper,SelectionKey.OP_READ); - } else { + switch (sd.keepAliveState) { + case NONE: { if (log.isDebugEnabled()) { log.debug("Send file connection is being closed"); } close(sc, sk); + break; + } + case PIPELINED: { + if (log.isDebugEnabled()) { + log.debug("Connection is keep alive, processing pipe-lined data"); + } + if (!processSocket(socketWrapper, SocketEvent.OPEN_READ, true)) { + close(sc, sk); + } + break; + } + case OPEN: { + if (log.isDebugEnabled()) { + log.debug("Connection is keep alive, registering back for OP_READ"); + } + reg(sk,socketWrapper,SelectionKey.OP_READ); + break; + } } } return SendfileState.DONE;
java/org/apache/tomcat/util/net/SendfileDataBase.java+3 −3 modified@@ -21,10 +21,10 @@ public abstract class SendfileDataBase { /** * Is the current request being processed on a keep-alive connection? This * determines if the socket is closed once the send file completes or if - * processing continues with the next request on the connection (or waiting - * for that next request to arrive). + * processing continues with the next request on the connection or waiting + * for that next request to arrive. */ - public boolean keepAlive; + public SendfileKeepAliveState keepAliveState = SendfileKeepAliveState.NONE; /** * The full path to the file that contains the data to be written to the
java/org/apache/tomcat/util/net/SendfileKeepAliveState.java+39 −0 added@@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.net; + +public enum SendfileKeepAliveState { + + /** + * Keep-alive is not in use. The socket can be closed when the response has + * been written. + */ + NONE, + + /** + * Keep-alive is in use and there is pipelined data in the input buffer to + * be read as soon as the current response has been written. + */ + PIPELINED, + + /** + * Keep-alive is in use. The socket should be added to the poller (or + * equivalent) to await more data as soon as the current response has been + * written. + */ + OPEN +}
webapps/docs/changelog.xml+3 −0 modified@@ -145,6 +145,9 @@ subsequent requests experiencing an <code>IllegalStateException</code>. (markt) </fix> + <fix> + Improve sendfile handling when requests are pipelined. (markt) + </fix> </changelog> </subsection> <subsection name="Jasper">
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
61- github.com/advisories/GHSA-3gv7-3h64-78cmghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2017-5647ghsaADVISORY
- www.arubanetworks.com/assets/alert/HPESBHF03730.txtnvdWEB
- www.debian.org/security/2017/dsa-3842nvdWEB
- www.debian.org/security/2017/dsa-3843nvdWEB
- www.oracle.com/technetwork/security-advisory/cpujul2017-3236622.htmlnvdWEB
- access.redhat.com/errata/RHSA-2017:1801nvdWEB
- access.redhat.com/errata/RHSA-2017:1802nvdWEB
- access.redhat.com/errata/RHSA-2017:2493nvdWEB
- access.redhat.com/errata/RHSA-2017:2494nvdWEB
- access.redhat.com/errata/RHSA-2017:3080nvdWEB
- access.redhat.com/errata/RHSA-2017:3081nvdWEB
- github.com/apache/tomcat/commit/864aa1199ad2cccc9a7e7c6b977f7d7f812c9910ghsaWEB
- github.com/apache/tomcat/commit/a4efd3ca1ccbdfc398136d76c0d8b7ad5a1e4905ghsaWEB
- github.com/apache/tomcat/commit/f5e06b8c743b1daa9eb5e817863958b6b320e044ghsaWEB
- github.com/apache/tomcat80/commit/ec10b8c785d1db91fe58946436f854dde04410fdghsaWEB
- h20566.www2.hpe.com/hpsc/doc/public/displaynvdWEB
- lists.apache.org/thread.html/343558d982879bf88ec20dbf707f8c11255f8e219e81d45c4f8d0551%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/343558d982879bf88ec20dbf707f8c11255f8e219e81d45c4f8d0551@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/37220405a377c0182d2afdbc36461c4783b2930fbeae3a17f1333113%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/37220405a377c0182d2afdbc36461c4783b2930fbeae3a17f1333113@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/388a323769f1dff84c9ec905455aa73fbcb20338e3c7eb131457f708%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/388a323769f1dff84c9ec905455aa73fbcb20338e3c7eb131457f708@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/39ae1f0bd5867c15755a6f959b271ade1aea04ccdc3b2e639dcd903b%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/39ae1f0bd5867c15755a6f959b271ade1aea04ccdc3b2e639dcd903b@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/3d19773b4cf0377db62d1e9328bf9160bf1819f04f988315086931d7%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/3d19773b4cf0377db62d1e9328bf9160bf1819f04f988315086931d7@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/5796678c5a773c6f3ff57c178ac247d85ceca0dee9190ba48171451a%40%3Cusers.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/5796678c5a773c6f3ff57c178ac247d85ceca0dee9190ba48171451a@%3Cusers.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/5c0e00fd31efc11e147bf99d0f03c00a734447d3b131ab0818644cdb%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/5c0e00fd31efc11e147bf99d0f03c00a734447d3b131ab0818644cdb@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/6af47120905aa7d8fe12f42e8ff2284fb338ba141d3b77b8c7cb61b3%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/6af47120905aa7d8fe12f42e8ff2284fb338ba141d3b77b8c7cb61b3@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/845312a10aabbe2c499fca94003881d2c79fc993d85f34c1f5c77424%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/845312a10aabbe2c499fca94003881d2c79fc993d85f34c1f5c77424@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/88855876c33f2f9c532ffb75bfee570ccf0b17ffa77493745af9a17a%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/88855876c33f2f9c532ffb75bfee570ccf0b17ffa77493745af9a17a@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/b5e3f51d28cd5d9b1809f56594f2cf63dcd6a90429e16ea9f83bbedc%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/b5e3f51d28cd5d9b1809f56594f2cf63dcd6a90429e16ea9f83bbedc@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/b84ad1258a89de5c9c853c7f2d3ad77e5b8b2930be9e132d5cef6b95%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/b84ad1258a89de5c9c853c7f2d3ad77e5b8b2930be9e132d5cef6b95@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/b8a1bf18155b552dcf9a928ba808cbadad84c236d85eab3033662cfb%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/b8a1bf18155b552dcf9a928ba808cbadad84c236d85eab3033662cfb@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/eb6efa8d59c45a7a9eff94c4b925467d3b3fec8ba7697f3daa314b04%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/eb6efa8d59c45a7a9eff94c4b925467d3b3fec8ba7697f3daa314b04@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r03c597a64de790ba42c167efacfa23300c3d6c9fe589ab87fe02859c%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/r03c597a64de790ba42c167efacfa23300c3d6c9fe589ab87fe02859c@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r3bbb800a816d0a51eccc5a228c58736960a9fffafa581a225834d97d%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/r3bbb800a816d0a51eccc5a228c58736960a9fffafa581a225834d97d@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r48c1444845fe15a823e1374674bfc297d5008a5453788099ea14caf0%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/r48c1444845fe15a823e1374674bfc297d5008a5453788099ea14caf0@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r587e50b86c1a96ee301f751d50294072d142fd6dc08a8987ae9f3a9b%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/r587e50b86c1a96ee301f751d50294072d142fd6dc08a8987ae9f3a9b@%3Cdev.tomcat.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r9136ff5b13e4f1941360b5a309efee2c114a14855578c3a2cbe5d19c%40%3Cdev.tomcat.apache.org%3EnvdWEB
- lists.apache.org/thread.html/r9136ff5b13e4f1941360b5a309efee2c114a14855578c3a2cbe5d19c@%3Cdev.tomcat.apache.org%3EghsaWEB
- security.gentoo.org/glsa/201705-09nvdWEB
- security.netapp.com/advisory/ntap-20180614-0001ghsaWEB
- web.archive.org/web/20170420114447/http://www.securitytracker.com/id/1038218ghsaWEB
- www.oracle.com/technetwork/security-advisory/cpujul2019-5072835.htmlnvdWEB
- www.securitytracker.com/id/1038218nvd
- security.netapp.com/advisory/ntap-20180614-0001/nvd
News mentions
0No linked articles in our index yet.