Skip to content

Commit 45e8d49

Browse files
committed
backport 06126361db1edb1d4c181a82952c1ac133a839f9
1 parent 8455fa8 commit 45e8d49

File tree

5 files changed

+111
-66
lines changed

5 files changed

+111
-66
lines changed

src/java.net.http/share/classes/jdk/internal/net/http/WindowUpdateSender.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -115,18 +115,24 @@ abstract class WindowUpdateSender {
115115
* the caller wants to buffer.
116116
*/
117117
boolean canBufferUnprocessedBytes(int len) {
118-
return !checkWindowSizeExceeded(unprocessed.addAndGet(len));
118+
long buffered, processed;
119+
// get received before unprocessed in order to avoid counting
120+
// unprocessed bytes that might get unbuffered asynchronously
121+
// twice.
122+
processed = received.get();
123+
buffered = unprocessed.addAndGet(len);
124+
return !checkWindowSizeExceeded(processed, buffered);
119125
}
120126

121127
// adds the provided amount to the amount of already
122-
// received and processed bytes and checks whether the
128+
// processed and processed bytes and checks whether the
123129
// flow control window is exceeded. If so, take
124130
// corrective actions and return true.
125-
private boolean checkWindowSizeExceeded(long len) {
131+
private boolean checkWindowSizeExceeded(long processed, long len) {
126132
// because windowSize is bound by Integer.MAX_VALUE
127133
// we will never reach the point where received.get() + len
128134
// could overflow
129-
long rcv = received.get() + len;
135+
long rcv = processed + len;
130136
return rcv > windowSize && windowSizeExceeded(rcv);
131137
}
132138

@@ -141,6 +147,7 @@ private boolean checkWindowSizeExceeded(long len) {
141147
* @param delta the amount of processed bytes to release
142148
*/
143149
void processed(int delta) {
150+
assert delta >= 0 : delta;
144151
long rest = unprocessed.addAndGet(-delta);
145152
assert rest >= 0;
146153
update(delta);
@@ -164,6 +171,7 @@ void processed(int delta) {
164171
* @return the amount of remaining unprocessed bytes
165172
*/
166173
long released(int delta) {
174+
assert delta >= 0 : delta;
167175
long rest = unprocessed.addAndGet(-delta);
168176
assert rest >= 0;
169177
return rest;
@@ -192,7 +200,7 @@ void update(int delta) {
192200
synchronized (this) {
193201
int tosend = (int)Math.min(received.get(), Integer.MAX_VALUE);
194202
if (tosend > limit) {
195-
received.getAndAdd(-tosend);
203+
received.addAndGet(-tosend);
196204
sendWindowUpdate(tosend);
197205
}
198206
}

test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -35,6 +35,7 @@
3535

3636
import java.io.IOException;
3737
import java.io.InputStream;
38+
import java.io.InterruptedIOException;
3839
import java.io.OutputStream;
3940
import java.net.ProtocolException;
4041
import java.net.URI;
@@ -357,7 +358,9 @@ public void handle(Http2TestExchange t) throws IOException {
357358
// to wait for the connection window
358359
fct.conn.obtainConnectionWindow(resp.length);
359360
} catch (InterruptedException ie) {
360-
// ignore and continue...
361+
var ioe = new InterruptedIOException(ie.toString());
362+
ioe.initCause(ie);
363+
throw ioe;
361364
}
362365
}
363366
try {
@@ -366,6 +369,7 @@ public void handle(Http2TestExchange t) throws IOException {
366369
if (t instanceof FCHttp2TestExchange fct) {
367370
fct.conn.updateConnectionWindow(resp.length);
368371
}
372+
throw x;
369373
}
370374
}
371375
} finally {

test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -239,7 +239,7 @@ public static abstract class HttpTestExchange implements AutoCloseable {
239239
public abstract OutputStream getResponseBody();
240240
public abstract HttpTestRequestHeaders getRequestHeaders();
241241
public abstract HttpTestResponseHeaders getResponseHeaders();
242-
public abstract void sendResponseHeaders(int code, int contentLength) throws IOException;
242+
public abstract void sendResponseHeaders(int code, long contentLength) throws IOException;
243243
public abstract URI getRequestURI();
244244
public abstract String getRequestMethod();
245245
public abstract void close();
@@ -292,7 +292,7 @@ public HttpTestResponseHeaders getResponseHeaders() {
292292
return HttpTestResponseHeaders.of(exchange.getResponseHeaders());
293293
}
294294
@Override
295-
public void sendResponseHeaders(int code, int contentLength) throws IOException {
295+
public void sendResponseHeaders(int code, long contentLength) throws IOException {
296296
if (contentLength == 0) contentLength = -1;
297297
else if (contentLength < 0) contentLength = 0;
298298
exchange.sendResponseHeaders(code, contentLength);
@@ -355,7 +355,7 @@ public HttpTestResponseHeaders getResponseHeaders() {
355355
return HttpTestResponseHeaders.of(exchange.getResponseHeaders());
356356
}
357357
@Override
358-
public void sendResponseHeaders(int code, int contentLength) throws IOException {
358+
public void sendResponseHeaders(int code, long contentLength) throws IOException {
359359
if (contentLength == 0) contentLength = -1;
360360
else if (contentLength < 0) contentLength = 0;
361361
exchange.sendResponseHeaders(code, contentLength);

test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/BodyOutputStream.java

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -63,22 +63,28 @@ synchronized void updateWindow(int update) {
6363
}
6464

6565
void waitForWindow(int demand) throws InterruptedException {
66-
// first wait for the connection window
67-
conn.obtainConnectionWindow(demand);
68-
// now wait for the stream window
66+
// first wait for the stream window
6967
waitForStreamWindow(demand);
68+
// now wait for the connection window
69+
conn.obtainConnectionWindow(demand);
7070
}
7171

72-
public void waitForStreamWindow(int demand) throws InterruptedException {
73-
synchronized (this) {
74-
while (demand > 0) {
75-
int n = Math.min(demand, window);
76-
demand -= n;
77-
window -= n;
78-
if (demand > 0) {
79-
wait();
72+
public void waitForStreamWindow(int amount) throws InterruptedException {
73+
int demand = amount;
74+
try {
75+
synchronized (this) {
76+
while (amount > 0) {
77+
int n = Math.min(amount, window);
78+
amount -= n;
79+
window -= n;
80+
if (amount > 0) {
81+
wait();
82+
}
8083
}
8184
}
85+
} catch (Throwable t) {
86+
window += (demand - amount);
87+
throw t;
8288
}
8389
}
8490

0 commit comments

Comments
 (0)