From bf39a3a9199d66d53dd6fdf25c068f51239535c1 Mon Sep 17 00:00:00 2001 From: Flavia Rainone Date: Thu, 10 Feb 2022 00:07:40 -0300 Subject: [PATCH] [UNDERTOW-2034] At Http2StreamSinkChannel.awaitWritable, wait for flow control window update if there is timeout available before throwing no window update IOException --- .../http2/Http2StreamSinkChannel.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/io/undertow/protocols/http2/Http2StreamSinkChannel.java b/core/src/main/java/io/undertow/protocols/http2/Http2StreamSinkChannel.java index 911709df1f..b64d7d3a3b 100644 --- a/core/src/main/java/io/undertow/protocols/http2/Http2StreamSinkChannel.java +++ b/core/src/main/java/io/undertow/protocols/http2/Http2StreamSinkChannel.java @@ -19,6 +19,7 @@ package io.undertow.protocols.http2; import java.io.IOException; +import java.io.InterruptedIOException; import java.nio.ByteBuffer; import io.undertow.UndertowMessages; @@ -27,7 +28,10 @@ import org.xnio.IoUtils; /** + * Stream sink channel used for HTTP2 communication. + * * @author Stuart Douglas + * @author Flavia Rainone */ public abstract class Http2StreamSinkChannel extends AbstractHttp2StreamSinkChannel { @@ -118,8 +122,11 @@ protected int grabFlowControlBytes(int toSend) { int newWindowSize = this.getChannel().getInitialSendWindowSize(); int settingsDelta = newWindowSize - this.initialWindowSize; //first adjust for any settings frame updates - this.initialWindowSize = newWindowSize; - this.flowControlWindow += settingsDelta; + if (settingsDelta != 0) { + this.initialWindowSize = newWindowSize; + this.flowControlWindow += settingsDelta; + flowControlLock.notifyAll(); + } int min = Math.min(toSend, this.flowControlWindow); int actualBytes = this.getChannel().grabFlowControlBytes(min); @@ -140,6 +147,7 @@ void updateFlowControlWindow(final int delta) throws IOException { return; } flowControlWindow += delta; + flowControlLock.notifyAll(); } if (exhausted) { getChannel().notifyFlowControlAllowed(); @@ -183,9 +191,22 @@ public void awaitWritable() throws IOException { synchronized (flowControlLock) { flowControlWindow = this.flowControlWindow; } + long initialTime = System.nanoTime(); super.awaitWritable(); synchronized (flowControlLock) { if (isReadyForFlush() && flowControlWindow <= 0 && flowControlWindow == this.flowControlWindow) { + final long timeout = getAwaitWritableTimeout(); + long remainingTimeout; + while ((remainingTimeout = timeout * 1_000_000 - (System.nanoTime() - initialTime)) > 0) { + try { + flowControlLock.wait(remainingTimeout/ 1_000_000, (int) (remainingTimeout % 1_000_000)); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new InterruptedIOException(); + } + if (flowControlWindow != this.flowControlWindow) + return; + } throw UndertowMessages.MESSAGES.noWindowUpdate(getAwaitWritableTimeout()); } }