This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/master by this push:
new 6d3c117 Fix the HTTP/2 equivalent of swallowInput
6d3c117 is described below
commit 6d3c117384c11f1bfd9393fb1484cd5a708a8245
Author: Mark Thomas <[email protected]>
AuthorDate: Sun Apr 7 21:39:15 2019 +0100
Fix the HTTP/2 equivalent of swallowInput
When Tomcat writes a final response without reading all of an HTTP/2
request, reset the stream to inform the client that the remaining
request body is not required.
---
java/org/apache/coyote/AbstractProcessor.java | 7 +++++--
java/org/apache/coyote/AbstractProcessorLight.java | 10 +++++++--
.../apache/coyote/http2/LocalStrings.properties | 1 +
java/org/apache/coyote/http2/Stream.java | 2 +-
java/org/apache/coyote/http2/StreamProcessor.java | 24 +++++++++++++++++++++-
webapps/docs/changelog.xml | 5 +++++
6 files changed, 43 insertions(+), 6 deletions(-)
diff --git a/java/org/apache/coyote/AbstractProcessor.java
b/java/org/apache/coyote/AbstractProcessor.java
index 205a789..e7909ba 100644
--- a/java/org/apache/coyote/AbstractProcessor.java
+++ b/java/org/apache/coyote/AbstractProcessor.java
@@ -197,7 +197,7 @@ public abstract class AbstractProcessor extends
AbstractProcessorLight implement
@Override
- public final SocketState dispatch(SocketEvent status) {
+ public final SocketState dispatch(SocketEvent status) throws IOException {
if (status == SocketEvent.OPEN_WRITE && response.getWriteListener() !=
null) {
asyncStateMachine.asyncOperation();
@@ -950,6 +950,9 @@ public abstract class AbstractProcessor extends
AbstractProcessorLight implement
*
* @return The state to return for the socket once the clean-up for the
* current request has completed
+ *
+ * @throws IOException If an I/O error occurs while attempting to end the
+ * request
*/
- protected abstract SocketState dispatchEndRequest();
+ protected abstract SocketState dispatchEndRequest() throws IOException;
}
diff --git a/java/org/apache/coyote/AbstractProcessorLight.java
b/java/org/apache/coyote/AbstractProcessorLight.java
index 340c986..7a46c79 100644
--- a/java/org/apache/coyote/AbstractProcessorLight.java
+++ b/java/org/apache/coyote/AbstractProcessorLight.java
@@ -152,10 +152,16 @@ public abstract class AbstractProcessorLight implements
Processor {
* Uses currently include Servlet 3.0 Async and HTTP upgrade connections.
* Further uses may be added in the future. These will typically start as
* HTTP requests.
+ *
* @param status The event to process
- * @return the socket state
+ *
+ * @return The state the caller should put the socket in when this method
+ * returns
+ *
+ * @throws IOException If an I/O error occurs during the processing of the
+ * request
*/
- protected abstract SocketState dispatch(SocketEvent status);
+ protected abstract SocketState dispatch(SocketEvent status) throws
IOException;
protected abstract SocketState asyncPostProcess();
diff --git a/java/org/apache/coyote/http2/LocalStrings.properties
b/java/org/apache/coyote/http2/LocalStrings.properties
index c948c29..1320e60 100644
--- a/java/org/apache/coyote/http2/LocalStrings.properties
+++ b/java/org/apache/coyote/http2/LocalStrings.properties
@@ -103,6 +103,7 @@ stream.reset.send=Connection [{0}], Stream [{1}], Reset
sent due to [{2}]
stream.trailerHeader.noEndOfStream=Connection [{0}], Stream [{1}], The trailer
headers did not include the end of stream flag
stream.writeTimeout=Timeout waiting for client to increase flow control window
to permit stream data to be written
+streamProcessor.cancel=Connection [{0}], Stream [{1}], The remaining request
body is not required.
streamProcessor.error.connection=Connection [{0}], Stream [{1}], An error
occurred during processing that was fatal to the connection
streamProcessor.error.stream=Connection [{0}], Stream [{1}], An error occurred
during processing that was fatal to the stream
streamProcessor.flushBufferedWrite.entry=Connection [{0}], Stream [{1}],
Flushing buffered writes
diff --git a/java/org/apache/coyote/http2/Stream.java
b/java/org/apache/coyote/http2/Stream.java
index 3e64329..7337eb9 100644
--- a/java/org/apache/coyote/http2/Stream.java
+++ b/java/org/apache/coyote/http2/Stream.java
@@ -676,7 +676,7 @@ class Stream extends AbstractStream implements
HeaderEmitter {
}
- private final boolean isInputFinished() {
+ final boolean isInputFinished() {
return !state.isFrameTypePermitted(FrameType.DATA);
}
diff --git a/java/org/apache/coyote/http2/StreamProcessor.java
b/java/org/apache/coyote/http2/StreamProcessor.java
index 6870926..90bf224 100644
--- a/java/org/apache/coyote/http2/StreamProcessor.java
+++ b/java/org/apache/coyote/http2/StreamProcessor.java
@@ -361,6 +361,13 @@ class StreamProcessor extends AbstractProcessor {
setErrorState(ErrorState.CLOSE_NOW, e);
}
+ if (!isAsync()) {
+ // If this is an async request then the request ends when it has
+ // been completed. The AsyncContext is responsible for calling
+ // endRequest() in that case.
+ endRequest();
+ }
+
if (sendfileState == SendfileState.PENDING) {
return SocketState.SENDFILE;
} else if (getErrorState().isError()) {
@@ -402,7 +409,22 @@ class StreamProcessor extends AbstractProcessor {
@Override
- protected final SocketState dispatchEndRequest() {
+ protected final SocketState dispatchEndRequest() throws IOException {
+ endRequest();
return SocketState.CLOSED;
}
+
+
+ private void endRequest() throws IOException {
+ if (!stream.isInputFinished()) {
+ // The request has been processed but the request body has not been
+ // fully read. This typically occurs when Tomcat rejects an upload
+ // of some form (e.g. PUT or POST). Need to tell the client not to
+ // send any more data.
+ StreamException se = new StreamException(
+ sm.getString("streamProcessor.cancel",
stream.getConnectionId(),
+ stream.getIdentifier()), Http2Error.CANCEL,
stream.getIdAsInt());
+ handler.sendStreamReset(se);
+ }
+ }
}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 7a7601c..ae3d717 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -132,6 +132,11 @@
query string present in the original HTTP/1.1 request is passed to the
HTTP/2 request processing. (markt)
</fix>
+ <fix>
+ When Tomcat writes a final response without reading all of an HTTP/2
+ request, reset the stream to inform the client that the remaining
+ request body is not required. (markt)
+ </fix>
</changelog>
</subsection>
<subsection name="Jasper">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]