undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,277 @@
/*
* Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6725892
* @library /test/lib
* @run main/othervm -Dsun.net.httpserver.maxReqTime=2 -Dsun.net.httpserver.clockTick=2000 Test
* @run main/othervm -Djava.net.preferIPv6Addresses=true -Dsun.net.httpserver.maxReqTime=2 -Dsun.net.httpserver.clockTick=2000 Test
* @summary
*/
import com.sun.net.httpserver.*;
import java.util.concurrent.*;
import java.util.logging.*;
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
import jdk.test.lib.net.URIBuilder;
public class Test {
static HttpServer s1;
static int port;
static URL url;
static final String RESPONSE_BODY = "response";
static boolean failed = false;
static class Handler implements HttpHandler {
public void handle(HttpExchange t)
throws IOException
{
InputStream is = t.getRequestBody();
InetSocketAddress rem = t.getRemoteAddress();
System.out.println("Request from: " + rem);
while (is.read () != -1) ;
is.close();
String requrl = t.getRequestURI().toString();
OutputStream os = t.getResponseBody();
t.sendResponseHeaders(200, RESPONSE_BODY.length());
os.write(RESPONSE_BODY.getBytes());
t.close();
}
}
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
InetAddress loopback = InetAddress.getLoopbackAddress();
try {
InetSocketAddress addr = new InetSocketAddress(loopback, 0);
s1 = HttpServer.create(addr, 100);
HttpHandler h = new Handler();
HttpContext c1 = s1.createContext("/", h);
s1.setExecutor(exec);
s1.start();
port = s1.getAddress().getPort();
System.out.println("Server on port " + port);
url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/foo")
.toURLUnchecked();
System.out.println("URL: " + url);
test1();
test2();
test3();
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
System.out.println("FAIL");
throw new RuntimeException();
} finally {
s1.stop(0);
System.out.println("After Shutdown");
exec.shutdown();
}
}
// open TCP connection without sending anything. Check server closes it.
static void test1() throws IOException {
failed = false;
Socket s = new Socket(InetAddress.getLoopbackAddress(), port);
InputStream is = s.getInputStream();
// server should close connection after 2 seconds. We wait up to 10
s.setSoTimeout(10000);
try {
is.read();
} catch (SocketTimeoutException e) {
failed = true;
}
s.close();
if (failed) {
System.out.println("test1: FAIL");
throw new RuntimeException();
} else {
System.out.println("test1: OK");
}
}
// send request and don't read response. Check server closes connection
static void test2() throws IOException {
HttpURLConnection urlc = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
urlc.setReadTimeout(20 * 1000);
InputStream is = urlc.getInputStream();
// we won't read response and check if it times out
// on server. If it timesout at client then there is a problem
try {
Thread.sleep(10 * 1000);
while (is.read() != -1) ;
} catch (InterruptedException e) {
System.out.println(e);
System.out.println("test2: FAIL");
throw new RuntimeException("unexpected error");
} catch (SocketTimeoutException e1) {
System.out.println(e1);
System.out.println("test2: FAIL");
throw new RuntimeException("client timedout");
} finally {
is.close();
}
System.out.println("test2: OK");
}
// same as test2, but repeated with multiple connections
// including a number of valid request/responses
// Worker: a thread opens a connection to the server in one of three modes.
// NORMAL - sends a request, waits for response, and checks valid response
// REQUEST - sends a partial request, and blocks, to see if
// server closes the connection.
// RESPONSE - sends a request, partially reads response and blocks,
// to see if server closes the connection.
static class Worker extends Thread {
CountDownLatch latch;
Mode mode;
enum Mode {
REQUEST, // block during sending of request
RESPONSE, // block during reading of response
NORMAL // don't block
};
Worker (CountDownLatch latch, Mode mode) {
this.latch = latch;
this.mode = mode;
}
void fail(String msg) {
System.out.println(msg);
failed = true;
}
public void run() {
HttpURLConnection urlc;
InputStream is = null;
try {
urlc = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
urlc.setReadTimeout(20 * 1000);
urlc.setDoOutput(true);
} catch (IOException e) {
fail("Worker: failed to connect to server");
latch.countDown();
return;
}
try {
OutputStream os = urlc.getOutputStream();
os.write("foo".getBytes());
if (mode == Mode.REQUEST) {
Thread.sleep(3000);
}
os.close();
is = urlc.getInputStream();
if (mode == Mode.RESPONSE) {
Thread.sleep(3000);
}
if (!checkResponse(is, RESPONSE_BODY)) {
fail("Worker: response");
}
is.close();
return;
} catch (InterruptedException e0) {
fail("Worker: timedout");
} catch (SocketTimeoutException e1) {
fail("Worker: timedout");
} catch (IOException e2) {
switch (mode) {
case NORMAL:
fail("Worker: " + e2.getMessage());
break;
case RESPONSE:
if (is == null) {
fail("Worker: " + e2.getMessage());
break;
}
// default: is ok
}
} finally {
latch.countDown();
}
}
}
static final int NUM = 20;
static void test3() throws Exception {
failed = false;
CountDownLatch l = new CountDownLatch(NUM*3);
Worker[] workers = new Worker[NUM*3];
for (int i=0; i<NUM; i++) {
workers[i*3] = new Worker(l, Worker.Mode.NORMAL);
workers[i*3+1] = new Worker(l, Worker.Mode.REQUEST);
workers[i*3+2] = new Worker(l, Worker.Mode.RESPONSE);
workers[i*3].start();
workers[i*3+1].start();
workers[i*3+2].start();
}
l.await();
for (int i=0; i<NUM*3; i++) {
workers[i].join();
}
if (failed) {
throw new RuntimeException("test3: failed");
}
System.out.println("test3: OK");
}
static boolean checkResponse(InputStream is, String resp) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buf = new byte[64];
int c;
while ((c=is.read(buf)) != -1) {
bos.write(buf, 0, c);
}
bos.close();
if (!bos.toString().equals(resp)) {
System.out.println("Wrong response: " + bos.toString());
return false;
}
} catch (IOException e) {
System.out.println(e);
return false;
}
return true;
}
}

View file

@ -0,0 +1,192 @@
/*
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8199849
* @library /test/lib
* @run main/othervm/timeout=6000 BasicAuthenticatorCharset
* @summary Check for correct use of character sets with BasicAuthenticator() authentication
*/
import com.sun.net.httpserver.*;
import jdk.test.lib.net.URIBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.nio.charset.Charset;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
/**
* Test authentication
*/
public class BasicAuthenticatorCharset {
public static volatile int failCount = 0;
static final String TEST_USER = "test";
static final String UNICODE_PW = "Selam D\u00fcnya. Ho\u015f\u00e7akal D\u00fcnya";
static Handler testHandler;
static HttpServer testHttpServer;
static java.net.Authenticator clientAuth;
static HttpClient client;
static class Handler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
InputStream is = t.getRequestBody();
while (is.read() != -1) ;
is.close();
t.sendResponseHeaders(200, RSPBODY_EMPTY);
t.close();
}
}
static class ClientAuthenticator extends java.net.Authenticator {
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(TEST_USER, UNICODE_PW.toCharArray());
}
}
static void setAuthenticationPW(String path, String realm, String testPW, Charset charset) {
HttpContext ctx = testHttpServer.createContext(path, testHandler);
BasicAuthenticator auth;
if (charset != null) {
auth = new BasicAuthenticator(realm, charset) {
public boolean checkCredentials(String username, String pw) {
return username.equals(TEST_USER) && pw.equals(testPW);
}
};
} else {
auth = new BasicAuthenticator(realm) {
public boolean checkCredentials(String username, String pw) {
return username.equals(TEST_USER) && pw.equals(testPW);
}
};
}
ctx.setAuthenticator(auth);
}
static void connectAndAuth(String path, int expectedStatus) throws Exception {
// path is prepended with /old or /new for old and new http client
URL oldurl = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(testHttpServer.getAddress().getPort())
.path("/old" + path)
.toURL();
URI newuri = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(testHttpServer.getAddress().getPort())
.path("/new" + path)
.build();
// check old client
HttpURLConnection testConnection = (HttpURLConnection) oldurl.openConnection(Proxy.NO_PROXY);
// Check for successful authentication
int status = testConnection.getResponseCode();
if (status != 401) {
InputStream is = testConnection.getInputStream();
while (is.read() != -1) ;
is.close();
}
if (status != expectedStatus) {
System.err.println("Error (old): " + path);
failCount++;
}
HttpRequest request = HttpRequest.newBuilder()
.uri(newuri)
.GET()
.build();
status = -1;
try {
HttpResponse<Void> response = client.send(request, HttpResponse.BodyHandlers.discarding());
status = response.statusCode();
} catch (IOException e) {
System.out.println("NEW: " + e);
status = 401; // limitation in new API.
}
if (status != expectedStatus) {
System.err.println("Error (new): " + path);
failCount++;
}
}
public static void main(String[] args) throws Exception {
clientAuth = new ClientAuthenticator();
client = HttpClient.newBuilder()
.authenticator(clientAuth)
.build();
String defaultCharset = System.getProperty("file.encoding");
boolean isUTF8 = defaultCharset.equalsIgnoreCase("UTF-8");
testHandler = new Handler();
InetSocketAddress addr = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
testHttpServer = HttpServer.create(addr, 0);
// Set the passing credentials OLD client
setAuthenticationPW("/old/test1/", "passingCharset@test.realm", UNICODE_PW, UTF_8);
setAuthenticationPW("/old/test2/", "failingCharset@test.realm", UNICODE_PW, ISO_8859_1);
setAuthenticationPW("/old/test3/", "defaultCharset@test.realm", UNICODE_PW, null);
// Set the passing credentials NEW client
setAuthenticationPW("/new/test1/", "passingCharset@test.realm", UNICODE_PW, UTF_8);
setAuthenticationPW("/new/test2/", "failingCharset@test.realm", UNICODE_PW, ISO_8859_1);
setAuthenticationPW("/new/test3/", "defaultCharset@test.realm", UNICODE_PW, null);
ExecutorService executor = Executors.newCachedThreadPool();
testHttpServer.setExecutor(executor);
testHttpServer.start();
java.net.Authenticator.setDefault(clientAuth);
connectAndAuth("/test1/passingCharset.html", 200);
connectAndAuth("/test2/failingCharset.html", 401);
if (isUTF8) {
connectAndAuth("/test3/defaultCharset.html", 200);
}
testHttpServer.stop(0);
executor.shutdown();
// should fail once with UNICODE_PW and unsupporting character set
if (failCount > 0)
throw new RuntimeException("Fail count : " + failCount);
}
}

View file

@ -0,0 +1,230 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.*;
import java.net.*;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.*;
import java.nio.charset.StandardCharsets;
import jdk.test.lib.net.URIBuilder;
/**
* @test
* @bug 8199849 8235976
* @summary
* @library /test/lib
* @run main/othervm ParamTest
* @run main/othervm -Djava.net.preferIPv6Addresses=true ParamTest
*/
public class ParamTest {
static final String[] variants = {
" ,charset=utf-8",
" ,charset=UtF-8",
" ,charset=\"utF-8\"",
" ,charset=\"UtF-8\""
};
static final int LOOPS = variants.length;
volatile static boolean error = false;
static class BasicServer extends Thread {
final ServerSocket server;
Socket s;
InputStream is;
OutputStream os;
static final String realm = "wallyworld";
String reply1 = "HTTP/1.1 401 Unauthorized\r\n"+
"WWW-Authenticate: Basic realm=\""+realm+"\"\r\n";
String reply2 = "HTTP/1.1 200 OK\r\n"+
"Date: Mon, 15 Jan 2001 12:18:21 GMT\r\n" +
"Server: Apache/1.3.14 (Unix)\r\n" +
"Connection: close\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
"Content-Length: 10\r\n\r\n";
BasicServer(ServerSocket s) {
server = s;
}
String readHeaders(Socket sock) throws IOException {
InputStream is = sock.getInputStream();
String s = "";
byte[] buf = new byte[1024];
while (!s.endsWith("\r\n\r\n")) {
int c = is.read(buf);
if (c == -1)
return s;
String f = new String(buf, 0, c, StandardCharsets.ISO_8859_1);
s = s + f;
}
return s;
}
void check(String s, int iteration) {
if (s.indexOf(encodedAuthString) == -1) {
System.err.printf("On iteration %d, wrong auth string received %s\n", iteration, s);
error = true;
} else {
System.err.println("check: correct auth string received");
}
}
public void run() {
try {
for (int j = 0; j < 2; j++)
for (int i = 0; i < LOOPS; i++) {
System.out.println("Server 1: accept");
s = server.accept();
readHeaders(s);
System.out.println("accepted");
os = s.getOutputStream();
String str = reply1 + variants[i] + "\r\n\r\n";
os.write(str.getBytes());
System.out.println("Server 2: accept");
Socket s1 = server.accept();
String request = readHeaders(s1);
check(request, i);
System.out.println("accepted");
os = s1.getOutputStream();
os.write((reply2 + "HelloWorld").getBytes());
os.flush();
s.close();
s1.close();
finished();
}
} catch (Exception e) {
System.out.println(e);
error = true;
}
}
public synchronized void finished() {
notifyAll();
}
}
static final String password = "Selam D\u00fcnya.";
// "user : <password above>" encoded in UTF-8 and converted to Base 64
static final String encodedAuthString = "dXNlcjpTZWxhbSBEw7xueWEu";
static class MyAuthenticator extends Authenticator {
MyAuthenticator() {
super();
}
public PasswordAuthentication getPasswordAuthentication()
{
System.out.println("Auth called");
return (new PasswordAuthentication ("user", password.toCharArray()));
}
}
static void read(InputStream is) throws IOException {
int c;
System.out.println("reading");
while ((c=is.read()) != -1) {
System.out.write(c);
}
System.out.println("");
System.out.println("finished reading");
}
public static void main(String args[]) throws Exception {
MyAuthenticator auth = new MyAuthenticator();
Authenticator.setDefault(auth);
InetAddress loopback = InetAddress.getLoopbackAddress();
ServerSocket ss = new ServerSocket();
ss.bind(new InetSocketAddress(loopback, 0));
int port = ss.getLocalPort();
BasicServer server = new BasicServer(ss);
synchronized (server) {
server.start();
System.out.println("client 1");
String base = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/")
.build()
.toString();
URL url = new URL(base + "d1/d2/d3/foo.html");
for (int i = 0; i < LOOPS; i++) {
URLConnection urlc = url.openConnection(Proxy.NO_PROXY);
InputStream is = urlc.getInputStream();
read(is);
System.out.println("Client: waiting for notify");
server.wait();
System.out.println("Client: continue");
// check if authenticator was called once (ok) or twice (not)
if (error) {
System.err.println("Error old client iteration " + i);
}
}
URI uri = url.toURI();
HttpClient client = HttpClient.newBuilder()
.authenticator(auth)
.proxy(ProxySelector.of(null))
.build();
HttpRequest request = HttpRequest
.newBuilder(uri)
.GET()
.build();
for (int i = 0; i < LOOPS; i++) {
HttpResponse<Void> response = client.send(request, HttpResponse.BodyHandlers.discarding());
int status = response.statusCode();
if (status != 200) {
System.err.printf("Error new client (%d) iteration ",
status, i);
error = true;
} else
System.err.println("New client ok iteration " + i);
System.out.println("New Client: waiting for notify");
server.wait();
System.out.println("New Client: continue");
}
if (error) {
throw new RuntimeException("Test failed");
}
}
}
}

View file

@ -0,0 +1,101 @@
/*
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8199849
* @library /test/lib
* @summary Checks that unicode bytes are being handled correctly
* @run main/othervm -Dfile.encoding=UTF_8 TestHttpUnicode
*/
import com.sun.net.httpserver.*;
import jdk.test.lib.net.URIBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
public class TestHttpUnicode {
private static final String TEST_USER = "Selam D\u00fcnya. Ho\u015f\u00e7akal D\u00fcnya";
private static final String TEST_PW = "Selam D\u00fcnya. Ho\u015f\u00e7akal D\u00fcnya";
static class ClientAuthenticator extends java.net.Authenticator {
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(TEST_USER, TEST_PW.toCharArray());
}
}
static class Handler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
InputStream is = t.getRequestBody();
while (is.read() != -1) ;
is.close();
HttpPrincipal p = t.getPrincipal();
if (p.getUsername().equals(TEST_USER)) {
t.sendResponseHeaders(200, RSPBODY_EMPTY);
}
t.close();
}
}
public static void main(String[] args) throws Exception {
HttpServer testHttpServer = null;
try {
InetSocketAddress loopbackAddress = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
testHttpServer = HttpServer.create(loopbackAddress, 0);
HttpContext context = testHttpServer.createContext("/test", new Handler());
System.setProperty("http.maxRedirects", "3");
BasicAuthenticator serverAuthenticator = new BasicAuthenticator("authCharacterSet@test.realm") {
public boolean checkCredentials(String username, String pw) {
return username.equals(TEST_USER) && pw.equals(TEST_PW);
}
};
context.setAuthenticator(serverAuthenticator);
java.net.Authenticator.setDefault(new ClientAuthenticator());
testHttpServer.start();
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(testHttpServer.getAddress().getPort())
.path("/test/authCharacterSet.html")
.toURL();
HttpURLConnection testConnection = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
// Authenication CHECK
if (testConnection.getResponseCode() == 401) {
throw new RuntimeException("Test Authentication failed with HTTP Status 401.");
}
InputStream is = testConnection.getInputStream();
while (is.read() != -1) ;
} finally {
testHttpServer.stop(0);
}
}
}

View file

@ -0,0 +1,144 @@
/*
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8300268
* @library /test/lib
* @modules jdk.httpserver/sun.net.httpserver
* @build jdk.httpserver/sun.net.httpserver.HttpServerAccess MaxIdleConnectionsTest
* @run junit/othervm -Dsun.net.httpserver.maxIdleConnections=4 MaxIdleConnectionsTest
*/
import com.sun.net.httpserver.HttpServer;
import jdk.test.lib.net.URIBuilder;
import sun.net.httpserver.HttpServerAccess;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_CHUNKED;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MaxIdleConnectionsTest {
HttpServer server;
int maxIdleConnections, totalConnections;
CountDownLatch reqFinishedProcessing;
@BeforeAll
void before() throws Exception {
maxIdleConnections = Integer.getInteger("sun.net.httpserver.maxIdleConnections");
totalConnections = maxIdleConnections + 1;
reqFinishedProcessing = new CountDownLatch(totalConnections);
server = startServer(reqFinishedProcessing);
}
@AfterAll
void after() throws Exception {
server.stop(0);
}
// Issue one too many requests and assert that the idle connection pool doesn't
// exceed maxIdleConnections
@Test
public void test() throws Exception {
final int port = server.getAddress().getPort();
final List<Future<Void>> responses = new ArrayList<>();
try (final ExecutorService requestIssuer = Executors.newFixedThreadPool(totalConnections)) {
for (int i = 1; i <= totalConnections; i++) {
URL requestURL = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/MaxIdleConnectionTest/" + i)
.toURL();
final Future<Void> result = requestIssuer.submit(() -> {
System.out.println("Issuing request " + requestURL);
final URLConnection conn = requestURL.openConnection();
try (final InputStream is = conn.getInputStream()) {
is.readAllBytes();
}
return null;
});
responses.add(result);
}
// wait for all the requests to reach each of the handlers
System.out.println("Waiting for all " + totalConnections + " requests to reach" +
" the server side request handler");
reqFinishedProcessing.await();
}
// verify every request got served before checking idle count
for (int i = 0; i < totalConnections; i++) {
responses.get(i).get();
System.out.println("Received successful response for request " + i);
}
// assert that the limit set by maxIdleConnections was not exceeded
int idleConnectionCount = HttpServerAccess.getIdleConnectionCount(server);
System.out.println("count " + idleConnectionCount);
assertTrue(maxIdleConnections >= idleConnectionCount,
String.format("Too many idle connections: %d, limit: %d", idleConnectionCount, maxIdleConnections));
}
// Create HttpServer that will handle requests with multiple threads
private static HttpServer startServer(final CountDownLatch reqFinishedProcessing) throws IOException {
final var bindAddr = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
final HttpServer server = HttpServer.create(bindAddr, 0);
final AtomicInteger threadId = new AtomicInteger();
server.setExecutor(Executors.newCachedThreadPool(r -> {
final Thread t = new Thread(r);
t.setName("http-request-handler-" + threadId.incrementAndGet());
t.setDaemon(true);
return t;
}));
server.createContext("/MaxIdleConnectionTest/", (exchange) -> {
System.out.println("Request " + exchange.getRequestURI() + " received");
System.out.println("Sending response for request " + exchange.getRequestURI() + " from " + exchange.getRemoteAddress());
reqFinishedProcessing.countDown();
exchange.sendResponseHeaders(200, RSPBODY_CHUNKED);
exchange.getResponseBody().close();
});
server.start();
System.out.println("Server started at address " + server.getAddress());
return server;
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
import com.sun.net.httpserver.HttpServer;
import java.lang.reflect.Field;
import java.util.Set;
public class HttpServerAccess {
// Given a HttpServer object get the number of idleConnections it currently has
public static int getIdleConnectionCount(HttpServer server) throws Exception{
// Use reflection to get server object which is HTTPServerImpl
Field serverField = server.getClass().getDeclaredField("server");
serverField.setAccessible(true);
// Get the actual serverImpl class, then get the IdleConnection Field
Object serverImpl = serverField.get(server);
Field idleConnectionField = serverImpl.getClass().getDeclaredField("idleConnections");
idleConnectionField.setAccessible(true);
// Finally get the IdleConnection object which is of type Set<HttpConnection>
Object idleConnectionSet = idleConnectionField.get(serverImpl);
Set<HttpConnection> idleConnectionPool = (Set<HttpConnection>) idleConnectionSet;
return idleConnectionPool.size();
}
}

View file

@ -0,0 +1,71 @@
/*
* Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6339483
* @summary NullPointerException when creating a HttpContext with no handler
* @library /test/lib
* @run main B6339483
* @run main/othervm -Djava.net.preferIPv6Addresses=true B6339483
*/
import com.sun.net.httpserver.*;
import java.util.concurrent.*;
import java.io.*;
import java.net.*;
import jdk.test.lib.net.URIBuilder;
public class B6339483 {
public static void main (String[] args) throws Exception {
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress addr = new InetSocketAddress (loopback, 0);
HttpServer server = HttpServer.create (addr, 0);
HttpContext ctx = server.createContext ("/test");
ExecutorService executor = Executors.newCachedThreadPool();
server.setExecutor (executor);
server.start ();
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(server.getAddress().getPort())
.path("/test/foo.html")
.toURL();
HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
try {
InputStream is = urlc.getInputStream();
int c = 0;
while (is.read()!= -1) {
c ++;
}
} catch (IOException e) {
server.stop(0);
executor.shutdown();
System.out.println ("OK");
}
}
}

View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6341616
* @library /test/lib
* @run main B6341616
* @run main/othervm -Djava.net.preferIPv6Addresses=true B6341616
* @summary Server doesnt send response if there is a RuntimeException in validate of BasicAuthFilter
*/
import com.sun.net.httpserver.*;
import java.util.concurrent.*;
import java.io.*;
import java.net.*;
import jdk.test.lib.net.URIBuilder;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
public class B6341616 {
public static void main (String[] args) throws Exception {
Handler handler = new Handler();
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress addr = new InetSocketAddress (loopback, 0);
HttpServer server = HttpServer.create (addr, 0);
HttpContext ctx = server.createContext ("/test", handler);
BasicAuthenticator filter = new BasicAuthenticator ("foobar@test.realm") {
public boolean checkCredentials (String username, String pw) {
throw new RuntimeException ("");
}
};
ctx.setAuthenticator (filter);
ExecutorService executor = Executors.newCachedThreadPool();
server.setExecutor (executor);
server.start ();
java.net.Authenticator.setDefault (new MyAuthenticator());
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(server.getAddress().getPort())
.path("/test/foo.html")
.toURL();
HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
try {
InputStream is = urlc.getInputStream();
int c = 0;
while (is.read()!= -1) {
c ++;
}
} catch (IOException e) {
server.stop(0);
executor.shutdown();
System.out.println ("OK");
}
}
public static boolean error = false;
static class MyAuthenticator extends java.net.Authenticator {
public PasswordAuthentication getPasswordAuthentication () {
PasswordAuthentication pw;
if (!getRequestingPrompt().equals ("foobar@test.realm")) {
B6341616.error = true;
}
pw = new PasswordAuthentication ("fred", "xyz".toCharArray());
return pw;
}
}
static class Handler implements HttpHandler {
int invocation = 1;
public void handle (HttpExchange t)
throws IOException
{
InputStream is = t.getRequestBody();
Headers map = t.getRequestHeaders();
Headers rmap = t.getResponseHeaders();
while (is.read () != -1) ;
is.close();
t.sendResponseHeaders (200, RSPBODY_EMPTY);
t.close();
}
}
}

View file

@ -0,0 +1,157 @@
/*
* Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6361557
* @run main/othervm B6361557
* @summary Lightweight HTTP server quickly runs out of file descriptors on Linux
*/
import com.sun.net.httpserver.*;
import java.util.*;
import java.util.concurrent.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.net.*;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
/**
* The test simply opens 1,000 separate connections
* and invokes one http request on each. The client does
* not close any sockets until after they are closed
* by the server. This verifies the basic ability
* of the server to manage a reasonable number of connections
*/
public class B6361557 {
public static boolean error = false;
static final int NUM = 1000;
static class Handler implements HttpHandler {
int invocation = 1;
public void handle (HttpExchange t)
throws IOException
{
InputStream is = t.getRequestBody();
Headers map = t.getRequestHeaders();
Headers rmap = t.getResponseHeaders();
while (is.read () != -1) ;
is.close();
t.sendResponseHeaders (200, RSPBODY_EMPTY);
t.close();
}
}
final static String request = "GET /test/foo.html HTTP/1.1\r\nContent-length: 0\r\n\r\n";
final static ByteBuffer requestBuf = ByteBuffer.wrap(request.getBytes());
public static void main (String[] args) throws Exception {
Handler handler = new Handler();
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress addr = new InetSocketAddress (loopback, 0);
HttpServer server = HttpServer.create (addr, 0);
HttpContext ctx = server.createContext ("/test", handler);
ExecutorService executor = Executors.newCachedThreadPool();
server.setExecutor (executor);
server.start ();
InetSocketAddress destaddr = new InetSocketAddress (
loopback, server.getAddress().getPort()
);
System.out.println ("destaddr " + destaddr);
Selector selector = Selector.open ();
int requests = 0;
int responses = 0;
while (true) {
// we need to read responses from time to time: slightly
// increase the timeout with the amount of pending responses
// to give a chance to the server to reply.
int selres = selector.select (requests - responses + 1);
Set<SelectionKey> selkeys = selector.selectedKeys();
for (SelectionKey key : selkeys) {
if (key.isReadable()) {
SocketChannel chan = (SocketChannel)key.channel();
ByteBuffer buf = (ByteBuffer)key.attachment();
try {
int x = chan.read(buf);
if (x == -1 || responseComplete(buf)) {
System.out.print("_");
key.attach(null);
chan.close();
responses++;
}
} catch (IOException e) {
System.out.println(e);
}
}
}
if (requests < NUM) {
System.out.print(".");
SocketChannel schan = SocketChannel.open(destaddr);
requestBuf.rewind();
int c = 0;
while (requestBuf.remaining() > 0) {
c += schan.write(requestBuf);
}
schan.configureBlocking(false);
schan.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(100));
requests++;
}
if (responses == NUM) {
System.out.println ("Finished clients");
break;
}
}
server.stop(0);
selector.close();
executor.shutdown ();
}
/* Look for CR LF CR LF */
static boolean responseComplete(ByteBuffer buf) {
int pos = buf.position();
buf.flip();
byte[] lookingFor = new byte[] {'\r', '\n', '\r', '\n' };
int lookingForCount = 0;
while (buf.hasRemaining()) {
byte b = buf.get();
if (b == lookingFor[lookingForCount]) {
lookingForCount++;
if (lookingForCount == 4) {
return true;
}
} else {
lookingForCount = 0;
}
}
buf.position(pos);
buf.limit(buf.capacity());
return false;
}
}

View file

@ -0,0 +1,193 @@
/*
* Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6373555
* @library /test/lib
* @summary HTTP Server failing to answer client requests
* @run main B6373555
* @run main/othervm -Djava.net.preferIPv6Addresses=true B6373555
*/
import java.net.*;
import java.io.*;
import java.util.*;
import com.sun.net.httpserver.*;
import java.util.concurrent.*;
import jdk.test.lib.net.URIBuilder;
public class B6373555 {
private static int s_received = 0;
private static int sent = 0;
private static int received = 0;
private static int port;
private static volatile boolean error = false;
static HttpServer httpServer;
static ExecutorService pool, execs;
static int NUM = 1000;
public static void main(String[] args) throws Exception {
try {
if (args.length > 0) {
NUM = Integer.parseInt (args[0]);
}
execs = Executors.newFixedThreadPool(5);
httpServer = createHttpServer(execs);
port = httpServer.getAddress().getPort();
pool = Executors.newFixedThreadPool(10);
httpServer.start();
for (int i=0; i < NUM; i++) {
pool.execute(new Client());
if (error) {
throw new Exception ("error in test");
}
}
System.out.println("Main thread waiting");
pool.shutdown();
long latest = System.currentTimeMillis() + 200 * 1000;
while (System.currentTimeMillis() < latest) {
if (pool.awaitTermination(2000L, TimeUnit.MILLISECONDS)) {
System.out.println("Main thread done!");
return;
}
if (error) {
throw new Exception ("error in test");
}
}
throw new Exception ("error in test: timed out");
} finally {
httpServer.stop(0);
pool.shutdownNow();
execs.shutdownNow();
}
}
public static class Client implements Runnable {
byte[] getBuf () {
byte[] buf = new byte [5200];
for (int i=0; i< 5200; i++) {
buf [i] = (byte)i;
}
return buf;
}
public void run() {
try {
Thread.sleep(10);
byte[] buf = getBuf();
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/test")
.toURLUnchecked();
System.out.println("URL: " + url);
HttpURLConnection con = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
con.setDoOutput(true);
con.setDoInput(true);
con.setRequestMethod("POST");
con.setRequestProperty(
"Content-Type",
"Multipart/Related; type=\"application/xop+xml\"; boundary=\"----=_Part_0_6251267.1128549570165\"; start-info=\"text/xml\"");
OutputStream out = con.getOutputStream();
out.write(buf);
out.close();
InputStream in = con.getInputStream();
byte[] newBuf = readFully(in);
in.close();
if (buf.length != newBuf.length) {
System.out.println("Doesn't match");
error = true;
}
}
catch(Exception e) {
e.printStackTrace();
System.out.print (".");
error = true;
}
}
}
private static byte[] readFully(InputStream istream) throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int num = 0;
if (istream != null) {
while ((num = istream.read(buf)) != -1) {
bout.write(buf, 0, num);
}
}
byte[] ret = bout.toByteArray();
return ret;
}
private static HttpServer createHttpServer(ExecutorService execs)
throws Exception {
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress inetAddress = new InetSocketAddress(loopback, 0);
HttpServer testServer = HttpServer.create(inetAddress, 15);
testServer.setExecutor(execs);
HttpContext context = testServer.createContext("/test");
context.setHandler(new HttpHandler() {
public void handle(HttpExchange msg) {
try {
String method = msg.getRequestMethod();
if (method.equals("POST")) {
InputStream is = msg.getRequestBody();
byte[] buf = readFully(is);
is.close();
writePostReply(msg, buf);
} else {
System.out.println("****** METHOD not handled ***** "+method);
System.out.println("Received="+s_received);
}
}
catch(Exception e) {
e.printStackTrace();
}
finally {
msg.close();
}
}
}
);
return testServer;
}
private static void writePostReply(HttpExchange msg, byte[] buf)
throws Exception {
msg.getResponseHeaders().add("Content-Type", "text/xml");
msg.sendResponseHeaders(200, buf.length);
OutputStream out = msg.getResponseBody();
out.write(buf);
out.close();
}
}

View file

@ -0,0 +1,159 @@
/*
* Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6393710
* @library /test/lib
* @summary Non authenticated call followed by authenticated call never returns
* @run main B6393710
* @run main/othervm -Djava.net.preferIPv6Addresses=true B6393710
*/
import com.sun.net.httpserver.*;
import java.util.*;
import java.util.concurrent.*;
import java.io.*;
import java.net.*;
import jdk.test.lib.Utils;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
/*
* Test checks for following bug(s) when a POST containing a request body
* needs to be authenticated
*
* 1) we were not reading the request body
*
* 2) we were not re-enabling the interestops for the socket channel
*/
public class B6393710 {
static String CRLF = "\r\n";
/* Two post requests containing data. The second one
* has the expected authorization credentials
*/
static String cmd =
"POST /test/foo HTTP/1.1"+CRLF+
"Content-Length: 22"+CRLF+
"Pragma: no-cache"+CRLF+
"Cache-Control: no-cache"+CRLF+ CRLF+
"<item desc=\"excuse\" />"+
"POST /test/foo HTTP/1.1"+CRLF+
"Content-Length: 22"+CRLF+
"Pragma: no-cache"+CRLF+
"Authorization: Basic ZnJlZDpmcmVkcGFzc3dvcmQ="+CRLF+
"Cache-Control: no-cache"+CRLF+ CRLF+
"<item desc=\"excuse\" />";
public static void main (String[] args) throws Exception {
Handler handler = new Handler();
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress addr = new InetSocketAddress (loopback, 0);
HttpServer server = HttpServer.create (addr, 0);
HttpContext ctx = server.createContext ("/test", handler);
ctx.setAuthenticator (new BasicAuthenticator ("test") {
public boolean checkCredentials (String user, String pass) {
return user.equals ("fred") && pass.equals("fredpassword");
}
});
server.start ();
Socket s = new Socket (loopback, server.getAddress().getPort());
s.setSoTimeout ((int) Utils.adjustTimeout(5000));
OutputStream os = s.getOutputStream();
os.write (cmd.getBytes());
InputStream is = s.getInputStream ();
try {
ok = readAndCheck (is, "401 Unauthorized") &&
readAndCheck (is, "200 OK");
} catch (SocketTimeoutException e) {
System.out.println ("Did not received expected data");
ok = false;
} finally {
s.close();
server.stop(0);
}
if (requests != 1) {
throw new RuntimeException ("server handler did not receive the request");
}
if (!ok) {
throw new RuntimeException ("did not get 200 OK");
}
System.out.println ("OK");
}
/* check for expected string and return true if found in stream */
static boolean readAndCheck (InputStream is, String expected) throws IOException {
int c;
int count = 0;
int expLen = expected.length();
expected = expected.toLowerCase();
while ((c=is.read()) != -1) {
c = Character.toLowerCase (c);
if (c == expected.charAt (count)) {
count ++;
if (count == expLen) {
return true;
}
} else {
count = 0;
}
}
return false;
}
public static volatile boolean ok = false;
static volatile int requests = 0;
static class Handler implements HttpHandler {
int invocation = 1;
public void handle (HttpExchange t)
throws IOException
{
int count = 0;
InputStream is = t.getRequestBody();
Headers map = t.getRequestHeaders();
Headers rmap = t.getResponseHeaders();
while (is.read () != -1) {
count ++;
}
if (count != 22) {
System.out.println ("Handler expected 22. got " + count);
ok = false;
}
is.close();
t.sendResponseHeaders (200, RSPBODY_EMPTY);
t.close();
requests ++;
}
}
}

View file

@ -0,0 +1,158 @@
/*
* Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @library /test/lib
* @bug 6401598
* @summary new HttpServer cannot serve binary stream data
* @run main B6401598
* @run main/othervm -Djava.net.preferIPv6Addresses=true B6401598
*/
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URL;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.concurrent.*;
import jdk.test.lib.net.URIBuilder;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_CHUNKED;
public class B6401598 {
static class MyHandler implements HttpHandler {
public MyHandler() {
}
public void handle(HttpExchange arg0) throws IOException {
try {
InputStream is = arg0.getRequestBody();
OutputStream os = arg0.getResponseBody();
DataInputStream dis = new DataInputStream(is);
short input = dis.readShort();
while (dis.read() != -1) ;
dis.close();
DataOutputStream dos = new DataOutputStream(os);
arg0.sendResponseHeaders(200, RSPBODY_CHUNKED);
dos.writeShort(input);
dos.flush();
dos.close();
} catch (IOException e) {
e.printStackTrace();
error = true;
}
}
}
static int port;
static boolean error = false;
static ExecutorService exec;
static HttpServer server;
public static void main(String[] args) {
try {
InetAddress loopback = InetAddress.getLoopbackAddress();
server = HttpServer.create(new InetSocketAddress(loopback, 0), 400);
server.createContext("/server/", new MyHandler());
exec = Executors.newFixedThreadPool(3);
server.setExecutor(exec);
port = server.getAddress().getPort();
server.start();
short counter;
for (counter = 0; counter < 1000; counter++) {
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/server/")
.toURLUnchecked();
System.out.println("URL: " + url);
HttpURLConnection connection = getHttpURLConnection(url, 10000);
OutputStream os = connection.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeShort(counter);
dos.flush();
dos.close();
counter++;
InputStream is = connection.getInputStream();
DataInputStream dis = new DataInputStream(is);
short ret = dis.readShort();
dis.close();
}
System.out.println ("Stopping");
} catch (Exception e) {
throw new AssertionError("Unexpected exception: " + e, e);
} finally {
server.stop(0);
exec.shutdown();
}
}
static HttpURLConnection getHttpURLConnection(URL url, int timeout) throws IOException {
HttpURLConnection httpURLConnection =
(HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
httpURLConnection.setConnectTimeout(40000);
httpURLConnection.setReadTimeout(timeout);
httpURLConnection.setDoOutput(true);
httpURLConnection.setDoInput(true);
httpURLConnection.setUseCaches(false);
httpURLConnection.setAllowUserInteraction(false);
httpURLConnection.setRequestMethod("POST");
// HttpURLConnection httpURLConnection = new MyHttpURLConnection(url);
return httpURLConnection;
}
}

View file

@ -0,0 +1,118 @@
/*
* Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6421581
* @summary NPE while closing HttpExchange.getResonseBody()
*/
import com.sun.net.httpserver.*;
import java.net.*;
import java.io.*;
import java.util.concurrent.*;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_CHUNKED;
public class B6421581 {
static boolean error = false;
static int iter = 0;
public static void main(String[] args) throws Exception {
once();
}
public static void once() throws Exception {
InetSocketAddress inetAddress = new InetSocketAddress(
"localhost", 0);
HttpServer server = HttpServer.create(inetAddress, 5);
int port = server.getAddress().getPort();
ExecutorService e = (Executors.newFixedThreadPool(5));
server.setExecutor(e);
HttpContext context = server.createContext("/hello");
server.start();
context.setHandler(new HttpHandler() {
public void handle(HttpExchange msg) {
iter ++;
System.out.println("Got request");
switch (iter) {
case 1:
/* close output stream without opening inpustream */
/* chunked encoding */
try {
msg.sendResponseHeaders(200, RSPBODY_CHUNKED);
OutputStream out = msg.getResponseBody();
out.write("hello".getBytes());
out.close();
} catch(Exception e) {
error = true;
} finally {
msg.close();
}
break;
case 2:
/* close output stream without opening inpustream */
/* fixed encoding */
try {
msg.sendResponseHeaders(200, 5);
OutputStream out = msg.getResponseBody();
out.write("hello".getBytes());
out.close();
} catch(Exception e) {
error = true;
} finally {
msg.close();
}
break;
case 3:
/* close exchange without opening any stream */
try {
msg.sendResponseHeaders(200, RSPBODY_EMPTY);
msg.close();
} catch(Exception e) {
error = true;
}
break;
}
}
});
URL url = new URL("http://localhost:"+port+"/hello/url.text");
doURL(url);
doURL(url);
doURL(url);
e.shutdown();
e.awaitTermination(4, TimeUnit.SECONDS);
server.stop(0);
if (error) {
throw new RuntimeException ("test failed");
}
}
static void doURL (URL url) throws Exception {
InputStream is = url.openStream();
while (is.read() != -1) ;
is.close();
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6424196
* @summary PIT build 85 mustang: two jhttp tests fail
*/
import java.net.InetSocketAddress;
import java.io.IOException;
import com.sun.net.httpserver.*;
public class B6424196 {
public static void main(String[] args) throws IOException {
HttpServer server = HttpServer.create();
}
}

View file

@ -0,0 +1,87 @@
/*
* Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6431193
* @summary The new HTTP server exits immediately
* @requires test.thread.factory != "Virtual"
* @library /test/lib
* @run main B6431193
* @run main/othervm -Djava.net.preferIPv6Addresses=true B6431193
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.*;
import jdk.test.lib.net.URIBuilder;
import com.sun.net.httpserver.*;
public class B6431193 {
static boolean handlerIsDaemon = true;
public static void main(String[] args) throws IOException {
class MyHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
try (InputStream is = t.getRequestBody();
OutputStream os = t.getResponseBody()) {
is.readAllBytes();
// .. read the request body
String response = "This is the response";
handlerIsDaemon = Thread.currentThread().isDaemon();
t.sendResponseHeaders(200, response.length());
os.write(response.getBytes());
}
}
}
InetAddress loopback = InetAddress.getLoopbackAddress();
HttpServer server = HttpServer.create(new InetSocketAddress(loopback, 0), 10);
server.createContext("/apps", new MyHandler());
server.setExecutor(null);
server.start();
try {
int port = server.getAddress().getPort();
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/apps/foo")
.toURL();
try (InputStream is = url.openConnection(Proxy.NO_PROXY).getInputStream()) {
is.readAllBytes();
}
if (handlerIsDaemon) {
throw new RuntimeException("request was handled by a daemon thread");
}
} catch (Exception e) {
throw new AssertionError("Unexpected exception: " + e, e);
} finally {
server.stop(0);
}
}
}

View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6433018
* @summary HTTP server sometimes sends bad request for browsers javascript
* @run main B6433018
* @run main/othervm -Djava.net.preferIPv6Addresses=true B6433018
*/
import com.sun.net.httpserver.*;
import java.util.concurrent.*;
import java.io.*;
import java.net.*;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
public class B6433018 {
static final String CRLF = "\r\n";
/* invalid HTTP POST with extra CRLF at end */
/* This checks that the server is able to handle it
* and recognise the second request */
static final String cmd =
"POST /test/item HTTP/1.1"+CRLF+
"Keep-Alive: 300"+CRLF+
"Proxy-Connection: keep-alive"+CRLF+
"Content-Type: text/xml"+CRLF+
"Content-Length: 22"+CRLF+
"Pragma: no-cache"+CRLF+
"Cache-Control: no-cache"+CRLF+ CRLF+
"<item desc=\"excuse\" />"+CRLF+
"GET /test/items HTTP/1.1"+CRLF+
"Host: araku:9999"+CRLF+
"Accept-Language: en-us,en;q=0.5"+CRLF+
"Accept-Encoding: gzip,deflate"+CRLF+
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7"+CRLF+
"Keep-Alive: 300"+CRLF+
"Proxy-Connection: keep-alive"+CRLF+
"Pragma: no-cache"+CRLF+
"Cache-Control: no-cache"+CRLF+CRLF;
public static void main(String[] args) throws Exception {
CountDownLatch finished = new CountDownLatch(2);
Handler handler = new Handler(finished);
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress addr = new InetSocketAddress(loopback, 0);
HttpServer server = HttpServer.create(addr, 0);
HttpContext ctx = server.createContext("/test", handler);
server.start();
int port = server.getAddress().getPort();
try (Socket s = new Socket(loopback, port);
OutputStream os = s.getOutputStream()) {
os.write(cmd.getBytes());
finished.await(30, TimeUnit.SECONDS);
} finally {
server.stop(0);
}
if (finished.getCount() != 0)
throw new RuntimeException("did not receive the 2 requests");
System.out.println("OK");
}
static class Handler implements HttpHandler {
private final CountDownLatch finished;
Handler(CountDownLatch finished) {
this.finished = finished;
}
@Override
public void handle(HttpExchange t) throws IOException {
try (InputStream is = t.getRequestBody()) {
Headers map = t.getRequestHeaders();
Headers rmap = t.getResponseHeaders();
while (is.read() != -1);
}
t.sendResponseHeaders(200, RSPBODY_EMPTY);
t.close();
finished.countDown();
}
}
}

View file

@ -0,0 +1,105 @@
/*
* Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6526158
* @library /test/lib
* @run main B6526158
* @run main/othervm -Djava.net.preferIPv6Addresses=true B6526158
* @summary HttpExchange.getRequestBody().close() throws Exception
*/
import com.sun.net.httpserver.*;
import java.util.concurrent.*;
import java.io.*;
import java.net.*;
import jdk.test.lib.net.URIBuilder;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
public class B6526158 {
/* keep under 64 k */
final static int SIZE = 60 * 1024;
public static void main (String[] args) throws Exception {
Handler handler = new Handler();
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress addr = new InetSocketAddress (loopback, 0);
HttpServer server = HttpServer.create (addr, 0);
HttpContext ctx = server.createContext ("/test", handler);
ExecutorService executor = Executors.newCachedThreadPool();
server.setExecutor (executor);
server.start ();
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(server.getAddress().getPort())
.path("/test/foo.html")
.toURL();
HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
urlc.setDoOutput (true);
try {
OutputStream os = new BufferedOutputStream (urlc.getOutputStream());
for (int i=0; i< SIZE; i++) {
os.write (i);
}
os.close();
InputStream is = urlc.getInputStream();
int c = 0;
while (is.read()!= -1) {
c ++;
}
is.close();
} finally {
server.stop(0);
executor.shutdown();
}
if (error) {
throw new RuntimeException ("Test failed");
}
}
public static boolean error = false;
static class Handler implements HttpHandler {
int invocation = 1;
public void handle (HttpExchange t)
throws IOException
{
InputStream is = t.getRequestBody();
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
error = true;
}
t.sendResponseHeaders (200, RSPBODY_EMPTY);
t.close();
}
}
}

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6526913
* @library /test/lib
* @run main/othervm -Dhttp.keepAlive=false B6526913
* @run main/othervm -Djava.net.preferIPv6Addresses=true
* -Dhttp.keepAlive=false B6526913
* @summary HttpExchange.getResponseBody().close() throws Exception
*/
import com.sun.net.httpserver.*;
import java.util.concurrent.*;
import java.io.*;
import java.net.*;
import jdk.test.lib.net.URIBuilder;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_CHUNKED;
public class B6526913 {
public static void main (String[] args) throws Exception {
Handler handler = new Handler();
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress addr = new InetSocketAddress (loopback, 0);
HttpServer server = HttpServer.create (addr, 0);
HttpContext ctx = server.createContext ("/test", handler);
ExecutorService executor = Executors.newCachedThreadPool();
server.setExecutor (executor);
server.start ();
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(server.getAddress().getPort())
.path("/test/foo.html")
.toURL();
HttpURLConnection urlc = (HttpURLConnection)url.openConnection (Proxy.NO_PROXY);
try {
InputStream is = urlc.getInputStream();
int c ,count = 0;
byte [] buf = new byte [32 * 1024];
while (count < 32 * 1024) {
count += is.read (buf);
}
is.close();
} finally {
server.stop(0);
executor.shutdown();
}
if (error) {
throw new RuntimeException ("Test failed");
}
}
public static boolean error = false;
static class Handler implements HttpHandler {
int invocation = 1;
public void handle (HttpExchange t)
throws IOException
{
InputStream is = t.getRequestBody();
try {
while (is.read() != -1) ;
is.close();
} catch (IOException e) {
e.printStackTrace();
error = true;
}
/* send a chunked response, but wait a while before
* sending the final empty chunk
*/
t.sendResponseHeaders (200, RSPBODY_CHUNKED);
OutputStream os = t.getResponseBody();
byte[] bb = new byte [32 * 1024];
os.write (bb);
os.flush();
try {Thread.sleep (5000); } catch (InterruptedException e){}
try {
/* empty chunk sent here */
os.close();
} catch (IOException e) {
error = true;
e.printStackTrace();
}
t.close();
}
}
}

View file

@ -0,0 +1,139 @@
/*
* Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6529200
* @run main/othervm B6529200
* @run main/othervm -Djava.net.preferIPv6Addresses=true B6529200
* @summary lightweight http server does not work with http1.0 clients
*/
import com.sun.net.httpserver.*;
import java.util.concurrent.*;
import java.io.*;
import java.net.*;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_CHUNKED;
public class B6529200 {
public static void main (String[] args) throws Exception {
Handler handler = new Handler();
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress addr = new InetSocketAddress (loopback, 0);
HttpServer server = HttpServer.create (addr, 0);
HttpContext ctx = server.createContext ("/test", handler);
ExecutorService executor = Executors.newCachedThreadPool();
server.setExecutor (executor);
server.start ();
/* test 1: keep-alive */
Socket sock = new Socket (loopback, server.getAddress().getPort());
OutputStream os = sock.getOutputStream();
System.out.println ("GET /test/foo HTTP/1.0\r\nConnection: keep-alive\r\n\r\n");
os.write ("GET /test/foo HTTP/1.0\r\nConnection: keep-alive\r\n\r\n".getBytes());
os.flush();
InputStream is = sock.getInputStream();
StringBuffer s = new StringBuffer();
boolean finished = false;
sock.setSoTimeout (10 * 1000);
try {
while (!finished) {
char c = (char) is.read();
s.append (c);
finished = s.indexOf ("\r\n\r\nhello") != -1;
/* test will timeout otherwise */
}
} catch (SocketTimeoutException e) {
server.stop(0);
executor.shutdown ();
throw new RuntimeException ("Test failed in test1");
}
System.out.println (new String (s));
/* test 2: even though we request keep-alive, server must close
* because it is sending unknown content length response */
System.out.println("GET /test/foo HTTP/1.0\r\nConnection: keep-alive\r\n\r\n");
os.write ("GET /test/foo HTTP/1.0\r\nConnection: keep-alive\r\n\r\n".getBytes());
os.flush();
int i=0,c;
byte [] buf = new byte [8*1024];
try {
while ((c=is.read()) != -1) {
buf[i++] = (byte)c;
}
} catch (SocketTimeoutException e) {
server.stop(0);
executor.shutdown ();
throw new RuntimeException ("Test failed in test2");
}
String ss = new String (buf, "ISO-8859-1");
if (ss.indexOf ("\r\n\r\nhello world") == -1) {
server.stop(0);
executor.shutdown ();
throw new RuntimeException ("Test failed in test2: wrong string");
}
System.out.println (ss);
is.close ();
server.stop(0);
executor.shutdown();
}
static class Handler implements HttpHandler {
int invocation = 1;
public void handle (HttpExchange t)
throws IOException
{
InputStream is;
OutputStream os;
switch (invocation++) {
case 1:
is = t.getRequestBody();
while (is.read() != -1) ;
is.close();
t.sendResponseHeaders (200, "hello".length());
os = t.getResponseBody();
os.write ("hello".getBytes());
os.close();
break;
case 2:
is = t.getRequestBody();
while (is.read() != -1) ;
is.close();
t.sendResponseHeaders (200, RSPBODY_CHUNKED);
os = t.getResponseBody();
os.write ("hello world".getBytes());
os.close();
break;
}
}
}
}

View file

@ -0,0 +1,115 @@
/*
* Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6744329
* @summary Exception in light weight Http server
* @library /test/lib
* @run main B6744329
* @run main/othervm -Djava.net.preferIPv6Addresses=true B6744329
*/
import com.sun.net.httpserver.*;
import java.util.concurrent.*;
import java.io.*;
import java.net.*;
import jdk.test.lib.net.URIBuilder;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_CHUNKED;
public class B6744329 {
public static void main (String[] args) throws Exception {
Handler handler = new Handler();
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress addr = new InetSocketAddress (loopback, 0);
HttpServer server = HttpServer.create (addr, 0);
HttpContext ctx = server.createContext ("/test", handler);
ExecutorService executor = Executors.newCachedThreadPool();
server.setExecutor (executor);
server.start ();
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(server.getAddress().getPort())
.path("/test/foo.html")
.toURL();
HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
try {
InputStream is = urlc.getInputStream();
int c = 0;
while (is.read()!= -1) {
c ++;
}
System.out.println ("OK");
} catch (IOException e) {
System.out.println ("exception");
e.printStackTrace();
error = true;
}
server.stop(0);
executor.shutdown();
if (error) {
throw new RuntimeException ("Test failed");
}
}
public static boolean error = false;
/* this must be the same size as in ChunkedOutputStream.java
*/
final static int CHUNK_SIZE = 4096;
static class Handler implements HttpHandler {
int invocation = 1;
public void handle (HttpExchange t)
throws IOException
{
InputStream is = t.getRequestBody();
Headers map = t.getRequestHeaders();
Headers rmap = t.getResponseHeaders();
while (is.read () != -1) ;
is.close();
/* chunked response */
t.sendResponseHeaders (200, RSPBODY_CHUNKED);
OutputStream os = t.getResponseBody();
byte[] first = new byte [CHUNK_SIZE * 2];
byte[] second = new byte [2];
os.write (first);
os.write ('x');
os.write ('x');
/* An index out of bounds exception will be thrown
* below, which is caught by server, and connection
* will be closed. resulting in IOException to client
* - if bug present
*/
os.write ('x');
os.write ('x');
os.write ('x');
t.close();
}
}
}

View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import com.sun.net.httpserver.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.logging.*;
import java.io.*;
import java.net.*;
import jdk.test.lib.net.URIBuilder;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_CHUNKED;
/*
* @test
* @bug 6886436
* @summary HttpServer should not send a body with 204 response.
* @library /test/lib
* @comment We use othervm because this test configures logging handlers
* for the system wide "com.sun.net.httpserver" logger
* @run main/othervm ${test.main.class}
* @run main/othervm -Djava.net.preferIPv6Addresses=true ${test.main.class}
*/
public class B6886436 {
private static final Logger logger = Logger.getLogger ("com.sun.net.httpserver");
private static void setupLogging() {
final ConsoleHandler c = new ConsoleHandler();
c.setLevel(Level.WARNING);
logger.addHandler(c);
logger.setLevel(Level.WARNING);
}
public static void main (String[] args) throws Exception {
setupLogging(); // merely for debugging
Handler handler = new Handler();
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress addr = new InetSocketAddress (loopback, 0);
HttpServer server = HttpServer.create (addr, 0);
HttpContext ctx = server.createContext ("/test", handler);
ExecutorService executor = Executors.newCachedThreadPool();
server.setExecutor (executor);
server.start ();
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(server.getAddress().getPort())
.path("/test/foo.html")
.toURL();
HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
try {
InputStream is = urlc.getInputStream();
while (is.read()!= -1) ;
is.close ();
urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
urlc.setReadTimeout (3000);
is = urlc.getInputStream();
while (is.read()!= -1);
is.close ();
} catch (IOException e) {
server.stop(0);
executor.shutdown();
throw new RuntimeException ("Test failed");
}
server.stop(0);
executor.shutdown();
System.out.println ("OK");
}
public static boolean error = false;
static class Handler implements HttpHandler {
int invocation = 1;
public void handle (HttpExchange t)
throws IOException
{
InputStream is = t.getRequestBody();
Headers map = t.getRequestHeaders();
Headers rmap = t.getResponseHeaders();
while (is.read () != -1) ;
is.close();
// send a 204 response with an empty chunked body
t.sendResponseHeaders (204, RSPBODY_CHUNKED);
t.close();
}
}
}

View file

@ -0,0 +1,125 @@
/*
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import com.sun.net.httpserver.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.logging.*;
import java.io.*;
import java.net.*;
import jdk.test.lib.net.URIBuilder;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
/*
* @test
* @bug 8211420
* @library /test/lib
* @comment We use othervm because this test configures logging handlers
* for the system wide "com.sun.net.httpserver" logger
* @run main/othervm ${test.main.class}
* @run main/othervm -Djava.net.preferIPv6Addresses=true ${test.main.class}
* @summary
*/
public class B8211420 {
private static final Logger logger = Logger.getLogger("com.sun.net.httpserver");
private static void setupLogging() {
final ConsoleHandler c = new ConsoleHandler();
c.setLevel(Level.WARNING);
logger.addHandler(c);
logger.setLevel(Level.WARNING);
}
public static void main(String[] args) throws Exception {
setupLogging(); // merely for debugging
Handler handler = new Handler();
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress addr = new InetSocketAddress(loopback, 0);
HttpServer server = HttpServer.create(addr, 0);
HttpContext ctx = server.createContext("/test", handler);
ExecutorService executor = Executors.newCachedThreadPool();
server.setExecutor(executor);
server.start();
URL url = URIBuilder.newBuilder()
.scheme("http")
.host(server.getAddress().getAddress())
.port(server.getAddress().getPort())
.path("/test/foo.html")
.toURL();
HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
try {
InputStream is = urlc.getInputStream();
while (is.read()!= -1) ;
is.close ();
String prop = urlc.getHeaderField("Content-length");
System.out.println("Content-length = " + prop + " should be null");
if (prop != null)
throw new RuntimeException("Content-length was present");
urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
is = urlc.getInputStream();
while (is.read()!= -1) ;
is.close();
if (urlc.getResponseCode() != 304) // expected for 2nd test
throw new RuntimeException("wrong response code");
String clen = urlc.getHeaderField("Content-length");
System.out.println("Content-length = " + clen + " should be 99");
System.out.println("len = " + clen.length());
if (clen == null || !clen.equals("99"))
throw new RuntimeException("Content-length not present or has wrong value");
System.out.println("OK");
} finally {
server.stop(0);
executor.shutdown();
}
}
public static boolean error = false;
static class Handler implements HttpHandler {
volatile int invocation = 1;
public void handle (HttpExchange t)
throws IOException
{
InputStream is = t.getRequestBody();
Headers map = t.getRequestHeaders();
Headers rmap = t.getResponseHeaders();
while (is.read() != -1) ;
is.close();
if (invocation++ == 1) {
// send a 204 response with no body
t.sendResponseHeaders(204, RSPBODY_EMPTY);
t.close();
} else {
// send a 304 response with no body but with content - length
rmap.add("Content-length", "99");
t.sendResponseHeaders(304, RSPBODY_EMPTY);
t.close();
}
}
}
}

View file

@ -0,0 +1,108 @@
/*
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8230159 8275534
* @library /test/lib
* @summary Ensure that correct exceptions are being thrown in
* BasicAuthenticator constructor
* @run junit BasicAuthenticatorExceptionCheck
*/
import java.nio.charset.Charset;
import com.sun.net.httpserver.BasicAuthenticator;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static java.nio.charset.StandardCharsets.UTF_8;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class BasicAuthenticatorExceptionCheck {
static final Class<NullPointerException> NPE = NullPointerException.class;
static final Class<IllegalArgumentException> IAE = IllegalArgumentException.class;
static BasicAuthenticator createBasicAuthenticator(String realm, Charset charset) {
return new BasicAuthenticator(realm, charset) {
public boolean checkCredentials(String username, String pw) {
return true;
}
};
}
static BasicAuthenticator createBasicAuthenticator(String realm) {
return new BasicAuthenticator(realm) {
public boolean checkCredentials(String username, String pw) {
return true;
}
};
}
@Test
public void testAuthenticationException() {
Throwable ex = Assertions.assertThrows(NPE, () ->
createBasicAuthenticator("/test", null));
System.out.println("Valid realm and Null charset provided - " +
"NullPointerException thrown as expected: " + ex);
ex = Assertions.assertThrows(NPE, () ->
createBasicAuthenticator(null, UTF_8));
System.out.println("Null realm and valid charset provided - " +
"NullPointerException thrown as expected: " + ex);
ex = Assertions.assertThrows(IAE, () ->
createBasicAuthenticator("", UTF_8));
assertEquals("realm must not be empty", ex.getMessage());
System.out.println("Empty string for realm and valid charset provided - " +
"IllegalArgumentException thrown as expected: " + ex);
ex = Assertions.assertThrows(NPE, () ->
createBasicAuthenticator(null));
System.out.println("Null realm provided - " +
"NullPointerException thrown as expected: " + ex);
ex = Assertions.assertThrows(IAE, () ->
createBasicAuthenticator(""));
assertEquals("realm must not be empty", ex.getMessage());
System.out.println("Empty string for realm provided - " +
"IllegalArgumentException thrown as expected: " + ex);
ex = Assertions.assertThrows(IAE, () ->
createBasicAuthenticator("\"/test\""));
assertEquals("realm invalid: \"/test\"", ex.getMessage());
System.out.println("Invalid string for realm provided - " +
"IllegalArgumentException thrown as expected: " + ex);
ex = Assertions.assertThrows(IAE, () ->
createBasicAuthenticator("\""));
assertEquals("realm invalid: \"", ex.getMessage());
System.out.println("Invalid string for realm provided - " +
"IllegalArgumentException thrown as expected: " + ex);
createBasicAuthenticator("\\\"/test\\\"");
}
}

View file

@ -0,0 +1,134 @@
/*
* Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import jdk.test.lib.net.URIBuilder;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.*;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
/*
* @test
* @bug 8219083
* @summary Exceptions thrown from HttpHandler.handle should not close connection
* if response is completed
* @library /test/lib
* @comment We use othervm because this test configures logging handlers
* for the system wide "com.sun.net.httpserver" logger
* @run junit/othervm ${test.main.class}
*/
public class ExceptionKeepAlive {
public static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver");
private static void setupLogging() {
final Handler handler = new ConsoleHandler();
handler.setLevel(Level.FINEST);
LOGGER.setLevel(Level.FINEST);
LOGGER.addHandler(handler);
}
@Test
void test() throws IOException, InterruptedException {
HttpServer httpServer = startHttpServer();
int port = httpServer.getAddress().getPort();
try {
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/firstCall")
.toURLUnchecked();
HttpURLConnection uc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
int responseCode = uc.getResponseCode();
assertEquals(200, responseCode, "First request should succeed");
URL url2 = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/secondCall")
.toURLUnchecked();
HttpURLConnection uc2 = (HttpURLConnection)url2.openConnection(Proxy.NO_PROXY);
responseCode = uc2.getResponseCode();
assertEquals(200, responseCode, "Second request should reuse connection");
} finally {
httpServer.stop(0);
}
}
/**
* Http Server
*/
HttpServer startHttpServer() throws IOException {
setupLogging(); // merely for debugging
InetAddress loopback = InetAddress.getLoopbackAddress();
HttpServer httpServer = HttpServer.create(new InetSocketAddress(loopback, 0), 0);
httpServer.createContext("/", new MyHandler());
httpServer.start();
return httpServer;
}
class MyHandler implements HttpHandler {
volatile int port1;
@Override
public void handle(HttpExchange t) throws IOException {
String path = t.getRequestURI().getPath();
if (path.equals("/firstCall")) {
port1 = t.getRemoteAddress().getPort();
System.out.println("First connection on client port = " + port1);
// send response
t.sendResponseHeaders(200, RSPBODY_EMPTY);
// response is completed now; throw exception
throw new NumberFormatException();
// the connection should still be reusable
} else if (path.equals("/secondCall")) {
int port2 = t.getRemoteAddress().getPort();
System.out.println("Second connection on client port = " + port2);
if (port1 == port2) {
t.sendResponseHeaders(200, RSPBODY_EMPTY);
} else {
t.sendResponseHeaders(500, RSPBODY_EMPTY);
}
}
t.close();
}
}
}

View file

@ -0,0 +1,162 @@
/*
* Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.util.logging.*;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import jdk.test.lib.net.URIBuilder;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
/*
* @test
* @bug 6756771 6755625
* @summary com.sun.net.httpserver.HttpServer should handle POSTs larger than 2Gig
* @library /test/lib
* @comment We use othervm because this test configures logging handlers
* for the system wide "com.sun.net.httpserver" logger
* @run main/othervm ${test.main.class}
* @run main/othervm -Djava.net.preferIPv6Addresses=true ${test.main.class}
*/
public class FixedLengthInputStream {
static final long POST_SIZE = 4L * 1024L * 1024L * 1024L; // 4Gig
private static final Logger logger = Logger.getLogger("com.sun.net.httpserver");
void test(String[] args) throws IOException {
HttpServer httpServer = startHttpServer();
int port = httpServer.getAddress().getPort();
try {
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/flis/")
.toURLUnchecked();
HttpURLConnection uc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
uc.setDoOutput(true);
uc.setRequestMethod("POST");
uc.setFixedLengthStreamingMode(POST_SIZE);
OutputStream os = uc.getOutputStream();
/* create a 32K byte array with data to POST */
int thirtyTwoK = 32 * 1024;
byte[] ba = new byte[thirtyTwoK];
for (int i =0; i<thirtyTwoK; i++)
ba[i] = (byte)i;
long times = POST_SIZE / thirtyTwoK;
for (int i=0; i<times; i++) {
os.write(ba);
}
os.close();
InputStream is = uc.getInputStream();
while(is.read(ba) != -1);
is.close();
pass();
} finally {
httpServer.stop(0);
}
}
private static void setupLogging() {
final ConsoleHandler handler = new ConsoleHandler();
handler.setLevel(Level.FINEST);
logger.setLevel(Level.FINEST);
logger.addHandler(handler);
}
/**
* Http Server
*/
HttpServer startHttpServer() throws IOException {
if (debug) {
setupLogging(); // merely for debugging
}
InetAddress loopback = InetAddress.getLoopbackAddress();
HttpServer httpServer = HttpServer.create(new InetSocketAddress(loopback, 0), 0);
httpServer.createContext("/flis/", new MyHandler(POST_SIZE));
httpServer.start();
return httpServer;
}
class MyHandler implements HttpHandler {
static final int BUFFER_SIZE = 32 * 1024;
long expected;
MyHandler(long expected){
this.expected = expected;
}
@Override
public void handle(HttpExchange t) throws IOException {
InputStream is = t.getRequestBody();
byte[] ba = new byte[BUFFER_SIZE];
int read;
long count = 0L;
while((read = is.read(ba)) != -1) {
count += read;
}
is.close();
check(count == expected, "Expected: " + expected + ", received "
+ count);
debug("Received " + count + " bytes");
t.sendResponseHeaders(200, RSPBODY_EMPTY);
t.close();
}
}
//--------------------- Infrastructure ---------------------------
boolean debug = true;
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);}
void debug(String message) {if(debug) { System.out.println(message); } }
public static void main(String[] args) throws Throwable {
Class<?> k = new Object(){}.getClass().getEnclosingClass();
try {k.getMethod("instanceMain",String[].class)
.invoke( k.newInstance(), (Object) args);}
catch (Throwable e) {throw e.getCause();}}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,438 @@
/*
* Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Locale;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import jdk.test.lib.net.SimpleSSLContext;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
/*
* @test
* @bug 8218554
* @summary test that the handler can request a connection close.
* @library /test/lib
* @build jdk.test.lib.net.SimpleSSLContext
* @comment We use othervm because this test configures logging handlers
* for the system wide "com.sun.net.httpserver" logger
* @run main/othervm ${test.main.class}
*/
public class HandlerConnectionClose {
static final int ONEK = 1024;
static final long POST_SIZE = ONEK * 1L;
private static final SSLContext sslContext = SimpleSSLContext.findSSLContext();
private static final Logger logger = Logger.getLogger("com.sun.net.httpserver");
void test(String[] args) throws Exception {
HttpServer httpServer = startHttpServer("http");
try {
testHttpURLConnection(httpServer, "http","/close/legacy/http/chunked");
testHttpURLConnection(httpServer, "http","/close/legacy/http/fixed");
testPlainSocket(httpServer, "http","/close/plain/http/chunked");
testPlainSocket(httpServer, "http","/close/plain/http/fixed");
} finally {
httpServer.stop(0);
}
HttpServer httpsServer = startHttpServer("https");
try {
testHttpURLConnection(httpsServer, "https","/close/legacy/https/chunked");
testHttpURLConnection(httpsServer, "https","/close/legacy/https/fixed");
testPlainSocket(httpsServer, "https","/close/plain/https/chunked");
testPlainSocket(httpsServer, "https","/close/plain/https/fixed");
} finally{
httpsServer.stop(0);
}
}
void testHttpURLConnection(HttpServer httpServer, String protocol, String path) throws Exception {
int port = httpServer.getAddress().getPort();
String host = httpServer.getAddress().getHostString();
URL url = new URI(protocol, null, host, port, path, null, null).toURL();
HttpURLConnection uc = (HttpURLConnection) url.openConnection();
if ("https".equalsIgnoreCase(protocol)) {
((HttpsURLConnection)uc).setSSLSocketFactory(sslContext.getSocketFactory());
((HttpsURLConnection)uc).setHostnameVerifier((String hostname, SSLSession session) -> true);
}
uc.setDoOutput(true);
uc.setRequestMethod("POST");
uc.setFixedLengthStreamingMode(POST_SIZE);
OutputStream os = uc.getOutputStream();
/* create a 1K byte array with data to POST */
byte[] ba = new byte[ONEK];
for (int i = 0; i < ONEK; i++)
ba[i] = (byte) i;
System.out.println("\n" + uc.getClass().getSimpleName() +": POST " + url + " HTTP/1.1");
long times = POST_SIZE / ONEK;
for (int i = 0; i < times; i++) {
os.write(ba);
}
os.close();
InputStream is = uc.getInputStream();
int read;
long count = 0;
while ((read = is.read(ba)) != -1) {
for (int i = 0; i < read; i++) {
byte expected = (byte) count++;
if (ba[i] != expected) {
throw new IOException("byte mismatch at "
+ (count - 1) + ": expected " + expected + " got " + ba[i]);
}
}
}
if (count != POST_SIZE) {
throw new IOException("Unexpected length: " + count + " expected " + POST_SIZE);
}
is.close();
pass();
}
void testPlainSocket(HttpServer httpServer, String protocol, String path) throws Exception {
int port = httpServer.getAddress().getPort();
String host = httpServer.getAddress().getHostString();
URL url = new URI(protocol, null, host, port, path, null, null).toURL();
Socket socket;
if ("https".equalsIgnoreCase(protocol)) {
socket = sslContext.getSocketFactory().createSocket(host, port);
} else {
socket = new Socket(host, port);
}
try (Socket sock = socket) {
OutputStream os = socket.getOutputStream();
// send request headers
String request = new StringBuilder()
.append("POST ").append(path).append(" HTTP/1.1").append("\r\n")
.append("host: ").append(host).append(':').append(port).append("\r\n")
.append("Content-Length: ").append(POST_SIZE).append("\r\n")
.append("\r\n")
.toString();
os.write(request.getBytes(StandardCharsets.US_ASCII));
/* create a 1K byte array with data to POST */
byte[] ba = new byte[ONEK];
for (int i = 0; i < ONEK; i++)
ba[i] = (byte) i;
// send request data
long times = POST_SIZE / ONEK;
for (int i = 0; i < times; i++) {
os.write(ba);
}
os.flush();
InputStream is = socket.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// read all response headers
int c;
int crlf = 0;
while ((c = is.read()) != -1) {
if (c == '\r') continue;
if (c == '\n') crlf++;
else crlf = 0;
bos.write(c);
if (crlf == 2) break;
}
String responseHeadersStr = bos.toString(StandardCharsets.US_ASCII);
List<String> responseHeaders = List.of(responseHeadersStr.split("\n"));
System.out.println("\nPOST " + url + " HTTP/1.1");
responseHeaders.stream().forEach(s -> System.out.println("[reply]\t" + s));
String statusLine = responseHeaders.get(0);
if (!statusLine.startsWith("HTTP/1.1 200 "))
throw new IOException("Unexpected status: " + statusLine);
String cl = responseHeaders.stream()
.map(s -> s.toLowerCase(Locale.ROOT))
.filter(s -> s.startsWith("content-length: "))
.findFirst()
.orElse(null);
String te = responseHeaders.stream()
.map(s -> s.toLowerCase(Locale.ROOT))
.filter(s -> s.startsWith("transfer-encoding: "))
.findFirst()
.orElse(null);
// check content-length and transfer-encoding are as expected
int read = 0;
long count = 0;
if (path.endsWith("/fixed")) {
if (!("content-length: " + POST_SIZE).equalsIgnoreCase(cl)) {
throw new IOException("Unexpected Content-Length: [" + cl + "]");
}
if (te != null) {
throw new IOException("Unexpected Transfer-Encoding: [" + te + "]");
}
// Got expected Content-Length: 1024 - read response data
while ((read = is.read()) != -1) {
int expected = (int) (count & 0xFF);
if ((read & 0xFF) != expected) {
throw new IOException("byte mismatch at "
+ (count - 1) + ": expected " + expected + " got " + read);
}
if (++count == POST_SIZE) break;
}
} else if (cl != null) {
throw new IOException("Unexpected Content-Length: [" + cl + "]");
} else {
if (!("transfer-encoding: chunked").equalsIgnoreCase(te)) {
throw new IOException("Unexpected Transfer-Encoding: [" + te + "]");
}
// This is a quick & dirty implementation of
// chunk decoding - no trailers - no extensions
StringBuilder chunks = new StringBuilder();
int cs = -1;
while (cs != 0) {
cs = 0;
chunks.setLength(0);
// read next chunk length
while ((read = is.read()) != -1) {
if (read == '\r') continue;
if (read == '\n') break;
chunks.append((char) read);
}
cs = Integer.parseInt(chunks.toString().trim(), 16);
System.out.println("Got chunk length: " + cs);
// If chunk size is 0, then we have read the last chunk.
if (cs == 0) break;
// Read the chunk data
while (--cs >= 0) {
read = is.read();
if (read == -1) break; // EOF
int expected = (int) (count & 0xFF);
if ((read & 0xFF) != expected) {
throw new IOException("byte mismatch at "
+ (count - 1) + ": expected " + expected + " got " + read);
}
// This is cheating: we know the size :-)
if (++count == POST_SIZE) break;
}
if (read == -1) {
throw new IOException("Unexpected EOF after " + count + " data bytes");
}
// read CRLF
if ((read = is.read()) != '\r') {
throw new IOException("Expected CR at " + count + "after chunk data - got " + read);
}
if ((read = is.read()) != '\n') {
throw new IOException("Expected LF at " + count + "after chunk data - got " + read);
}
if (cs == 0 && count == POST_SIZE) {
cs = -1;
}
if (cs != -1) {
// count == POST_SIZE, but some chunk data still to be read?
throw new IOException("Unexpected chunk size, "
+ cs + " bytes still to read after " + count +
" data bytes received.");
}
}
// Last CRLF?
for (int i = 0; i < 2; i++) {
if ((read = is.read()) == -1) break;
}
}
if (count != POST_SIZE) {
throw new IOException("Unexpected length: " + count + " expected " + POST_SIZE);
}
if (!sock.isClosed()) {
try {
// We send an end request to the server to verify that the
// connection is closed. If the server has not closed the
// connection, it will reply. If we receive a response,
// we should fail...
String endrequest = new StringBuilder()
.append("GET ").append("/close/end").append(" HTTP/1.1").append("\r\n")
.append("host: ").append(host).append(':').append(port).append("\r\n")
.append("Content-Length: ").append(0).append("\r\n")
.append("\r\n")
.toString();
os.write(endrequest.getBytes(StandardCharsets.US_ASCII));
os.flush();
StringBuilder resp = new StringBuilder();
crlf = 0;
// read all headers.
// If the server closed the connection as expected
// we should immediately read EOF
while ((read = is.read()) != -1) {
if (read == '\r') continue;
if (read == '\n') crlf++;
else crlf = 0;
if (crlf == 2) break;
resp.append((char) read);
}
List<String> lines = List.of(resp.toString().split("\n"));
if (read != -1 || resp.length() != 0) {
System.err.println("Connection not closed!");
System.err.println("Got: ");
lines.stream().forEach(s -> System.err.println("[end]\t" + s));
throw new AssertionError("EOF not received after " + count + " data bytes");
}
if (read != -1) {
throw new AssertionError("EOF was expected after " + count + " bytes, but got: " + read);
} else {
System.out.println("Got expected EOF (" + read + ")");
}
} catch (IOException x) {
// expected! all is well
System.out.println("Socket closed as expected, got exception writing to it.");
}
} else {
System.out.println("Socket closed as expected");
}
pass();
}
}
private static void setupLogging() {
final Handler handler = new ConsoleHandler();
handler.setLevel(Level.FINEST);
logger.setLevel(Level.FINEST);
logger.addHandler(handler);
}
/**
* Http Server
*/
HttpServer startHttpServer(String protocol) throws IOException {
if (debug) {
setupLogging(); // merely for debugging
}
InetSocketAddress serverAddress = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
HttpServer httpServer = null;
if ("http".equalsIgnoreCase(protocol)) {
httpServer = HttpServer.create(serverAddress, 0);
}
if ("https".equalsIgnoreCase(protocol)) {
HttpsServer httpsServer = HttpsServer.create(serverAddress, 0);
httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext));
httpServer = httpsServer;
}
httpServer.createContext("/close/", new MyHandler(POST_SIZE));
System.out.println("Server created at: " + httpServer.getAddress());
httpServer.start();
return httpServer;
}
class MyHandler implements HttpHandler {
static final int BUFFER_SIZE = 512;
final long expected;
MyHandler(long expected){
this.expected = expected;
}
@Override
public void handle(HttpExchange t) throws IOException {
System.out.println("Server: serving " + t.getRequestURI());
boolean chunked = t.getRequestURI().getPath().endsWith("/chunked");
boolean fixed = t.getRequestURI().getPath().endsWith("/fixed");
boolean end = t.getRequestURI().getPath().endsWith("/end");
long responseLength = fixed ? POST_SIZE : 0;
responseLength = end ? -1 : responseLength;
responseLength = chunked ? 0 : responseLength;
if (!end) t.getResponseHeaders().add("connection", "CLose");
t.sendResponseHeaders(200, responseLength);
if (!end) {
OutputStream os = t.getResponseBody();
InputStream is = t.getRequestBody();
byte[] ba = new byte[BUFFER_SIZE];
int read;
long count = 0L;
while ((read = is.read(ba)) != -1) {
count += read;
os.write(ba, 0, read);
}
is.close();
check(count == expected, "Expected: " + expected + ", received "
+ count);
debug("Received " + count + " bytes");
os.close();
}
t.close();
}
}
//--------------------- Infrastructure ---------------------------
boolean debug = true;
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);}
void debug(String message) {if(debug) { System.out.println(message); } }
public static void main(String[] args) throws Throwable {
Class<?> k = new Object(){}.getClass().getEnclosingClass();
try {k.getMethod("instanceMain",String[].class)
.invoke( k.newInstance(), (Object) args);}
catch (Throwable e) {throw e.getCause();}}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,131 @@
/*
* Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import jdk.test.lib.net.URIBuilder;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.*;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
/*
* @test
* @bug 8304963
* @summary Connection should be reusable after HEAD request
* @library /test/lib
* @comment We use othervm because this test configures logging handlers
* for the system wide "com.sun.net.httpserver" logger
* @run junit/othervm ${test.main.class}
*/
public class HeadKeepAlive {
private static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver");
private static void setupLogging() {
final Handler handler = new ConsoleHandler();
handler.setLevel(Level.FINEST);
LOGGER.setLevel(Level.FINEST);
LOGGER.addHandler(handler);
}
@Test
void test() throws IOException, InterruptedException {
HttpServer httpServer = startHttpServer();
int port = httpServer.getAddress().getPort();
try {
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/firstCall")
.toURLUnchecked();
HttpURLConnection uc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
uc.setRequestMethod("HEAD");
int responseCode = uc.getResponseCode();
assertEquals(200, responseCode, "First request should succeed");
URL url2 = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/secondCall")
.toURLUnchecked();
HttpURLConnection uc2 = (HttpURLConnection)url2.openConnection(Proxy.NO_PROXY);
uc2.setRequestMethod("HEAD");
responseCode = uc2.getResponseCode();
assertEquals(200, responseCode, "Second request should reuse connection");
} finally {
httpServer.stop(0);
}
}
/**
* Http Server
*/
HttpServer startHttpServer() throws IOException {
setupLogging(); // merely for debugging
InetAddress loopback = InetAddress.getLoopbackAddress();
HttpServer httpServer = HttpServer.create(new InetSocketAddress(loopback, 0), 0);
httpServer.createContext("/", new MyHandler());
httpServer.start();
return httpServer;
}
class MyHandler implements HttpHandler {
volatile int port1;
@Override
public void handle(HttpExchange t) throws IOException {
String path = t.getRequestURI().getPath();
if (path.equals("/firstCall")) {
port1 = t.getRemoteAddress().getPort();
System.out.println("First connection on client port = " + port1);
// send response
t.sendResponseHeaders(200, RSPBODY_EMPTY);
// the connection should still be reusable
} else if (path.equals("/secondCall")) {
int port2 = t.getRemoteAddress().getPort();
System.out.println("Second connection on client port = " + port2);
if (port1 == port2) {
t.sendResponseHeaders(200, RSPBODY_EMPTY);
} else {
t.sendResponseHeaders(500, RSPBODY_EMPTY);
}
}
t.close();
}
}
}

View file

@ -0,0 +1,131 @@
/*
* Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6886723
* @library /test/lib
* @run main HeadTest
* @run main/othervm -Djava.net.preferIPv6Addresses=true HeadTest
* @summary light weight http server doesn't return correct status code for HEAD requests
*/
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import jdk.test.lib.net.URIBuilder;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
public class HeadTest {
public static void main(String[] args) throws Exception {
server();
}
static void server() throws Exception {
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress inetAddress = new InetSocketAddress(loopback, 0);
HttpServer server = HttpServer.create(inetAddress, 5);
try {
server.setExecutor(Executors.newFixedThreadPool(5));
HttpContext chunkedContext = server.createContext("/chunked");
chunkedContext.setHandler(new HttpHandler() {
@Override
public void handle(HttpExchange msg) {
try {
try {
if (msg.getRequestMethod().equals("HEAD")) {
msg.getRequestBody().close();
msg.getResponseHeaders().add("Transfer-encoding", "chunked");
msg.sendResponseHeaders(200, RSPBODY_EMPTY);
}
} catch(IOException ioe) {
ioe.printStackTrace();
}
} finally {
msg.close();
}
}
});
HttpContext clContext = server.createContext("/content");
clContext.setHandler(new HttpHandler() {
@Override
public void handle(HttpExchange msg) {
try {
try {
if (msg.getRequestMethod().equals("HEAD")) {
msg.getRequestBody().close();
msg.getResponseHeaders().add("Content-length", "1024");
msg.sendResponseHeaders(200, RSPBODY_EMPTY);
}
} catch(IOException ioe) {
ioe.printStackTrace();
}
} finally {
msg.close();
}
}
});
server.start();
String urlStr = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(server.getAddress().getPort())
.path("/")
.build()
.toString();
System.out.println("Server is at " + urlStr);
// Run the chunked client
for(int i=0; i < 10; i++) {
runClient(urlStr + "chunked/");
}
// Run the content length client
for(int i=0; i < 10; i++) {
runClient(urlStr + "content/");
}
} finally {
// Stop the server
((ExecutorService)server.getExecutor()).shutdown();
server.stop(0);
}
}
static void runClient(String urlStr) throws Exception {
HttpURLConnection conn = (HttpURLConnection) new URL(urlStr).openConnection(Proxy.NO_PROXY);
conn.setRequestMethod("HEAD");
int status = conn.getResponseCode();
if (status != 200) {
throw new RuntimeException("HEAD request doesn't return 200, but returns " + status);
}
}
}

View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import com.sun.net.httpserver.*;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import jdk.test.lib.net.URIBuilder;
import sun.net.httpserver.HttpExchangeAccess;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
/**
* @test
* @bug 8203036
* @library /test/lib
* @modules jdk.httpserver/sun.net.httpserver
* @build jdk.httpserver/sun.net.httpserver.HttpExchangeAccess AutoCloseableHttpExchange
* @run main/othervm AutoCloseableHttpExchange
* @summary Ensure that HttpExchange closes correctly when utilising the
* AutoCloseable interface e.g. both request InputStream and response OutputStream
* are closed, if not already.
*/
public class AutoCloseableHttpExchange {
static HttpServer testHttpServer;
static AtomicBoolean exchangeCloseFail = new AtomicBoolean(false);
static class Handler implements HttpHandler {
private CountDownLatch latch;
Handler(CountDownLatch latch) {
this.latch = latch;
}
public void handle(HttpExchange t) throws IOException {
InputStream is = t.getRequestBody();
try (HttpExchange e = t) {
while (is.read() != -1) ;
t.sendResponseHeaders(200, RSPBODY_EMPTY);
}
if (!HttpExchangeAccess.isClosed(t)) {
exchangeCloseFail.set(true);
}
latch.countDown();
}
}
static void connectAndCheck(String realm) throws Exception {
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(testHttpServer.getAddress().getPort())
.path(realm)
.toURL();
HttpURLConnection testConnection = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
InputStream is = testConnection.getInputStream();
while (is.read() != -1) ;
is.close();
}
public static void main(String[] args) throws Exception {
int CONNECTION_COUNT = 5;
CountDownLatch latch = new CountDownLatch(CONNECTION_COUNT);
InetSocketAddress addr = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
testHttpServer = HttpServer.create(addr, 0);
testHttpServer.createContext("/test", new Handler(latch));
ExecutorService executor = Executors.newFixedThreadPool(CONNECTION_COUNT);
testHttpServer.setExecutor(executor);
testHttpServer.start();
while (CONNECTION_COUNT-- != 0) {
connectAndCheck("/test");
}
latch.await();
testHttpServer.stop(0);
executor.shutdown();
if (exchangeCloseFail.get())
throw new RuntimeException("The exchange was not closed properly");
}
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver;
public class HttpExchangeAccess {
public static boolean isClosed(com.sun.net.httpserver.HttpExchange exch) {
synchronized (exch) {
return ((HttpExchangeImpl) exch).getExchangeImpl().closed;
}
}
}

View file

@ -0,0 +1,139 @@
/*
* Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
/*
* @test
* @bug 8190793
* @summary Httpserver does not detect truncated request body
* @comment We use othervm because this test configures logging handlers
* for the system wide "com.sun.net.httpserver" logger
* @run main/othervm ${test.main.class}
*/
/*
* Send two POST requests to the server which are both trucated
* and socket closed. Server needs to detect this and throw an IOException
* in getRequestBody().read(). Two variants for fixed length and chunked.
*/
public class TruncatedRequestBody {
private static final Logger logger = Logger.getLogger("com.sun.net.httpserver");
static volatile boolean error = false;
static CountDownLatch latch = new CountDownLatch(2);
static class Handler implements HttpHandler {
@Override
public void handle(HttpExchange exch) throws IOException {
InputStream is = exch.getRequestBody();
int c, count = 0;
byte[] buf = new byte[128];
try {
while ((c=is.read(buf)) > 0)
count += c;
} catch (IOException e) {
System.out.println("Exception caught");
latch.countDown();
throw e;
}
// shouldn't get to here
error = true;
latch.countDown();
System.out.println("Read " + count + " bytes");
is.close();
exch.sendResponseHeaders(200, RSPBODY_EMPTY);
}
}
private static void setupLogging() {
final ConsoleHandler h = new ConsoleHandler();
h.setLevel(Level.ALL);
logger.setLevel(Level.ALL);
logger.addHandler(h);
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException, InterruptedException {
setupLogging(); // merely for debugging
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress addr = new InetSocketAddress(loopback, 0);
HttpServer server = HttpServer.create(addr, 10);
HttpContext ct = server.createContext("/", new Handler());
ExecutorService ex = Executors.newCachedThreadPool();
server.setExecutor(ex);
server.start();
int port = server.getAddress().getPort();
// Test 1: fixed length
Socket sock = new Socket(loopback, port);
String s1 = "POST /foo HTTP/1.1\r\nContent-length: 200000\r\n"
+ "\r\nfoo bar99";
OutputStream os = sock.getOutputStream();
os.write(s1.getBytes(StandardCharsets.ISO_8859_1));
Thread.sleep(500);
sock.close();
// Test 2: chunked
String s2 = "POST /foo HTTP/1.1\r\nTransfer-encoding: chunked\r\n\r\n" +
"100\r\nFoo bar";
sock = new Socket(loopback, port);
os = sock.getOutputStream();
os.write(s2.getBytes(StandardCharsets.ISO_8859_1));
Thread.sleep(500);
sock.close();
latch.await();
server.stop(0);
ex.shutdownNow();
if (error)
throw new RuntimeException("Test failed");
}
}

View file

@ -0,0 +1,118 @@
/*
* Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import jdk.test.lib.net.URIBuilder;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.concurrent.CountDownLatch;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.*;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
/*
* @test
* @bug 8219083
* @summary HttpExchange.getResponseBody write and close should not throw
* even when response length is zero
* @library /test/lib
* @comment We use othervm because this test configures logging handlers
* for the system wide "com.sun.net.httpserver" logger
* @run junit/othervm ${test.main.class}
*/
public class ZeroLengthOutputStream {
private static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver");
public volatile boolean closed;
public CountDownLatch cdl = new CountDownLatch(1);
@Test
void test() throws IOException, InterruptedException {
HttpServer httpServer = startHttpServer();
int port = httpServer.getAddress().getPort();
try {
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.path("/flis/")
.toURLUnchecked();
HttpURLConnection uc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
uc.getResponseCode();
cdl.await();
assertTrue(closed, "OutputStream close did not complete");
} finally {
httpServer.stop(0);
}
}
private static void setupLogging() {
final Handler handler = new ConsoleHandler();
handler.setLevel(Level.FINEST);
LOGGER.setLevel(Level.FINEST);
LOGGER.addHandler(handler);
}
/**
* Http Server
*/
HttpServer startHttpServer() throws IOException {
setupLogging(); // merely for debugging
InetAddress loopback = InetAddress.getLoopbackAddress();
HttpServer httpServer = HttpServer.create(new InetSocketAddress(loopback, 0), 0);
httpServer.createContext("/flis/", new MyHandler());
httpServer.start();
return httpServer;
}
class MyHandler implements HttpHandler {
@Override
public void handle(HttpExchange t) throws IOException {
try {
OutputStream os = t.getResponseBody();
t.sendResponseHeaders(200, RSPBODY_EMPTY);
os.write(new byte[0]);
os.close();
System.out.println("Output stream closed");
closed = true;
} finally {
cdl.countDown();
}
}
}
}