Skip to content
Permalink
Browse files

Expand HTTP/2 timeout handling to connection window exhaustion on write.

  • Loading branch information...
markt-asf committed Apr 30, 2019
1 parent 5b9399d commit 0bcd69c9dd8ae0ff424f2cd46de51583510b7f35
@@ -805,7 +805,26 @@ int reserveWindowSize(Stream stream, int reservation, boolean block) throws IOEx
if (allocation == 0) {
if (block) {
try {
stream.wait();
// Connection level window is empty. Although this
// request is for a stream, use the connection
// timeout
long writeTimeout = protocol.getWriteTimeout();
if (writeTimeout < 0) {
stream.wait();
} else {
stream.wait(writeTimeout);
}
// Has this stream been granted an allocation
int[] value = backLogStreams.get(stream);
if (value[1] == 0) {
// No allocation
// Close the connection. Do this first since
// closing the stream will raise an exception
close();
// Close the stream (in app code so need to
// signal to app stream is closing)
stream.doWriteTimeout();
}
} catch (InterruptedException e) {
throw new IOException(sm.getString(
"upgradeHandler.windowSizeReservationInterrupted", connectionId,
@@ -1023,11 +1042,20 @@ private Stream createLocalStream(Request request) {


private void close() {
connectionState.set(ConnectionState.CLOSED);
ConnectionState previous = connectionState.getAndSet(ConnectionState.CLOSED);
if (previous == ConnectionState.CLOSED) {
// Already closed
return;
}

for (Stream stream : streams.values()) {
// The connection is closing. Close the associated streams as no
// longer required.
stream.receiveReset(Http2Error.CANCEL.getCode());
// Release any streams waiting for an allocation
synchronized (stream) {
stream.notifyAll();
}
}
try {
socketWrapper.close();
@@ -280,17 +280,7 @@ private synchronized int reserveWindowSize(int reservation, boolean block) throw
}
windowSize = getWindowSize();
if (windowSize == 0) {
String msg = sm.getString("stream.writeTimeout");
StreamException se = new StreamException(
msg, Http2Error.ENHANCE_YOUR_CALM, getIdAsInt());
// Prevent the application making further writes
streamOutputBuffer.closed = true;
// Prevent Tomcat's error handling trying to write
coyoteResponse.setError();
coyoteResponse.setErrorReported();
// Trigger a reset once control returns to Tomcat
streamOutputBuffer.reset = se;
throw new CloseNowException(msg, se);
doWriteTimeout();
}
} catch (InterruptedException e) {
// Possible shutdown / rst or similar. Use an IOException to
@@ -313,6 +303,21 @@ private synchronized int reserveWindowSize(int reservation, boolean block) throw
}


void doWriteTimeout() throws CloseNowException {
String msg = sm.getString("stream.writeTimeout");
StreamException se = new StreamException(
msg, Http2Error.ENHANCE_YOUR_CALM, getIdAsInt());
// Prevent the application making further writes
streamOutputBuffer.closed = true;
// Prevent Tomcat's error handling trying to write
coyoteResponse.setError();
coyoteResponse.setErrorReported();
// Trigger a reset once control returns to Tomcat
streamOutputBuffer.reset = se;
throw new CloseNowException(msg, se);
}


@Override
@Deprecated
protected synchronized void doNotifyAll() {
@@ -113,6 +113,10 @@
Refactor Hostname validation to improve performance. Patch provided by
Uwe Hees. (markt)
</scode>
<fix>
Expand HTTP/2 timeout handling to include connection window exhaustion
on write. (markt)
</fix>
</changelog>
</subsection>
<subsection name="Other">

0 comments on commit 0bcd69c

Please sign in to comment.
You can’t perform that action at this time.