Skip to content

Commit ec0ffa2

Browse files
committed
8304963: HttpServer closes connection after processing HEAD after JDK-7026262
Backport-of: 3c4cd50e3cef5905d6c5dacddd6759e118bc50ca
1 parent 9f0f97a commit ec0ffa2

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed

src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ public void sendResponseHeaders (int rCode, long contentLen)
240240
}
241241
noContentToSend = true;
242242
contentLen = 0;
243+
o.setWrappedStream (new FixedLengthOutputStream (this, ros, contentLen));
243244
} else { /* not a HEAD request or 304 response */
244245
if (contentLen == 0) {
245246
if (http10) {
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/**
25+
* @test
26+
* @bug 8304963
27+
* @summary Connection should be reusable after HEAD request
28+
* @library /test/lib
29+
* @run junit HeadKeepAlive
30+
*/
31+
32+
import com.sun.net.httpserver.HttpExchange;
33+
import com.sun.net.httpserver.HttpHandler;
34+
import com.sun.net.httpserver.HttpServer;
35+
import jdk.test.lib.net.URIBuilder;
36+
import org.junit.jupiter.api.Test;
37+
38+
import java.io.IOException;
39+
import java.net.HttpURLConnection;
40+
import java.net.InetAddress;
41+
import java.net.InetSocketAddress;
42+
import java.net.Proxy;
43+
import java.net.URL;
44+
import java.util.logging.Handler;
45+
import java.util.logging.Level;
46+
import java.util.logging.Logger;
47+
import java.util.logging.SimpleFormatter;
48+
import java.util.logging.StreamHandler;
49+
50+
import static org.junit.jupiter.api.Assertions.*;
51+
52+
public class HeadKeepAlive
53+
{
54+
55+
public static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver");
56+
57+
@Test
58+
void test() throws IOException, InterruptedException {
59+
HttpServer httpServer = startHttpServer();
60+
int port = httpServer.getAddress().getPort();
61+
try {
62+
URL url = URIBuilder.newBuilder()
63+
.scheme("http")
64+
.loopback()
65+
.port(port)
66+
.path("/firstCall")
67+
.toURLUnchecked();
68+
HttpURLConnection uc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
69+
uc.setRequestMethod("HEAD");
70+
int responseCode = uc.getResponseCode();
71+
assertEquals(200, responseCode, "First request should succeed");
72+
73+
URL url2 = URIBuilder.newBuilder()
74+
.scheme("http")
75+
.loopback()
76+
.port(port)
77+
.path("/secondCall")
78+
.toURLUnchecked();
79+
HttpURLConnection uc2 = (HttpURLConnection)url2.openConnection(Proxy.NO_PROXY);
80+
uc2.setRequestMethod("HEAD");
81+
responseCode = uc2.getResponseCode();
82+
assertEquals(200, responseCode, "Second request should reuse connection");
83+
} finally {
84+
httpServer.stop(0);
85+
}
86+
}
87+
88+
/**
89+
* Http Server
90+
*/
91+
HttpServer startHttpServer() throws IOException {
92+
Handler outHandler = new StreamHandler(System.out,
93+
new SimpleFormatter());
94+
outHandler.setLevel(Level.FINEST);
95+
LOGGER.setLevel(Level.FINEST);
96+
LOGGER.addHandler(outHandler);
97+
InetAddress loopback = InetAddress.getLoopbackAddress();
98+
HttpServer httpServer = HttpServer.create(new InetSocketAddress(loopback, 0), 0);
99+
httpServer.createContext("/", new MyHandler());
100+
httpServer.start();
101+
return httpServer;
102+
}
103+
104+
class MyHandler implements HttpHandler {
105+
106+
volatile int port1;
107+
@Override
108+
public void handle(HttpExchange t) throws IOException {
109+
String path = t.getRequestURI().getPath();
110+
if (path.equals("/firstCall")) {
111+
port1 = t.getRemoteAddress().getPort();
112+
System.out.println("First connection on client port = " + port1);
113+
// send response
114+
t.sendResponseHeaders(200, -1);
115+
// the connection should still be reusable
116+
} else if (path.equals("/secondCall")) {
117+
int port2 = t.getRemoteAddress().getPort();
118+
System.out.println("Second connection on client port = " + port2);
119+
if (port1 == port2) {
120+
t.sendResponseHeaders(200, -1);
121+
} else {
122+
t.sendResponseHeaders(500, -1);
123+
}
124+
}
125+
t.close();
126+
}
127+
}
128+
}

0 commit comments

Comments
 (0)