On 08/04/2019 09:57, Rémy Maucherat wrote:
> On Sun, Apr 7, 2019 at 10:42 PM <ma...@apache.org> wrote:
> 
>> 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 <ma...@apache.org>
>> 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.
>>
> 
> After this change, I do get this CI failure "reliably":
> https://ci.apache.org/projects/tomcat/tomcat9/logs/4183/TEST-org.apache.coyote.http2.TestHttp2Section_6_8.NIO2.txt
> 
> Unsure if this is relatively normal or a bug.

I saw that failure but couldn't reproduce it locally. I'll take another
look.

Mark


> 
> Rémy
> 
> 
>> ---
>>  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: dev-unsubscr...@tomcat.apache.org
>> For additional commands, e-mail: dev-h...@tomcat.apache.org
>>
>>
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to