Mark Slater created HTTPCLIENT-2352:
---------------------------------------

             Summary: Race condition causing java.lang.ArithmeticException: 
Update causes flow control window to exceed 2147483647
                 Key: HTTPCLIENT-2352
                 URL: https://issues.apache.org/jira/browse/HTTPCLIENT-2352
             Project: HttpComponents HttpClient
          Issue Type: Bug
          Components: HttpClient (async)
    Affects Versions: 5.3.1
            Reporter: Mark Slater


I’m getting {{java.lang.ArithmeticException: Update causes flow control window 
to exceed 2147483647}} intermittently when making HTTP/2 requests using HTTP 
Client 5.3.1 as the engine for the [Ktor HTTP Client 
3.0.3|https://github.com/ktorio/ktor/tree/3.0.3].  It occurs in about 10% of 
requests to some addresses from my desktop.

I’ve found what seems to be a race condition that appears to be the root cause 
of the problem in 
{{[org.apache.hc.core5.http2.impl.nio.AbstractH2StreamMultiplexer|https://github.com/apache/httpcomponents-core/blob/rel/v5.2.4/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java]}}
 (version 5.2.4 is used by this version of HTTP Client).

This is the stack trace I get:
{code:java}
Caused by: java.lang.ArithmeticException: Update causes flow control window to 
exceed 2147483647
     at 
org.apache.hc.core5.http2.impl.nio.AbstractH2StreamMultiplexer.updateWindow(AbstractH2StreamMultiplexer.java:215)
     at 
org.apache.hc.core5.http2.impl.nio.AbstractH2StreamMultiplexer.updateInputWindow(AbstractH2StreamMultiplexer.java:225)
     at 
org.apache.hc.core5.http2.impl.nio.AbstractH2StreamMultiplexer.incrementInputCapacity(AbstractH2StreamMultiplexer.java:385)
     at 
org.apache.hc.core5.http2.impl.nio.AbstractH2StreamMultiplexer.access$1200(AbstractH2StreamMultiplexer.java:94)
     at 
org.apache.hc.core5.http2.impl.nio.AbstractH2StreamMultiplexer$H2StreamChannelImpl.update(AbstractH2StreamMultiplexer.java:1448)
     at 
io.ktor.client.engine.apache5.ApacheResponseConsumer.updateCapacity(ApacheResponseConsumer.kt:131)
     at 
io.ktor.client.engine.apache5.BasicResponseConsumer.updateCapacity(ApacheResponseConsumer.kt:54)
     at 
org.apache.hc.client5.http.impl.async.HttpAsyncMainClientExec$1.updateCapacity(HttpAsyncMainClientExec.java:233)
     at 
org.apache.hc.core5.http2.impl.nio.ClientH2StreamHandler.updateInputCapacity(ClientH2StreamHandler.java:226)
     at 
org.apache.hc.core5.http2.impl.nio.AbstractH2StreamMultiplexer$H2Stream.produceInputCapacityUpdate(AbstractH2StreamMultiplexer.java:1662)
     at 
org.apache.hc.core5.http2.impl.nio.AbstractH2StreamMultiplexer.consumeDataFrame(AbstractH2StreamMultiplexer.java:1030)
     at 
org.apache.hc.core5.http2.impl.nio.AbstractH2StreamMultiplexer.consumeFrame(AbstractH2StreamMultiplexer.java:735)
     at 
org.apache.hc.core5.http2.impl.nio.AbstractH2StreamMultiplexer.onInput(AbstractH2StreamMultiplexer.java:446)
     at 
org.apache.hc.core5.http2.impl.nio.AbstractH2IOEventHandler.inputReady(AbstractH2IOEventHandler.java:65)
     at 
org.apache.hc.core5.http2.impl.nio.ClientH2IOEventHandler.inputReady(ClientH2IOEventHandler.java:39)
     at 
org.apache.hc.core5.reactor.ssl.SSLIOSession.decryptData(SSLIOSession.java:609)
     at 
org.apache.hc.core5.reactor.ssl.SSLIOSession.access$200(SSLIOSession.java:74)
     at 
org.apache.hc.core5.reactor.ssl.SSLIOSession$1.inputReady(SSLIOSession.java:202)
     at 
org.apache.hc.core5.reactor.InternalDataChannel.onIOEvent(InternalDataChannel.java:142)
     at 
org.apache.hc.core5.reactor.InternalChannel.handleIOEvent(InternalChannel.java:51)
     ... 5 more
{code}
The problem is in the 
{{[updateWindow|https://github.com/apache/httpcomponents-core/blob/rel/v5.2.4/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java#L202]}}
 method, which attempts to adjust the flow control window by a delta computed 
previously.  The method caters for the window size changing concurrently with 
the computation and validation of the new size by aborting and retrying 
conflicted calls.  However, it doesn’t cater for the consequences of 
out-of-order deltas.

On connect, the size of {{connInputWindow}} is increased by the 
{{[maximizeConnWindow|https://github.com/apache/httpcomponents-core/blob/rel/v5.2.4/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java#L1049]}}
 method to {{{}Integer.MAX_VALUE{}}}, the largest permitted size.  As data is 
consumed and received, the 
{{[updateWindow|https://github.com/apache/httpcomponents-core/blob/rel/v5.2.4/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java#L202]}}
 method is called with positive and negative deltas to reflect the changes in 
available capacity.  However, the order in which these updates are applied is 
not guaranteed.  If a negative delta due to the receipt of data is applied 
after the positive delta due to some of that data being consumed, the window 
size will be increased beyond {{Integer.MAX_VALUE,}} and 
{{ArithmeticException}} will be thrown.

It would be possible to mitigate this somewhat (perhaps entirely) if 
{{[maximizeConnWindow|https://github.com/apache/httpcomponents-core/blob/rel/v5.2.4/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java#L1049]}}
  could be configured to use a maximum size somewhat less than 
{{{}Integer.MAX_VALUE{}}}, but I’m not familiar enough with HTTP/2 to know if 
this would have wider consequences.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

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

Reply via email to