Skip to content

Commit 0bcd69c

Browse files
committed
Expand HTTP/2 timeout handling to connection window exhaustion on write.
1 parent 5b9399d commit 0bcd69c

File tree

3 files changed

+50
-13
lines changed

3 files changed

+50
-13
lines changed

java/org/apache/coyote/http2/Http2UpgradeHandler.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,26 @@ int reserveWindowSize(Stream stream, int reservation, boolean block) throws IOEx
805805
if (allocation == 0) {
806806
if (block) {
807807
try {
808-
stream.wait();
808+
// Connection level window is empty. Although this
809+
// request is for a stream, use the connection
810+
// timeout
811+
long writeTimeout = protocol.getWriteTimeout();
812+
if (writeTimeout < 0) {
813+
stream.wait();
814+
} else {
815+
stream.wait(writeTimeout);
816+
}
817+
// Has this stream been granted an allocation
818+
int[] value = backLogStreams.get(stream);
819+
if (value[1] == 0) {
820+
// No allocation
821+
// Close the connection. Do this first since
822+
// closing the stream will raise an exception
823+
close();
824+
// Close the stream (in app code so need to
825+
// signal to app stream is closing)
826+
stream.doWriteTimeout();
827+
}
809828
} catch (InterruptedException e) {
810829
throw new IOException(sm.getString(
811830
"upgradeHandler.windowSizeReservationInterrupted", connectionId,
@@ -1023,11 +1042,20 @@ private Stream createLocalStream(Request request) {
10231042

10241043

10251044
private void close() {
1026-
connectionState.set(ConnectionState.CLOSED);
1045+
ConnectionState previous = connectionState.getAndSet(ConnectionState.CLOSED);
1046+
if (previous == ConnectionState.CLOSED) {
1047+
// Already closed
1048+
return;
1049+
}
1050+
10271051
for (Stream stream : streams.values()) {
10281052
// The connection is closing. Close the associated streams as no
10291053
// longer required.
10301054
stream.receiveReset(Http2Error.CANCEL.getCode());
1055+
// Release any streams waiting for an allocation
1056+
synchronized (stream) {
1057+
stream.notifyAll();
1058+
}
10311059
}
10321060
try {
10331061
socketWrapper.close();

java/org/apache/coyote/http2/Stream.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -280,17 +280,7 @@ private synchronized int reserveWindowSize(int reservation, boolean block) throw
280280
}
281281
windowSize = getWindowSize();
282282
if (windowSize == 0) {
283-
String msg = sm.getString("stream.writeTimeout");
284-
StreamException se = new StreamException(
285-
msg, Http2Error.ENHANCE_YOUR_CALM, getIdAsInt());
286-
// Prevent the application making further writes
287-
streamOutputBuffer.closed = true;
288-
// Prevent Tomcat's error handling trying to write
289-
coyoteResponse.setError();
290-
coyoteResponse.setErrorReported();
291-
// Trigger a reset once control returns to Tomcat
292-
streamOutputBuffer.reset = se;
293-
throw new CloseNowException(msg, se);
283+
doWriteTimeout();
294284
}
295285
} catch (InterruptedException e) {
296286
// Possible shutdown / rst or similar. Use an IOException to
@@ -313,6 +303,21 @@ private synchronized int reserveWindowSize(int reservation, boolean block) throw
313303
}
314304

315305

306+
void doWriteTimeout() throws CloseNowException {
307+
String msg = sm.getString("stream.writeTimeout");
308+
StreamException se = new StreamException(
309+
msg, Http2Error.ENHANCE_YOUR_CALM, getIdAsInt());
310+
// Prevent the application making further writes
311+
streamOutputBuffer.closed = true;
312+
// Prevent Tomcat's error handling trying to write
313+
coyoteResponse.setError();
314+
coyoteResponse.setErrorReported();
315+
// Trigger a reset once control returns to Tomcat
316+
streamOutputBuffer.reset = se;
317+
throw new CloseNowException(msg, se);
318+
}
319+
320+
316321
@Override
317322
@Deprecated
318323
protected synchronized void doNotifyAll() {

webapps/docs/changelog.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@
113113
Refactor Hostname validation to improve performance. Patch provided by
114114
Uwe Hees. (markt)
115115
</scode>
116+
<fix>
117+
Expand HTTP/2 timeout handling to include connection window exhaustion
118+
on write. (markt)
119+
</fix>
116120
</changelog>
117121
</subsection>
118122
<subsection name="Other">

0 commit comments

Comments
 (0)