Skip to content

Commit ef27cae

Browse files
committed
8307648: java/net/httpclient/ExpectContinueTest.java timed out
Reviewed-by: rschmelter Backport-of: 04b0e785f6b9b4629b77bb19f2b072434be4951c
1 parent 2927a67 commit ef27cae

File tree

3 files changed

+63
-9
lines changed

3 files changed

+63
-9
lines changed

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

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ void incoming(Http2Frame frame) throws IOException {
475475
if ((frame instanceof HeaderFrame hf)) {
476476
if (hf.endHeaders()) {
477477
Log.logTrace("handling response (streamid={0})", streamid);
478-
handleResponse();
478+
handleResponse(hf);
479479
}
480480
if (hf.getFlag(HeaderFrame.END_STREAM)) {
481481
if (debug.on()) debug.log("handling END_STREAM: %d", streamid);
@@ -523,7 +523,7 @@ String checkInterimResponseCountExceeded() {
523523
return null;
524524
}
525525

526-
protected void handleResponse() throws IOException {
526+
protected void handleResponse(HeaderFrame hf) throws IOException {
527527
HttpHeaders responseHeaders = responseHeadersBuilder.build();
528528

529529
if (!finalResponseCodeReceived) {
@@ -543,6 +543,14 @@ protected void handleResponse() throws IOException {
543543
// If informational code, response is partially complete
544544
if (responseCode < 100 || responseCode > 199) {
545545
this.finalResponseCodeReceived = true;
546+
} else if (hf.getFlag(HeaderFrame.END_STREAM)) {
547+
// see RFC 9113 section 8.1:
548+
// A HEADERS frame with the END_STREAM flag set that carries an
549+
// informational status code is malformed
550+
protocolErrorMsg = String.format(
551+
"Stream %s PROTOCOL_ERROR: " +
552+
"HEADERS frame with status %s has END_STREAM flag set",
553+
streamid, responseCode);
546554
} else {
547555
protocolErrorMsg = checkInterimResponseCountExceeded();
548556
}
@@ -610,12 +618,20 @@ void incoming_reset(ResetFrame frame) {
610618
// response to be read before the Reset is handled in the case where the client's
611619
// input stream is partially consumed or not consumed at all by the server.
612620
if (frame.getErrorCode() != ResetFrame.NO_ERROR) {
621+
if (debug.on()) {
622+
debug.log("completing requestBodyCF exceptionally due to received" +
623+
" RESET(%s) (stream=%s)", frame.getErrorCode(), streamid);
624+
}
613625
requestBodyCF.completeExceptionally(new IOException("RST_STREAM received"));
614626
} else {
627+
if (debug.on()) {
628+
debug.log("completing requestBodyCF normally due to received" +
629+
" RESET(NO_ERROR) (stream=%s)", streamid);
630+
}
615631
requestBodyCF.complete(null);
616632
}
617633
}
618-
if (response == null && subscriber == null) {
634+
if ((response == null || !finalResponseCodeReceived) && subscriber == null) {
619635
// we haven't received the headers yet, and won't receive any!
620636
// handle reset now.
621637
handleReset(frame, null);
@@ -1009,6 +1025,10 @@ public void onNext(ByteBuffer item) {
10091025
private void onNextImpl(ByteBuffer item) {
10101026
// Got some more request body bytes to send.
10111027
if (requestBodyCF.isDone()) {
1028+
if (debug.on()) {
1029+
debug.log("RequestSubscriber: requestBodyCf is done: " +
1030+
"cancelling subscription");
1031+
}
10121032
// stream already cancelled, probably in timeout
10131033
sendScheduler.stop();
10141034
subscription.cancel();
@@ -1568,7 +1588,7 @@ void completeResponseExceptionally(Throwable t) {
15681588

15691589
// create and return the PushResponseImpl
15701590
@Override
1571-
protected void handleResponse() {
1591+
protected void handleResponse(HeaderFrame hf) {
15721592
HttpHeaders responseHeaders = responseHeadersBuilder.build();
15731593

15741594
if (!finalPushResponseCodeReceived) {

test/jdk/java/net/httpclient/ExpectContinueTest.java

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
* @summary Tests that when the httpclient sends a 100 Expect Continue header and receives
2929
* a response code of 417 Expectation Failed, that the client does not hang
3030
* indefinitely and closes the connection.
31-
* @bug 8286171
31+
* @bug 8286171 8307648
3232
* @library /test/lib /test/jdk/java/net/httpclient/lib
3333
* @build jdk.httpclient.test.lib.common.HttpServerAdapters
3434
* @run testng/othervm ExpectContinueTest
@@ -58,6 +58,7 @@
5858
import java.net.Socket;
5959
import java.net.URI;
6060
import java.net.http.HttpClient;
61+
import java.net.http.HttpClient.Builder;
6162
import java.net.http.HttpRequest;
6263
import java.net.http.HttpResponse;
6364
import java.util.StringTokenizer;
@@ -109,6 +110,10 @@ public void setup() throws Exception {
109110
h2postUri = URI.create("http://" + http2TestServer.serverAuthority() + "/http2/post");
110111
h2hangUri = URI.create("http://" + http2TestServer.serverAuthority() + "/http2/hang");
111112

113+
System.out.println("HTTP/1.1 server listening at: " + http1TestServer.serverAuthority());
114+
System.out.println("HTTP/1.1 hang server listening at: " + hangUri.getRawAuthority());
115+
System.out.println("HTTP/2 clear server listening at: " + http2TestServer.serverAuthority());
116+
112117
http1TestServer.start();
113118
http1HangServer.start();
114119
http2TestServer.start();
@@ -127,8 +132,10 @@ static class GetHandler implements HttpTestHandler {
127132
public void handle(HttpTestExchange exchange) throws IOException {
128133
try (InputStream is = exchange.getRequestBody();
129134
OutputStream os = exchange.getResponseBody()) {
135+
System.err.println("Server reading body");
130136
is.readAllBytes();
131137
byte[] bytes = "RESPONSE_BODY".getBytes(UTF_8);
138+
System.err.println("Server sending 200 (length="+bytes.length+")");
132139
exchange.sendResponseHeaders(200, bytes.length);
133140
os.write(bytes);
134141
}
@@ -142,13 +149,16 @@ public void handle(HttpTestExchange exchange) throws IOException {
142149
// Http1 server has already sent 100 response at this point but not Http2 server
143150
if (exchange.getExchangeVersion().equals(HttpClient.Version.HTTP_2)) {
144151
// Send 100 Headers, tell client that we're ready for body
152+
System.err.println("Server sending 100 (length = 0)");
145153
exchange.sendResponseHeaders(100, 0);
146154
}
147155

148156
// Read body from client and acknowledge with 200
149157
try (InputStream is = exchange.getRequestBody();
150158
OutputStream os = exchange.getResponseBody()) {
159+
System.err.println("Server reading body");
151160
is.readAllBytes();
161+
System.err.println("Server send 200 (length=0)");
152162
exchange.sendResponseHeaders(200, 0);
153163
}
154164
}
@@ -162,6 +172,7 @@ public void handle(HttpTestExchange exchange) throws IOException {
162172
try (InputStream is = exchange.getRequestBody();
163173
OutputStream os = exchange.getResponseBody()) {
164174
byte[] bytes = EXPECTATION_FAILED_417.getBytes();
175+
System.err.println("Server send 417 (length="+bytes.length+")");
165176
exchange.sendResponseHeaders(417, bytes.length);
166177
os.write(bytes);
167178
}
@@ -187,11 +198,14 @@ static class Http1HangServer extends Thread implements Closeable {
187198
public void run() {
188199
byte[] bytes = EXPECTATION_FAILED_417.getBytes();
189200

201+
boolean closed = this.closed;
190202
while (!closed) {
191203
try {
192204
// Not using try with resources here as we expect the client to close resources when
193205
// 417 is received
194-
client = ss.accept();
206+
System.err.println("Http1HangServer accepting connections");
207+
var client = this.client = ss.accept();
208+
System.err.println("Http1HangServer accepted connection: " + client);
195209
InputStream is = client.getInputStream();
196210
OutputStream os = client.getOutputStream();
197211

@@ -216,7 +230,8 @@ public void run() {
216230
&& version.equals("HTTP/1.1");
217231
// If correct request, send 417 reply. Otherwise, wait for correct one
218232
if (validRequest) {
219-
closed = true;
233+
System.err.println("Http1HangServer sending 417");
234+
closed = this.closed = true;
220235
response.append("HTTP/1.1 417 Expectation Failed\r\n")
221236
.append("Content-Length: ")
222237
.append(0)
@@ -227,17 +242,25 @@ public void run() {
227242
os.write(bytes);
228243
os.flush();
229244
} else {
245+
System.err.println("Http1HangServer received invalid request: closing");
230246
client.close();
231247
}
232248
} catch (IOException e) {
233-
closed = true;
249+
closed = this.closed = true;
234250
e.printStackTrace();
251+
} finally {
252+
if (closed = this.closed) {
253+
System.err.println("Http1HangServer: finished");
254+
} else {
255+
System.err.println("Http1HangServer: looping for accepting next connection");
256+
}
235257
}
236258
}
237259
}
238260

239261
@Override
240262
public void close() throws IOException {
263+
var client = this.client;
241264
if (client != null) client.close();
242265
if (ss != null) ss.close();
243266
}
@@ -247,13 +270,15 @@ public void close() throws IOException {
247270
public Object[][] urisData() {
248271
return new Object[][]{
249272
{ getUri, postUri, hangUri, HTTP_1_1 },
250-
{ h2getUri, h2postUri, h2hangUri, HttpClient.Version.HTTP_2 }
273+
{ h2getUri, h2postUri, h2hangUri, HTTP_2 }
251274
};
252275
}
253276

254277
@Test(dataProvider = "uris")
255278
public void test(URI getUri, URI postUri, URI hangUri, HttpClient.Version version) throws IOException, InterruptedException {
279+
System.out.println("Testing with version: " + version);
256280
HttpClient client = HttpClient.newBuilder()
281+
.proxy(Builder.NO_PROXY)
257282
.version(version)
258283
.build();
259284

@@ -271,18 +296,24 @@ public void test(URI getUri, URI postUri, URI hangUri, HttpClient.Version versio
271296
.expectContinue(true)
272297
.build();
273298

299+
System.out.printf("Sending request (%s): %s%n", version, getRequest);
300+
System.err.println("Sending request: " + getRequest);
274301
CompletableFuture<HttpResponse<String>> cf = client.sendAsync(getRequest, HttpResponse.BodyHandlers.ofString());
275302
HttpResponse<String> resp = cf.join();
276303
System.err.println("Response Headers: " + resp.headers());
277304
System.err.println("Response Status Code: " + resp.statusCode());
278305
assertEquals(resp.statusCode(), 200);
279306

307+
System.out.printf("Sending request (%s): %s%n", version, postRequest);
308+
System.err.println("Sending request: " + postRequest);
280309
cf = client.sendAsync(postRequest, HttpResponse.BodyHandlers.ofString());
281310
resp = cf.join();
282311
System.err.println("Response Headers: " + resp.headers());
283312
System.err.println("Response Status Code: " + resp.statusCode());
284313
assertEquals(resp.statusCode(), 200);
285314

315+
System.out.printf("Sending request (%s): %s%n", version, hangRequest);
316+
System.err.println("Sending request: " + hangRequest);
286317
cf = client.sendAsync(hangRequest, HttpResponse.BodyHandlers.ofString());
287318
resp = cf.join();
288319
System.err.println("Response Headers: " + resp.headers());

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ public void sendResponseHeaders(int rCode, long responseLength) throws IOExcepti
140140
public void sendResponseHeaders(int rCode, long responseLength,
141141
BiPredicate<CharSequence, CharSequence> insertionPolicy)
142142
throws IOException {
143+
// Do not set Content-Length for 100, and do not set END_STREAM
144+
if (rCode == 100) responseLength = 0;
145+
143146
this.responseLength = responseLength;
144147
if (responseLength !=0 && rCode != 204 && !isHeadRequest()) {
145148
long clen = responseLength > 0 ? responseLength : 0;

0 commit comments

Comments
 (0)