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,143 @@
/*
* Copyright (c) 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 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.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
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.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNull;
/*
* @test
* @bug 8359709
* @summary verify that if the Host header is allowed to be set by the application
* then the correct value gets set in a HTTP request issued through
* java.net.HttpURLConnection
* @library /test/lib
* @run junit HostHeaderTest
* @run junit/othervm -Dsun.net.http.allowRestrictedHeaders=true HostHeaderTest
* @run junit/othervm -Dsun.net.http.allowRestrictedHeaders=false HostHeaderTest
*/
class HostHeaderTest {
private static final String SERVER_CTX_ROOT = "/8359709/";
private static final boolean allowsHostHeader = Boolean.getBoolean("sun.net.http.allowRestrictedHeaders");
private static HttpServer server;
@BeforeAll
static void beforeAll() throws Exception {
final InetSocketAddress addr = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
server = HttpServer.create(addr, 0);
server.createContext(SERVER_CTX_ROOT, new Handler());
server.start();
System.err.println("started server at " + server.getAddress());
}
@AfterAll
static void afterAll() throws Exception {
if (server != null) {
System.err.println("stopping server " + server.getAddress());
server.stop(0);
}
}
@Test
void testHostHeader() throws Exception {
final InetSocketAddress serverAddr = server.getAddress();
final URL reqURL = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(serverAddr.getPort())
.path(SERVER_CTX_ROOT)
.build().toURL();
final URLConnection conn = reqURL.openConnection(Proxy.NO_PROXY);
conn.setRequestProperty("Host", "foobar");
if (!allowsHostHeader) {
// if restricted headers aren't allowed to be set by the user, then
// we expect the previous call to setRequestProperty to not set the Host
// header
assertNull(conn.getRequestProperty("Host"), "Host header unexpectedly set");
}
assertInstanceOf(HttpURLConnection.class, conn);
final HttpURLConnection httpURLConn = (HttpURLConnection) conn;
// send the HTTP request
System.err.println("sending request " + reqURL);
final int respCode = httpURLConn.getResponseCode();
assertEquals(200, respCode, "unexpected response code");
// verify that the server side handler received the expected
// Host header value in the request
try (final InputStream is = httpURLConn.getInputStream()) {
final byte[] resp = is.readAllBytes();
// if Host header wasn't explicitly set, then we expect it to be
// derived from the request URL
final String expected = allowsHostHeader
? "foobar"
: reqURL.getHost() + ":" + reqURL.getPort();
final String actual = new String(resp, US_ASCII);
assertEquals(expected, actual, "unexpected Host header received on server side");
}
}
private static final class Handler implements HttpHandler {
private static final int NO_RESPONSE_BODY = -1;
@Override
public void handle(final HttpExchange exchange) throws IOException {
final List<String> headerVals = exchange.getRequestHeaders().get("Host");
System.err.println("Host header has value(s): " + headerVals);
// unexpected Host header value, respond with 400 status code
if (headerVals == null || headerVals.size() != 1) {
System.err.println("Unexpected header value(s) for Host header: " + headerVals);
exchange.sendResponseHeaders(400, NO_RESPONSE_BODY);
return;
}
// respond back with the Host header value that we found in the request
final byte[] response = headerVals.getFirst().getBytes(US_ASCII);
exchange.sendResponseHeaders(200, response.length);
try (final OutputStream os = exchange.getResponseBody()) {
os.write(response);
}
}
}
}

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 2001, 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 4473092
* @library /test/lib
* @summary Method throws IOException when object should be returned
* @run main HttpResponseCode
* @run main/othervm -Djava.net.preferIPv6Addresses=true HttpResponseCode
*/
import java.net.*;
import java.io.*;
import jdk.test.lib.net.URIBuilder;
public class HttpResponseCode implements Runnable {
ServerSocket ss;
/*
* Our "http" server
*/
public void run() {
try {
Socket s = ss.accept();
BufferedReader in = new BufferedReader(
new InputStreamReader(s.getInputStream()) );
String req = in.readLine();
PrintStream out = new PrintStream(
new BufferedOutputStream(
s.getOutputStream() ));
/* send the header */
out.print("HTTP/1.1 403 Forbidden\r\n");
out.print("\r\n");
out.flush();
s.close();
ss.close();
} catch (Exception e) {
e.printStackTrace();
}
}
HttpResponseCode() throws Exception {
/* start the server */
InetAddress loopback = InetAddress.getLoopbackAddress();
ss = new ServerSocket();
ss.bind(new InetSocketAddress(loopback, 0));
(new Thread(this)).start();
/* establish http connection to server */
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(ss.getLocalPort())
.path("/missing.nothtml")
.toURL();
URLConnection uc = url.openConnection(Proxy.NO_PROXY);
int respCode1 = ((HttpURLConnection)uc).getResponseCode();
((HttpURLConnection)uc).disconnect();
int respCode2 = ((HttpURLConnection)uc).getResponseCode();
if (respCode1 != 403 || respCode2 != 403) {
throw new RuntimeException("Testing Http response code failed");
}
}
public static void main(String args[]) throws Exception {
new HttpResponseCode();
}
}

View file

@ -0,0 +1,170 @@
/*
* Copyright (c) 2016, 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 8161016 8183369
* @library /test/lib
* @summary When proxy is set HttpURLConnection should not use DIRECT connection.
* @run main/othervm HttpURLConWithProxy
*/
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.net.URI;
import java.net.URL;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.List;
import jdk.test.lib.net.URIBuilder;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.LogRecord;
public class HttpURLConWithProxy {
private static Logger logger =
Logger.getLogger("sun.net.www.protocol.http.HttpURLConnection");
public static void main(String... arg) throws Exception {
// Remove the default nonProxyHosts to use localhost for testing
System.setProperty("http.nonProxyHosts", "");
// 240.0.0.0/4 is unallocated and "reserved for future use" (RFC 1112, Section 4)
System.setProperty("http.proxyHost", "240.0.0.1");
System.setProperty("http.proxyPort", "1111");
// Use the logger to help verify the Proxy was used
logger.setLevel(Level.ALL);
Handler h = new ProxyHandler();
h.setLevel(Level.ALL);
logger.addHandler(h);
ServerSocket ss;
URL url;
HttpURLConnection con;
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress address = new InetSocketAddress(loopback, 0);
// Test1: using Proxy set by System Property:
try {
ss = new ServerSocket();
ss.bind(address);
url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(ss.getLocalPort())
.toURL();
con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(10 * 1000);
con.connect();
if(con.usingProxy()){
System.out.println("Test1 Passed with: Connection succeeded with proxy");
} else {
throw new RuntimeException("Shouldn't use DIRECT connection "
+ "when proxy is invalid/down");
}
} catch (IOException ie) {
if(!ProxyHandler.proxyRetried) {
throw new RuntimeException("Connection not retried with proxy");
}
System.out.println("Test1 Passed with: " + ie.getMessage());
}
// Test2: using custom ProxySelector implementation
ProxyHandler.proxyRetried = false;
MyProxySelector myProxySel = new MyProxySelector();
ProxySelector.setDefault(myProxySel);
try {
ss = new ServerSocket();
ss.bind(address);
url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(ss.getLocalPort())
.toURL();
con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(10 * 1000);
con.connect();
if(con.usingProxy()){
System.out.println("Test2 Passed with: Connection succeeded with proxy");
} else {
throw new RuntimeException("Shouldn't use DIRECT connection "
+ "when proxy is invalid/down");
}
} catch (IOException ie) {
if(!ProxyHandler.proxyRetried) {
throw new RuntimeException("Connection not retried with proxy");
}
System.out.println("Test2 Passed with: " + ie.getMessage());
}
}
}
class MyProxySelector extends ProxySelector {
List<Proxy> proxies = new ArrayList<>();
MyProxySelector() {
// 240.0.0.0/4 is unallocated and "reserved for future use" (RFC 1112, Section 4)
Proxy p1 = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("240.0.0.2", 2222));
Proxy p2 = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("240.0.0.3", 3333));
proxies.add(p1);
proxies.add(p2);
}
@Override
public List<Proxy> select(URI uri) {
return proxies;
}
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
// System.out.println("MyProxySelector.connectFailed(): "+sa);
}
}
class ProxyHandler extends Handler {
public static boolean proxyRetried = false;
@Override
public void publish(LogRecord record) {
if (record.getMessage().contains("Retrying with proxy")) {
proxyRetried = true;
}
}
@Override
public void flush() {
}
@Override
public void close() {
}
}

View file

@ -0,0 +1,335 @@
/*
* 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.
*/
/* @test
* @bug 8231632
* @summary HttpURLConnection::usingProxy could specify that it lazily evaluates the fact
* @modules java.base/sun.net.www
* @library /test/lib
* @run main/othervm HttpURLConnUsingProxy
*/
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import jdk.test.lib.net.URIBuilder;
public class HttpURLConnUsingProxy {
static HttpServer server;
static Proxy proxy;
static InetSocketAddress isa;
static class Handler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
byte[] response = "Hello World!".getBytes(StandardCharsets.UTF_8);
try (InputStream req = exchange.getRequestBody()) {
req.readAllBytes();
}
exchange.sendResponseHeaders(200, response.length);
try (OutputStream resp = exchange.getResponseBody()) {
resp.write(response);
}
}
}
public static void main(String[] args) {
try {
InetAddress loopbackAddress = InetAddress.getLoopbackAddress();
InetSocketAddress addr = new InetSocketAddress(loopbackAddress, 0);
server = HttpServer.create(addr, 0);
server.createContext("/HttpURLConnUsingProxy/http1/", new Handler());
server.start();
ProxyServer pserver = new ProxyServer(loopbackAddress,
server.getAddress().getPort());
// Start proxy server
new Thread(pserver).start();
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(server.getAddress().getPort())
.path("/HttpURLConnUsingProxy/http1/x.html")
.toURLUnchecked();
// NO_PROXY
try {
HttpURLConnection urlc =
(HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
assertEqual(urlc.usingProxy(), false);
urlc.getResponseCode();
assertEqual(urlc.usingProxy(), false);
urlc.disconnect();
} catch (IOException ioe) {
throw new RuntimeException("Direct connection should succeed: "
+ ioe.getMessage());
}
// Non-existing proxy
try {
isa = InetSocketAddress.createUnresolved("inexistent", 8080);
proxy = new Proxy(Proxy.Type.HTTP, isa);
HttpURLConnection urlc = (HttpURLConnection) url.openConnection(proxy);
assertEqual(urlc.usingProxy(), true);
InputStream is = urlc.getInputStream();
is.close();
throw new RuntimeException("Non-existing proxy should cause IOException");
} catch (IOException ioe) {
// expected
}
// Normal proxy settings
try {
isa = InetSocketAddress.createUnresolved(loopbackAddress.getHostAddress(),
pserver.getPort());
proxy = new Proxy(Proxy.Type.HTTP, isa);
HttpURLConnection urlc = (HttpURLConnection) url.openConnection(proxy);
assertEqual(urlc.usingProxy(), true);
urlc.getResponseCode();
assertEqual(urlc.usingProxy(), true);
urlc.disconnect();
} catch (IOException ioe) {
throw new RuntimeException("Connection through local proxy should succeed: "
+ ioe.getMessage());
}
// Reuse proxy with new HttpURLConnection
try {
HttpURLConnection urlc = (HttpURLConnection) url.openConnection(proxy);
assertEqual(urlc.usingProxy(), true);
urlc.getResponseCode();
assertEqual(urlc.usingProxy(), true);
read(urlc.getInputStream());
assertEqual(urlc.usingProxy(), true);
} catch (IOException ioe) {
throw new RuntimeException("Connection through local proxy should succeed: "
+ ioe.getMessage());
}
// Reuse proxy with existing HttpURLConnection
try {
HttpURLConnection urlc = (HttpURLConnection) url.openConnection(proxy);
assertEqual(urlc.usingProxy(), true);
urlc.getResponseCode();
assertEqual(urlc.usingProxy(), true);
read(urlc.getInputStream());
assertEqual(urlc.usingProxy(), true);
urlc.disconnect();
} catch (IOException ioe) {
throw new RuntimeException("Connection through local proxy should succeed: "
+ ioe.getMessage());
}
// ProxySelector with normal proxy settings
try {
ProxySelector.setDefault(ProxySelector.of(isa));
HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
assertEqual(urlc.usingProxy(), false);
urlc.getResponseCode();
assertEqual(urlc.usingProxy(), true);
read(urlc.getInputStream());
assertEqual(urlc.usingProxy(), true);
urlc.disconnect();
assertEqual(urlc.usingProxy(), true);
} catch (IOException ioe) {
throw new RuntimeException("Connection through local proxy should succeed: "
+ ioe.getMessage());
}
// ProxySelector with proxying disabled
try {
ProxySelector.setDefault(ProxySelector.of(null));
HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
assertEqual(urlc.usingProxy(), false);
urlc.getResponseCode();
assertEqual(urlc.usingProxy(), false);
read(urlc.getInputStream());
assertEqual(urlc.usingProxy(), false);
} catch (IOException ioe) {
throw new RuntimeException("Direct connection should succeed: "
+ ioe.getMessage());
}
// ProxySelector overwritten
try {
ProxySelector.setDefault(ProxySelector.of(isa));
HttpURLConnection urlc = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
assertEqual(urlc.usingProxy(), false);
urlc.disconnect();
} catch (IOException ioe) {
throw new RuntimeException("Direct connection should succeed: "
+ ioe.getMessage());
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (server != null) {
server.stop(0);
}
}
}
static class ProxyServer extends Thread {
private static ServerSocket ss = null;
// Client requesting a tunnel
private Socket clientSocket = null;
/*
* Origin server's address and port that the client
* wants to establish the tunnel for communication.
*/
private InetAddress serverInetAddr;
private int serverPort;
public ProxyServer(InetAddress server, int port) throws IOException {
serverInetAddr = server;
serverPort = port;
ss = new ServerSocket(0, 0, InetAddress.getLoopbackAddress());
}
public void run() {
while (true) {
try {
clientSocket = ss.accept();
processRequests();
} catch (Exception e) {
System.out.println("Proxy failed: " + e);
e.printStackTrace();
try {
ss.close();
} catch (IOException ioe) {
System.out.println("ProxyServer close error: " + ioe);
ioe.printStackTrace();
}
}
}
}
private void processRequests() throws Exception {
// Connection set to tunneling mode
Socket serverSocket = new Socket(serverInetAddr, serverPort);
ProxyTunnel clientToServer = new ProxyTunnel(
clientSocket, serverSocket);
ProxyTunnel serverToClient = new ProxyTunnel(
serverSocket, clientSocket);
clientToServer.start();
serverToClient.start();
System.out.println("Proxy: Started tunneling...");
clientToServer.join();
serverToClient.join();
System.out.println("Proxy: Finished tunneling...");
clientToServer.close();
serverToClient.close();
}
/**
* **************************************************************
* Helper methods follow
* **************************************************************
*/
public int getPort() {
return ss.getLocalPort();
}
/*
* This inner class provides unidirectional data flow through the sockets
* by continuously copying bytes from input socket to output socket
* while both sockets are open and EOF has not been received.
*/
static class ProxyTunnel extends Thread {
Socket sockIn;
Socket sockOut;
InputStream input;
OutputStream output;
public ProxyTunnel(Socket sockIn, Socket sockOut) throws Exception {
this.sockIn = sockIn;
this.sockOut = sockOut;
input = sockIn.getInputStream();
output = sockOut.getOutputStream();
}
public void run() {
int BUFFER_SIZE = 400;
byte[] buf = new byte[BUFFER_SIZE];
int bytesRead = 0;
int count = 0; // Keep track of amount of data transferred
try {
while ((bytesRead = input.read(buf)) >= 0) {
output.write(buf, 0, bytesRead);
output.flush();
count += bytesRead;
}
} catch (IOException e) {
/*
* Peer end has closed connection
* so we close tunnel
*/
close();
}
}
public void close() {
try {
if (!sockIn.isClosed())
sockIn.close();
if (!sockOut.isClosed())
sockOut.close();
} catch (IOException ignored) {
}
}
}
}
private static void assertEqual(boolean usingProxy, boolean expected) {
if (usingProxy != expected) {
throw new RuntimeException("Expected: " + expected
+ " but usingProxy returned: " + usingProxy);
}
}
private static String read(InputStream inputStream) throws IOException {
StringBuilder sb = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8));
int i = bufferedReader.read();
while (i != -1) {
sb.append((char) i);
i = bufferedReader.read();
}
bufferedReader.close();
return sb.toString();
}
}

View file

@ -0,0 +1,246 @@
/*
* Copyright (c) 2023, 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 8314978
* @summary Multiple server call from connection failing with expect100 in
* getOutputStream
* @library /test/lib
* @run junit/othervm HttpURLConnectionExpect100Test
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.net.HttpURLConnection;
import jdk.test.lib.net.URIBuilder;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import static org.junit.jupiter.api.Assertions.assertEquals;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class HttpURLConnectionExpect100Test {
private HttpServer server;
private int port;
static final String RESPONSE = "This is default response.";
@BeforeAll
void setup() throws Exception {
server = HttpServer.create();
port = server.getPort();
}
@AfterAll
void teardown() throws Exception {
server.close();
}
@Test
public void expect100ContinueHitCountTest() throws Exception {
server.resetHitCount();
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.toURL();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("PUT");
//send expect continue
conn.setRequestProperty("Expect", "100-continue");
sendRequest(conn);
getHeaderField(conn);
// Server rejects the expect 100-continue request with 417 response
assertEquals(417, conn.getResponseCode());
assertEquals(1, server.getServerHitCount());
}
@Test
public void defaultRequestHitCountTest() throws Exception {
server.resetHitCount();
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(port)
.toURL();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("PUT");
sendRequest(conn);
getHeaderField(conn);
assertEquals(200, conn.getResponseCode());
try ( InputStream in = conn.getInputStream()) {
byte[] data = in.readAllBytes();
assertEquals(RESPONSE.length(), data.length);
}
assertEquals(1, server.getServerHitCount());
}
private void sendRequest(final HttpURLConnection conn) throws Exception {
conn.setDoOutput(true);
conn.setFixedLengthStreamingMode(10);
byte[] payload = new byte[10];
try ( OutputStream os = conn.getOutputStream()) {
os.write(payload);
os.flush();
} catch (IOException e) {
// intentional, server will reject the expect 100
System.err.println("Got expected exception: " + e);
}
}
private void getHeaderField(final HttpURLConnection conn) {
// Call getHeaderFiels in loop, this should not hit server.
for (int i = 0; i < 5; i++) {
System.out.println("Getting: field" + i);
conn.getHeaderField("field" + i);
}
}
static class HttpServer extends Thread {
private final ServerSocket ss;
private static HttpServer inst;
private volatile int hitCount;
private volatile boolean isRunning;
private final int port;
private HttpServer() throws IOException {
InetAddress loopback = InetAddress.getLoopbackAddress();
ss = new ServerSocket();
ss.bind(new InetSocketAddress(loopback, 0));
port = ss.getLocalPort();
isRunning = true;
}
static HttpServer create() throws IOException {
if (inst != null) {
return inst;
} else {
inst = new HttpServer();
inst.setDaemon(true);
inst.start();
return inst;
}
}
int getServerHitCount() {
return hitCount;
}
void resetHitCount() {
hitCount = 0;
}
int getPort() {
return port;
}
void close() {
isRunning = false;
if (ss != null && !ss.isClosed()) {
try {
ss.close();
} catch (IOException ex) {
}
}
}
@Override
public void run() {
Socket client;
try (ss) {
while (isRunning) {
client = ss.accept();
System.out.println(client.getRemoteSocketAddress().toString());
hitCount++;
handleConnection(client);
}
} catch (IOException ex) {
// throw exception only if isRunning is true
if (isRunning) {
throw new RuntimeException(ex);
}
}
}
private void handleConnection(Socket client) throws IOException {
try (client; BufferedReader in = new BufferedReader(
new InputStreamReader(client.getInputStream()));
PrintStream out = new PrintStream(client.getOutputStream())) {
handle_connection(in, out);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private void handle_connection(BufferedReader in, PrintStream out)
throws IOException, InterruptedException {
StringBuilder clientRequest = new StringBuilder();
String line = null;
do {
line = in.readLine();
clientRequest.append(line);
} while (line != null && line.length() != 0);
if (clientRequest.toString().contains("100-continue")) {
rejectExpect100Continue(out);
} else {
defaultResponse(out);
}
// wait until the client closes the socket
while (line != null) {
line = in.readLine();
}
}
private void rejectExpect100Continue(PrintStream out) {
out.print("HTTP/1.1 417 Expectation Failed\r\n");
out.print("Server: Test-Server\r\n");
out.print("Connection: close\r\n");
out.print("Content-Length: 0\r\n");
out.print("\r\n");
out.flush();
}
private void defaultResponse(PrintStream out) {
// send the 200 OK
out.print("HTTP/1.1 200 OK\r\n");
out.print("Server: Test-Server\r\n");
out.print("Connection: close\r\n");
out.print("Content-Length: " + RESPONSE.length() + "\r\n\r\n");
out.print(RESPONSE);
out.flush();
}
}
}

View file

@ -0,0 +1,443 @@
/*
* 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 8054022
* @summary Verify that expect 100-continue doesn't hang
* @library /test/lib
* @run junit/othervm HttpURLConnectionExpectContinueTest
* @run junit/othervm -Djava.net.preferIPv4Stack=true HttpURLConnectionExpectContinueTest
* @run junit/othervm -Djava.net.preferIPv6Addresses=true HttpURLConnectionExpectContinueTest
*/
import jdk.test.lib.net.URIBuilder;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.assertTrue;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class HttpURLConnectionExpectContinueTest {
class Control {
volatile ServerSocket serverSocket = null;
volatile boolean stop = false;
volatile boolean respondWith100Continue = false;
volatile boolean write100ContinueTwice = false;
volatile String response = null;
}
private Thread serverThread = null;
private volatile Control control;
static final Logger logger;
static {
logger = Logger.getLogger("sun.net.www.protocol.http.HttpURLConnection");
logger.setLevel(Level.ALL);
Logger.getLogger("").getHandlers()[0].setLevel(Level.ALL);
}
@BeforeAll
public void startServerSocket() throws Exception {
Control control = this.control = new Control();
control.serverSocket = new ServerSocket();
control.serverSocket.setReuseAddress(true);
control.serverSocket.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
Runnable runnable = () -> {
while (!control.stop) {
try {
Socket socket = control.serverSocket.accept();
InputStream inputStream = socket.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
StringBuilder stringBuilder = new StringBuilder();
// Read initial request
byte b;
while (true) {
b = (byte) inputStreamReader.read();
stringBuilder.append((char) b);
if (stringBuilder.length() >= 4) {
char[] lastBytes = new char[4];
stringBuilder.getChars(
stringBuilder.length() - 4,
stringBuilder.length(), lastBytes, 0);
if (Arrays.equals(lastBytes, new char[]{'\r', '\n', '\r', '\n'})) {
break;
}
}
}
OutputStream outputStream = socket.getOutputStream();
String header = stringBuilder.toString();
String contentLengthString = "Content-Length:";
// send 100 continue responses if set by test
if (control.respondWith100Continue) {
outputStream.write("HTTP/1.1 100 Continue\r\n\r\n".getBytes());
outputStream.flush();
if (control.write100ContinueTwice) {
outputStream.write("HTTP/1.1 100 Continue\r\n\r\n".getBytes());
outputStream.flush();
}
}
// expect main request to be received
int idx = header.indexOf(contentLengthString);
if (idx >= 0) {
String substr = header.substring(idx + contentLengthString.length());
idx = substr.indexOf('\r');
substr = substr.substring(0, idx);
int contentLength = Integer.parseInt(substr.trim());
StringBuilder contentLengthBuilder = new StringBuilder();
for (int i = 0; i < contentLength; i++) {
b = (byte) inputStreamReader.read();
contentLengthBuilder.append((char) b);
}
} else {
StringBuilder contentLengthBuilder = new StringBuilder();
while (true) {
b = (byte) inputStreamReader.read();
contentLengthBuilder.append((char) b);
if (contentLengthBuilder.length() >= 2) {
char[] lastBytes = new char[2];
contentLengthBuilder.getChars(
contentLengthBuilder.length() - 2,
contentLengthBuilder.length(), lastBytes, 0);
if (Arrays.equals(lastBytes, new char[]{'\r', '\n'})) {
String lengthInHex =
contentLengthBuilder.substring(0, contentLengthBuilder.length() - 2);
int contentLength = Integer.parseInt(lengthInHex, 16);
char[] body = new char[contentLength];
inputStreamReader.read(body);
break;
// normally we have to parse more data,
// but for simplicity we expect no more chunks...
}
}
}
}
// send response
outputStream.write(control.response.getBytes());
outputStream.flush();
} catch (SocketException e) {
// ignore
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
serverThread = new Thread(runnable);
serverThread.start();
}
@AfterAll
public void stopServerSocket() throws Exception {
Control control = this.control;
control.stop = true;
control.serverSocket.close();
serverThread.join();
}
@Test
public void testNonChunkedRequestAndNoExpect100ContinueResponse() throws Exception {
String body = "testNonChunkedRequestAndNoExpect100ContinueResponse";
Control control = this.control;
control.response = "HTTP/1.1 200 OK\r\n" +
"Connection: close\r\n" +
"Content-Length: " + body.length() + "\r\n" +
"\r\n" +
body + "\r\n";
control.respondWith100Continue = false;
control.write100ContinueTwice = false;
HttpURLConnection connection = createConnection();
OutputStream outputStream = connection.getOutputStream();
outputStream.write(body.getBytes());
outputStream.close();
int responseCode = connection.getResponseCode();
String responseBody = new String(connection.getInputStream().readAllBytes(), StandardCharsets.UTF_8).strip();
System.err.println("response body: " + responseBody);
assertTrue(responseCode == 200,
String.format("Expected 200 response, instead received %s", responseCode));
assertTrue(body.equals(responseBody),
String.format("Expected response %s, instead received %s", body, responseBody));
}
@Test
public void testNonChunkedRequestWithExpect100ContinueResponse() throws Exception {
String body = "testNonChunkedRequestWithExpect100ContinueResponse";
Control control = this.control;
control.response = "HTTP/1.1 200 OK\r\n" +
"Connection: close\r\n" +
"Content-Length: " + body.length() + "\r\n" +
"\r\n" +
body + "\r\n";
control.respondWith100Continue = true;
control.write100ContinueTwice = false;
HttpURLConnection connection = createConnection();
OutputStream outputStream = connection.getOutputStream();
outputStream.write(body.getBytes());
outputStream.close();
int responseCode = connection.getResponseCode();
String responseBody = new String(connection.getInputStream().readAllBytes(), StandardCharsets.UTF_8).strip();
System.err.println("response body: " + responseBody);
assertTrue(responseCode == 200,
String.format("Expected 200 response, instead received %s", responseCode));
assertTrue(body.equals(responseBody),
String.format("Expected response %s, instead received %s", body, responseBody));
}
@Test
public void testNonChunkedRequestWithDoubleExpect100ContinueResponse() throws Exception {
String body = "testNonChunkedRequestWithDoubleExpect100ContinueResponse";
Control control = this.control;
control.response = "HTTP/1.1 200 OK\r\n" +
"Connection: close\r\n" +
"Content-Length: " + body.length() + "\r\n" +
"\r\n" +
body + "\r\n";
control.respondWith100Continue = true;
control.write100ContinueTwice = true;
HttpURLConnection connection = createConnection();
OutputStream outputStream = connection.getOutputStream();
outputStream.write(body.getBytes());
outputStream.close();
int responseCode = connection.getResponseCode();
String responseBody = new String(connection.getInputStream().readAllBytes(), StandardCharsets.UTF_8).strip();
System.err.println("response body: " + responseBody);
assertTrue(responseCode == 200,
String.format("Expected 200 response, instead received %s", responseCode));
assertTrue(body.equals(responseBody),
String.format("Expected response %s, instead received %s", body, responseBody));
}
@Test
public void testChunkedRequestAndNoExpect100ContinueResponse() throws Exception {
String body = "testChunkedRequestAndNoExpect100ContinueResponse";
Control control = this.control;
control.response = "HTTP/1.1 200 OK\r\n" +
"Connection: close\r\n" +
"Content-Length: " + body.length() + "\r\n" +
"\r\n" +
body + "\r\n";
control.respondWith100Continue = false;
control.write100ContinueTwice = false;
HttpURLConnection connection = createConnection();
connection.setChunkedStreamingMode(body.length() / 2);
OutputStream outputStream = connection.getOutputStream();
outputStream.write(body.getBytes());
outputStream.close();
int responseCode = connection.getResponseCode();
String responseBody = new String(connection.getInputStream().readAllBytes(), StandardCharsets.UTF_8).strip();
System.err.println("response body: " + responseBody);
assertTrue(responseCode == 200,
String.format("Expected 200 response, instead received %s", responseCode));
assertTrue(body.equals(responseBody),
String.format("Expected response %s, instead received %s", body, responseBody));
}
@Test
public void testChunkedRequestWithExpect100ContinueResponse() throws Exception {
String body = "testChunkedRequestWithExpect100ContinueResponse";
Control control = this.control;
control.response = "HTTP/1.1 200 OK\r\n" +
"Connection: close\r\n" +
"Content-Length: " + body.length() + "\r\n" +
"\r\n" +
body + "\r\n";
control.respondWith100Continue = true;
control.write100ContinueTwice = false;
HttpURLConnection connection = createConnection();
connection.setChunkedStreamingMode(body.length() / 2);
OutputStream outputStream = connection.getOutputStream();
outputStream.write(body.getBytes());
outputStream.close();
int responseCode = connection.getResponseCode();
String responseBody = new String(connection.getInputStream().readAllBytes(), StandardCharsets.UTF_8).strip();
System.err.println("response body: " + responseBody);
assertTrue(responseCode == 200,
String.format("Expected 200 response, instead received %s", responseCode));
assertTrue(body.equals(responseBody),
String.format("Expected response %s, instead received %s", body, responseBody));
}
@Test
public void testChunkedRequestWithDoubleExpect100ContinueResponse() throws Exception {
String body = "testChunkedRequestWithDoubleExpect100ContinueResponse";
Control control = this.control;
control.response = "HTTP/1.1 200 OK\r\n" +
"Connection: close\r\n" +
"Content-Length: " + body.length() + "\r\n" +
"\r\n" +
body + "\r\n";
control.respondWith100Continue = true;
control.write100ContinueTwice = true;
HttpURLConnection connection = createConnection();
connection.setChunkedStreamingMode(body.length() / 2);
OutputStream outputStream = connection.getOutputStream();
outputStream.write(body.getBytes());
outputStream.close();
int responseCode = connection.getResponseCode();
String responseBody = new String(connection.getInputStream().readAllBytes(), StandardCharsets.UTF_8).strip();
System.err.println("response body: " + responseBody);
assertTrue(responseCode == 200,
String.format("Expected 200 response, instead received %s", responseCode));
assertTrue(body.equals(responseBody),
String.format("Expected response %s, instead received %s", body, responseBody));
}
@Test
public void testFixedLengthRequestAndNoExpect100ContinueResponse() throws Exception {
String body = "testFixedLengthRequestAndNoExpect100ContinueResponse";
Control control = this.control;
control.response = "HTTP/1.1 200 OK\r\n" +
"Connection: close\r\n" +
"Content-Length: " + body.length() + "\r\n" +
"\r\n" +
body + "\r\n";
control.respondWith100Continue = false;
control.write100ContinueTwice = false;
HttpURLConnection connection = createConnection();
connection.setFixedLengthStreamingMode(body.length());
OutputStream outputStream = connection.getOutputStream();
outputStream.write(body.getBytes());
outputStream.close();
int responseCode = connection.getResponseCode();
String responseBody = new String(connection.getInputStream().readAllBytes(), StandardCharsets.UTF_8).strip();
System.err.println("response body: " + responseBody);
assertTrue(responseCode == 200,
String.format("Expected 200 response, instead received %s", responseCode));
assertTrue(body.equals(responseBody),
String.format("Expected response %s, instead received %s", body, responseBody));
}
@Test
public void testFixedLengthRequestWithExpect100ContinueResponse() throws Exception {
String body = "testFixedLengthRequestWithExpect100ContinueResponse";
Control control = this.control;
control.response = "HTTP/1.1 200 OK\r\n" +
"Connection: close\r\n" +
"Content-Length: " + body.length() + "\r\n" +
"\r\n" +
body + "\r\n";
control.respondWith100Continue = true;
control.write100ContinueTwice = false;
HttpURLConnection connection = createConnection();
connection.setFixedLengthStreamingMode(body.getBytes().length);
OutputStream outputStream = connection.getOutputStream();
outputStream.write(body.getBytes());
outputStream.close();
int responseCode = connection.getResponseCode();
String responseBody = new String(connection.getInputStream().readAllBytes(), StandardCharsets.UTF_8).strip();
System.err.println("response body: " + responseBody);
assertTrue(responseCode == 200,
String.format("Expected 200 response, instead received %s", responseCode));
assertTrue(body.equals(responseBody),
String.format("Expected response %s, instead received %s", body, responseBody));
}
@Test
public void testFixedLengthRequestWithDoubleExpect100ContinueResponse() throws Exception {
String body = "testFixedLengthRequestWithDoubleExpect100ContinueResponse";
Control control = this.control;
control.response = "HTTP/1.1 200 OK\r\n" +
"Connection: close\r\n" +
"Content-Length: " + body.length() + "\r\n" +
"\r\n" +
body + "\r\n";
control.respondWith100Continue = true;
control.write100ContinueTwice = true;
HttpURLConnection connection = createConnection();
connection.setFixedLengthStreamingMode(body.getBytes().length);
OutputStream outputStream = connection.getOutputStream();
outputStream.write(body.getBytes());
outputStream.close();
int responseCode = connection.getResponseCode();
String responseBody = new String(connection.getInputStream().readAllBytes(), StandardCharsets.UTF_8).strip();
System.err.println("response body: " + responseBody);
assertTrue(responseCode == 200,
String.format("Expected 200 response, instead received %s", responseCode));
assertTrue(body.equals(responseBody),
String.format("Expected response %s, instead received %s", body, responseBody));
}
// Creates a connection with all the common settings used in each test
private HttpURLConnection createConnection() throws Exception {
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(control.serverSocket.getLocalPort())
.toURL();
HttpURLConnection connection = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
connection.setDoOutput(true);
connection.setReadTimeout(5000);
connection.setUseCaches(false);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Close");
connection.setRequestProperty("Expect", "100-Continue");
return connection;
}
}

View file

@ -0,0 +1,177 @@
/*
* Copyright (c) 2021, 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 8133686
* @summary Ensuring that multiple header values for a given field-name are returned in
* the order they were added for HttpURLConnection.getRequestProperties
* and HttpURLConnection.getHeaderFields
* @library /test/lib
* @run testng HttpURLConnectionHeadersOrder
*/
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.testng.Assert;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import java.io.IOException;
import java.net.*;
import java.util.Arrays;
import java.util.List;
public class HttpURLConnectionHeadersOrder {
private static final String LOCAL_TEST_ENDPOINT = "/headertest";
private static final String ERROR_MESSAGE_TEMPLATE = "Expected Request Properties = %s, Actual Request Properties = %s";
private static final List<String> EXPECTED_HEADER_VALUES = Arrays.asList("a", "b", "c");
private static HttpServer server;
private static URL serverUrl;
@BeforeTest
public void beforeTest() throws Exception {
SimpleHandler handler = new SimpleHandler();
server = createSimpleHttpServer(handler);
serverUrl = URIBuilder.newBuilder()
.scheme("http")
.host(server.getAddress().getAddress())
.port(server.getAddress().getPort())
.path(LOCAL_TEST_ENDPOINT)
.toURL();
}
@AfterTest
public void afterTest() {
if (server != null)
server.stop(0);
}
/**
* - This tests requestProperty insertion-order
* - on the client side by sending a HTTP GET
* - request to a "dummy" server with additional
* - custom request properties
*
* @throws Exception
*/
@Test (priority = 1)
public void testRequestPropertiesOrder() throws Exception {
final var conn = (HttpURLConnection) serverUrl.openConnection();
conn.addRequestProperty("test_req_prop", "a");
conn.addRequestProperty("test_req_prop", "b");
conn.addRequestProperty("test_req_prop", "c");
conn.setRequestMethod("GET");
var requestProperties = conn.getRequestProperties();
var customRequestProps = requestProperties.get("test_req_prop");
conn.disconnect();
Assert.assertNotNull(customRequestProps);
Assert.assertEquals(customRequestProps, EXPECTED_HEADER_VALUES, String.format(ERROR_MESSAGE_TEMPLATE, EXPECTED_HEADER_VALUES.toString(), customRequestProps.toString()));
}
/**
* - This tests whether or not the insertion order is preserved for custom headers
* - on the server's side.
* - The server will return a custom status code (999) if the expected headers
* - are not equal to the actual headers
*
* @throws Exception
*/
@Test (priority = 2)
public void testServerSideRequestHeadersOrder() throws Exception {
final var conn = (HttpURLConnection) serverUrl.openConnection();
conn.addRequestProperty("test_server_handling", "a");
conn.addRequestProperty("test_server_handling", "b");
conn.addRequestProperty("test_server_handling", "c");
int statusCode = conn.getResponseCode();
conn.disconnect();
Assert.assertEquals(statusCode, 999, "The insertion-order was not preserved on the server-side response headers handling");
}
@Test (priority = 3)
public void testClientSideResponseHeadersOrder() throws Exception {
final var conn = (HttpURLConnection) serverUrl.openConnection();
conn.setRequestMethod("GET");
var actualCustomResponseHeaders = conn.getHeaderFields().get("Test_response");
Assert.assertNotNull(actualCustomResponseHeaders, "Error in reading custom response headers");
Assert.assertEquals(EXPECTED_HEADER_VALUES, actualCustomResponseHeaders, String.format(ERROR_MESSAGE_TEMPLATE, EXPECTED_HEADER_VALUES.toString(), actualCustomResponseHeaders.toString()));
}
private static HttpServer createSimpleHttpServer(SimpleHandler handler) throws IOException {
var serverAddress = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
var server = HttpServer.create(serverAddress, 0);
server.createContext(LOCAL_TEST_ENDPOINT, handler);
server.start();
System.out.println("Server started on " + server.getAddress());
return server;
}
private static class SimpleHandler implements HttpHandler {
@Override
public void handle(HttpExchange exchange) throws IOException {
int statusCode = testRequestHeadersOrder(exchange);
sendCustomResponse(exchange, statusCode);
}
private int testRequestHeadersOrder(HttpExchange exchange) {
var requestHeaders = exchange.getRequestHeaders();
var actualTestRequestHeaders = requestHeaders.get("test_server_handling");
if (actualTestRequestHeaders == null) {
System.out.println("Error: requestHeaders.get(\"test_server_handling\") returned null");
return -1;
}
if (!actualTestRequestHeaders.equals(EXPECTED_HEADER_VALUES)) {
System.out.println("Error: " + String.format(ERROR_MESSAGE_TEMPLATE, EXPECTED_HEADER_VALUES.toString(), actualTestRequestHeaders.toString()));
return -1;
}
return 999;
}
private void sendCustomResponse(HttpExchange exchange, int statusCode) throws IOException {
var responseHeaders = exchange.getResponseHeaders();
responseHeaders.add("test_response", "a");
responseHeaders.add("test_response", "b");
responseHeaders.add("test_response", "c");
var outputStream = exchange.getResponseBody();
var response = "Testing headers";
exchange.sendResponseHeaders(statusCode, response.length());
outputStream.write(response.getBytes());
outputStream.flush();
outputStream.close();
}
}
}

View file

@ -0,0 +1,162 @@
/*
* 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 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.testng.Assert;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import sun.net.spi.DefaultProxySelector;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
/**
* @test
* @bug 6563286 6797318 8177648 8230220
* @summary Tests that sun.net.www.protocol.http.HttpURLConnection when dealing with
* sun.net.spi.DefaultProxySelector#select() handles any IllegalArgumentException
* correctly
* @library /test/lib
* @run testng HttpURLProxySelectionTest
* @modules java.base/sun.net.spi:+open
*/
public class HttpURLProxySelectionTest {
private static final String WEB_APP_CONTEXT = "/httpurlproxytest";
private HttpServer server;
private SimpleHandler handler;
private ProxySelector previousDefault;
private CustomProxySelector ourProxySelector = new CustomProxySelector();
@BeforeTest
public void beforeTest() throws Exception {
previousDefault = ProxySelector.getDefault();
ProxySelector.setDefault(ourProxySelector);
handler = new SimpleHandler();
server = createServer(handler);
}
@AfterTest
public void afterTest() {
try {
if (server != null) {
final int delaySeconds = 0;
server.stop(delaySeconds);
}
} finally {
ProxySelector.setDefault(previousDefault);
}
}
/**
* - Test initiates a HTTP request to server
* - Server receives request and sends a 301 redirect to an URI which doesn't have a "host"
* - Redirect is expected to fail with IOException (caused by IllegalArgumentException from DefaultProxySelector)
*
* @throws Exception
*/
@Test
public void test() throws Exception {
final URL targetURL = URIBuilder.newBuilder()
.scheme("http")
.host(server.getAddress().getAddress())
.port(server.getAddress().getPort())
.path(WEB_APP_CONTEXT)
.toURL();
System.out.println("Sending request to " + targetURL);
final HttpURLConnection conn = (HttpURLConnection) targetURL.openConnection();
try {
conn.getResponseCode();
Assert.fail("Request to " + targetURL + " was expected to fail during redirect");
} catch (IOException ioe) {
// expected because of the redirect to an invalid URL, for which a proxy can't be selected
// make sure the it was indeed a redirect
Assert.assertTrue(handler.redirectSent, "Server was expected to send a redirect, but didn't");
Assert.assertTrue(ourProxySelector.selectorUsedForRedirect, "Proxy selector wasn't used for redirect");
// make sure the IOException was caused by an IllegalArgumentException
Assert.assertTrue(ioe.getCause() instanceof IllegalArgumentException, "Unexpected cause in the IOException");
}
}
private static HttpServer createServer(final HttpHandler handler) throws IOException {
final InetSocketAddress serverAddr = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
final int backlog = -1;
final HttpServer server = HttpServer.create(serverAddr, backlog);
// setup the handler
server.createContext(WEB_APP_CONTEXT, handler);
// start the server
server.start();
System.out.println("Server started on " + server.getAddress());
return server;
}
private static class SimpleHandler implements HttpHandler {
private volatile boolean redirectSent = false;
@Override
public void handle(final HttpExchange httpExchange) throws IOException {
final String redirectURL;
try {
redirectURL = new URI("http", "/irrelevant", null).toString();
} catch (URISyntaxException e) {
throw new IOException(e);
}
httpExchange.getResponseHeaders().add("Location", redirectURL);
final URI requestURI = httpExchange.getRequestURI();
System.out.println("Handling " + httpExchange.getRequestMethod() + " request "
+ requestURI + " responding with redirect to " + redirectURL);
this.redirectSent = true;
httpExchange.sendResponseHeaders(301, -1);
}
}
private static class CustomProxySelector extends DefaultProxySelector {
private volatile boolean selectorUsedForRedirect = false;
@Override
public List<Proxy> select(final URI uri) {
if (uri.toString().contains("/irrelevant")) {
this.selectorUsedForRedirect = true;
}
return super.select(uri);
}
}
}

View file

@ -0,0 +1,196 @@
/*
* Copyright (c) 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
* @summary Test that Response Message gets set even if a non 100 response
* gets return when Expect Continue is set
* @bug 8352502
* @library /test/lib
* @run junit/othervm -Djdk.internal.httpclient.debug=true
* -Djdk.httpclient.HttpClient.log=all
* HttpUrlConnectionExpectContinueResponseMessageTest
*/
import jdk.test.lib.net.URIBuilder;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.ServerSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URL;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.assertTrue;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class HttpUrlConnectionExpectContinueResponseMessageTest {
class Control {
volatile ServerSocket serverSocket = null;
volatile boolean stop = false;
volatile String response = null;
volatile Socket acceptingSocket = null;
volatile String testPath = null;
}
private Thread serverThread = null;
private volatile Control control;
static final Logger logger;
static {
logger = Logger.getLogger("sun.net.www.protocol.http.HttpURLConnection");
logger.setLevel(Level.ALL);
Logger.getLogger("").getHandlers()[0].setLevel(Level.ALL);
}
public Object[][] args() {
return new Object[][]{
// Expected Status Code, Status Line, Expected responseMessage
{ 404, "HTTP/1.1 404 Not Found", "Not Found" },
{ 405, "HTTP/1.1 405 Method Not Allowed", "Method Not Allowed" },
{ 401, "HTTP/1.1 401 Unauthorized", "Unauthorized"}
};
}
@BeforeAll
public void startServerSocket() throws Exception {
Control control = this.control = new Control();
control.serverSocket = new ServerSocket();
control.serverSocket.setReuseAddress(true);
control.serverSocket.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
Runnable runnable = () -> {
while (!control.stop) {
try {
Socket socket = control.serverSocket.accept();
String path = getPath(socket);
OutputStream outputStream;
if (path.equals(control.testPath)) {
control.acceptingSocket = socket;
outputStream = control.acceptingSocket.getOutputStream();
// send a wrong response and then shutdown
outputStream.write(control.response.getBytes());
outputStream.flush();
control.acceptingSocket.shutdownOutput();
} else {
// stray request showed up, return 500 and close socket
outputStream = socket.getOutputStream();
outputStream.write("HTTP/1.1 500 Internal Server Error\r\n".getBytes());
outputStream.write("Connection: close\r\n".getBytes());
outputStream.write("Content-Length: 0\r\n".getBytes());
outputStream.write("\r\n".getBytes());
outputStream.flush();
socket.close();
}
} catch (Exception e) {
// Any exceptions will be ignored
}
}
};
serverThread = new Thread(runnable);
serverThread.start();
}
private static String getPath(Socket socket) throws IOException {
InputStream inputStream = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder reqBuilder = new StringBuilder();
String line = null;
while (!(line = reader.readLine()).isEmpty()) {
reqBuilder.append(line + "\r\n");
}
String req = reqBuilder.toString();
StringTokenizer tokenizer = new StringTokenizer(req);
String method = tokenizer.nextToken();
String path = tokenizer.nextToken();
return path;
}
@AfterAll
public void stopServerSocket() throws Exception {
Control control = this.control;
control.stop = true;
control.serverSocket.close();
serverThread.join();
}
@ParameterizedTest
@MethodSource("args")
public void test(int expectedCode, String statusLine, String expectedMessage) throws Exception {
String body = "Testing: " + expectedCode;
Control control = this.control;
control.response = statusLine + "\r\n"
+ "Content-Length: 0\r\n"
+ "\r\n";
control.testPath = "/ContinueResponseMessageTest/" + expectedCode;
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.port(control.serverSocket.getLocalPort())
.path(control.testPath)
.toURL();
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Close");
connection.setRequestProperty("Expect", "100-Continue");
try {
connection.setFixedLengthStreamingMode(body.getBytes().length);
OutputStream outputStream = connection.getOutputStream();
outputStream.write(body.getBytes());
outputStream.close();
} catch (Exception ex) {
// server returning 4xx responses can result in exceptions
// but we can just swallow them
}
int responseCode = connection.getResponseCode();
String responseMessage = connection.getResponseMessage();
assertTrue(responseCode == expectedCode,
String.format("Expected %s response, instead received %s", expectedCode, responseCode));
assertTrue(expectedMessage.equals(responseMessage),
String.format("Expected Response Message %s, instead received %s",
expectedMessage, responseMessage));
control.acceptingSocket.close();
}
}

View file

@ -0,0 +1,72 @@
/*
* Copyright (c) 2016, 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 8144008
* @library /test/lib
* @summary Setting NO_PROXY on HTTP URL connections does not stop proxying
* @run main/othervm NoProxyTest
*/
import java.io.IOException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import jdk.test.lib.net.URIBuilder;
public class NoProxyTest {
static class NoProxyTestSelector extends ProxySelector {
@Override
public List<Proxy> select(URI uri) {
throw new RuntimeException("Should not reach here as proxy==Proxy.NO_PROXY");
}
@Override
public void connectFailed(URI u, SocketAddress s, IOException e) { }
}
public static void main(String args[]) throws MalformedURLException {
ProxySelector.setDefault(new NoProxyTestSelector());
URL url = URIBuilder.newBuilder()
.scheme("http")
.loopback()
.path("/")
.toURLUnchecked();
System.out.println("URL: " + url);
URLConnection connection;
try {
connection = url.openConnection(Proxy.NO_PROXY);
connection.connect();
} catch (IOException ignore) {
//ignore
}
}
}

View file

@ -0,0 +1,228 @@
/*
* Copyright (c) 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.
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.ProtocolException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import jdk.test.lib.net.URIBuilder;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* @test
* @bug 8170305
* @summary Tests behaviour of HttpURLConnection when server responds with 1xx interim response status codes
* @library /test/lib
* @run testng Response1xxTest
*/
public class Response1xxTest {
private static final String EXPECTED_RSP_BODY = "Hello World";
private ServerSocket serverSocket;
private Http11Server server;
private String requestURIBase;
@BeforeClass
public void setup() throws Exception {
serverSocket = new ServerSocket(0, 0, InetAddress.getLoopbackAddress());
server = new Http11Server(serverSocket);
new Thread(server).start();
requestURIBase = URIBuilder.newBuilder().scheme("http").loopback()
.port(serverSocket.getLocalPort()).build().toString();
}
@AfterClass
public void teardown() throws Exception {
if (server != null) {
server.stop = true;
System.out.println("(HTTP 1.1) Server stop requested");
}
if (serverSocket != null) {
serverSocket.close();
System.out.println("Closed (HTTP 1.1) server socket");
}
}
private static final class Http11Server implements Runnable {
private static final int CONTENT_LENGTH = EXPECTED_RSP_BODY.getBytes(StandardCharsets.UTF_8).length;
private static final String HTTP_1_1_RSP_200 = "HTTP/1.1 200 OK\r\n" +
"Content-Length: " + CONTENT_LENGTH + "\r\n\r\n" +
EXPECTED_RSP_BODY;
private static final String REQ_LINE_FOO = "GET /test/foo HTTP/1.1\r\n";
private static final String REQ_LINE_BAR = "GET /test/bar HTTP/1.1\r\n";
private static final String REQ_LINE_HELLO = "GET /test/hello HTTP/1.1\r\n";
private static final String REQ_LINE_BYE = "GET /test/bye HTTP/1.1\r\n";
private final ServerSocket serverSocket;
private volatile boolean stop;
private Http11Server(final ServerSocket serverSocket) {
this.serverSocket = serverSocket;
}
@Override
public void run() {
System.out.println("Server running at " + serverSocket);
while (!stop) {
Socket socket = null;
try {
// accept a connection
socket = serverSocket.accept();
System.out.println("Accepted connection from client " + socket);
// read request
final String requestLine;
try {
requestLine = readRequestLine(socket);
} catch (Throwable t) {
// ignore connections from potential rogue client
System.err.println("Ignoring connection/request from client " + socket
+ " due to exception:");
t.printStackTrace();
// close the socket
safeClose(socket);
continue;
}
System.out.println("Received following request line from client " + socket
+ " :\n" + requestLine);
final int informationalResponseCode;
if (requestLine.startsWith(REQ_LINE_FOO)) {
// we will send intermediate/informational 102 response
informationalResponseCode = 102;
} else if (requestLine.startsWith(REQ_LINE_BAR)) {
// we will send intermediate/informational 103 response
informationalResponseCode = 103;
} else if (requestLine.startsWith(REQ_LINE_HELLO)) {
// we will send intermediate/informational 100 response
informationalResponseCode = 100;
} else if (requestLine.startsWith(REQ_LINE_BYE)) {
// we will send intermediate/informational 101 response
informationalResponseCode = 101;
} else {
// unexpected client. ignore and close the client
System.err.println("Ignoring unexpected request from client " + socket);
safeClose(socket);
continue;
}
try (final OutputStream os = socket.getOutputStream()) {
// send informational response headers a few times (spec allows them to
// be sent multiple times)
for (int i = 0; i < 3; i++) {
// send 1xx response header
os.write(("HTTP/1.1 " + informationalResponseCode + "\r\n\r\n")
.getBytes(StandardCharsets.UTF_8));
os.flush();
System.out.println("Sent response code " + informationalResponseCode
+ " to client " + socket);
}
// now send a final response
System.out.println("Now sending 200 response code to client " + socket);
os.write(HTTP_1_1_RSP_200.getBytes(StandardCharsets.UTF_8));
os.flush();
System.out.println("Sent 200 response code to client " + socket);
}
} catch (Throwable t) {
// close the client connection
safeClose(socket);
// continue accepting any other client connections until we are asked to stop
System.err.println("Ignoring exception in server:");
t.printStackTrace();
}
}
}
static String readRequestLine(final Socket sock) throws IOException {
final InputStream is = sock.getInputStream();
final StringBuilder sb = new StringBuilder("");
byte[] buf = new byte[1024];
while (!sb.toString().endsWith("\r\n\r\n")) {
final int numRead = is.read(buf);
if (numRead == -1) {
return sb.toString();
}
final String part = new String(buf, 0, numRead, StandardCharsets.ISO_8859_1);
sb.append(part);
}
return sb.toString();
}
private static void safeClose(final Socket socket) {
try {
socket.close();
} catch (Throwable t) {
// ignore
}
}
}
/**
* Tests that when a HTTP/1.1 server sends intermediate 1xx response codes and then the final
* response, the client (internally) will ignore those intermediate informational response codes
* and only return the final response to the application
*/
@Test
public void test1xx() throws Exception {
final URI[] requestURIs = new URI[]{
new URI(requestURIBase + "/test/foo"),
new URI(requestURIBase + "/test/bar"),
new URI(requestURIBase + "/test/hello")};
for (final URI requestURI : requestURIs) {
System.out.println("Issuing request to " + requestURI);
final HttpURLConnection urlConnection = (HttpURLConnection) requestURI.toURL().openConnection();
final int responseCode = urlConnection.getResponseCode();
Assert.assertEquals(responseCode, 200, "Unexpected response code");
final String body;
try (final InputStream is = urlConnection.getInputStream()) {
final byte[] bytes = is.readAllBytes();
body = new String(bytes, StandardCharsets.UTF_8);
}
Assert.assertEquals(body, EXPECTED_RSP_BODY, "Unexpected response body");
}
}
/**
* Tests that when a HTTP/1.1 server sends 101 response code, when the client
* didn't ask for a connection upgrade, then the request fails with an exception.
*/
@Test
public void test101CausesRequestFailure() throws Exception {
final URI requestURI = new URI(requestURIBase + "/test/bye");
System.out.println("Issuing request to " + requestURI);
final HttpURLConnection urlConnection = (HttpURLConnection) requestURI.toURL().openConnection();
// we expect the request to fail because the server unexpectedly sends a 101 response
Assert.assertThrows(ProtocolException.class, () -> urlConnection.getResponseCode());
}
}

View file

@ -0,0 +1,288 @@
/*
* Copyright (c) 2016, 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.
*/
import java.io.IOException;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/*
* @test
* @bug 8169415
* @library /test/lib
* @modules java.logging
* java.base/sun.net.www
* java.base/sun.net.www.protocol.http
* jdk.httpserver/sun.net.httpserver
* @build jdk.test.lib.net.SimpleSSLContext HTTPTest HTTPTestServer HTTPTestClient HTTPSetAuthenticatorTest
* @summary A simple HTTP test that starts an echo server supporting the given
* authentication scheme, then starts a regular HTTP client to invoke it.
* The client first does a GET request on "/", then follows on
* with a POST request that sends "Hello World!" to the server.
* The client expects to receive "Hello World!" in return.
* The test supports several execution modes:
* SERVER: The server performs Server authentication;
* PROXY: The server pretends to be a proxy and performs
* Proxy authentication;
* SERVER307: The server redirects the client (307) to another
* server that perform Server authentication;
* PROXY305: The server attempts to redirect
* the client to a proxy using 305 code;
* This test runs the client several times, providing different
* authenticators to the HttpURLConnection and verifies that
* the authenticator is invoked as expected - validating that
* connections with different authenticators do not share each
* other's socket channel and authentication info.
* Note: BASICSERVER means that the server will let the underlying
* com.sun.net.httpserver.HttpServer perform BASIC
* authentication when in Server mode. There should be
* no real difference between BASICSERVER and BASIC - it should
* be transparent on the client side.
* @run main/othervm HTTPSetAuthenticatorTest NONE SERVER PROXY SERVER307 PROXY305
* @run main/othervm -Dhttp.auth.digest.reEnabledAlgorithms=MD5 HTTPSetAuthenticatorTest DIGEST SERVER
* @run main/othervm -Dhttp.auth.digest.reEnabledAlgorithms=MD5 HTTPSetAuthenticatorTest DIGEST PROXY
* @run main/othervm -Dhttp.auth.digest.reEnabledAlgorithms=MD5 HTTPSetAuthenticatorTest DIGEST PROXY305
* @run main/othervm -Dhttp.auth.digest.reEnabledAlgorithms=MD5 HTTPSetAuthenticatorTest DIGEST SERVER307
* @run main/othervm HTTPSetAuthenticatorTest BASIC SERVER
* @run main/othervm HTTPSetAuthenticatorTest BASIC PROXY
* @run main/othervm HTTPSetAuthenticatorTest BASIC PROXY305
* @run main/othervm HTTPSetAuthenticatorTest BASIC SERVER307
* @run main/othervm HTTPSetAuthenticatorTest BASICSERVER SERVER
* @run main/othervm HTTPSetAuthenticatorTest BASICSERVER SERVER307
*
* @author danielfuchs
*/
public class HTTPSetAuthenticatorTest extends HTTPTest {
public static void main(String[] args) throws Exception {
String[] schemes;
String[] params;
if (args == null || args.length == 0) {
schemes = Stream.of(HttpSchemeType.values())
.map(HttpSchemeType::name)
.collect(Collectors.toList())
.toArray(new String[0]);
params = new String[0];
} else {
schemes = new String[] { args[0] };
params = Arrays.copyOfRange(args, 1, args.length);
}
for (String scheme : schemes) {
System.out.println("==== Testing with scheme=" + scheme + " ====\n");
new HTTPSetAuthenticatorTest(HttpSchemeType.valueOf(scheme))
.execute(params);
System.out.println();
}
}
final HttpSchemeType scheme;
public HTTPSetAuthenticatorTest(HttpSchemeType scheme) {
this.scheme = scheme;
}
@Override
public HttpSchemeType getHttpSchemeType() {
return scheme;
}
@Override
public int run(HTTPTestServer server,
HttpProtocolType protocol,
HttpAuthType mode)
throws IOException
{
HttpTestAuthenticator authOne = new HttpTestAuthenticator("authOne", "dublin", "foox");
HttpTestAuthenticator authTwo = new HttpTestAuthenticator("authTwo", "dublin", "foox");
int expectedIncrement = scheme == HttpSchemeType.NONE
? 0 : EXPECTED_AUTH_CALLS_PER_TEST;
int count;
int defaultCount = AUTHENTICATOR.count.get();
// Connect to the server with a GET request, then with a
// POST that contains "Hello World!"
// Uses authenticator #1
System.out.println("\nClient: Using authenticator #1: "
+ toString(authOne));
HTTPTestClient.connect(protocol, server, mode, authOne);
count = authOne.count.get();
if (count != expectedIncrement) {
throw new AssertionError("Authenticator #1 called " + count(count)
+ " expected it to be called " + expected(expectedIncrement));
}
// Connect to the server with a GET request, then with a
// POST that contains "Hello World!"
// Uses authenticator #2
System.out.println("\nClient: Using authenticator #2: "
+ toString(authTwo));
HTTPTestClient.connect(protocol, server, mode, authTwo);
count = authTwo.count.get();
if (count != expectedIncrement) {
throw new AssertionError("Authenticator #2 called " + count(count)
+ " expected it to be called " + expected(expectedIncrement));
}
// Connect to the server with a GET request, then with a
// POST that contains "Hello World!"
// Uses authenticator #1
System.out.println("\nClient: Using authenticator #1 again: "
+ toString(authOne));
HTTPTestClient.connect(protocol, server, mode, authOne);
count = authOne.count.get();
if (count != expectedIncrement) {
throw new AssertionError("Authenticator #1 called " + count(count)
+ " expected it to be called " + expected(expectedIncrement));
}
count = authTwo.count.get();
if (count != expectedIncrement) {
throw new AssertionError("Authenticator #2 called " + count(count)
+ " expected it to be called " + expected(expectedIncrement));
}
count = AUTHENTICATOR.count.get();
if (count != defaultCount) {
throw new AssertionError("Default Authenticator called " + count(count)
+ " expected it to be called " + expected(defaultCount));
}
// Now tries with the default authenticator: it should be invoked.
System.out.println("\nClient: Using the default authenticator: "
+ toString(null));
HTTPTestClient.connect(protocol, server, mode, null);
count = authOne.count.get();
if (count != expectedIncrement) {
throw new AssertionError("Authenticator #1 called " + count(count)
+ " expected it to be called " + expected(expectedIncrement));
}
count = authTwo.count.get();
if (count != expectedIncrement) {
throw new AssertionError("Authenticator #2 called " + count(count)
+ " expected it to be called " + expected(expectedIncrement));
}
count = AUTHENTICATOR.count.get();
if (count != defaultCount + expectedIncrement) {
throw new AssertionError("Default Authenticator called " + count(count)
+ " expected it to be called " + expected(defaultCount + expectedIncrement));
}
// Now tries with explicitly setting the default authenticator: it should
// be invoked again.
// Uncomment the code below when 8169068 is available.
System.out.println("\nClient: Explicitly setting the default authenticator: "
+ toString(Authenticator.getDefault()));
HTTPTestClient.connect(protocol, server, mode, Authenticator.getDefault());
count = authOne.count.get();
if (count != expectedIncrement) {
throw new AssertionError("Authenticator #1 called " + count(count)
+ " expected it to be called " + expected(expectedIncrement));
}
count = authTwo.count.get();
if (count != expectedIncrement) {
throw new AssertionError("Authenticator #2 called " + count(count)
+ " expected it to be called " + expected(expectedIncrement));
}
count = AUTHENTICATOR.count.get();
if (count != defaultCount + 2 * expectedIncrement) {
throw new AssertionError("Default Authenticator called " + count(count)
+ " expected it to be called "
+ expected(defaultCount + 2 * expectedIncrement));
}
// Now tries to set an authenticator on a connected connection.
URL url = url(protocol, server.getAddress(), "/");
Proxy proxy = proxy(server, mode);
HttpURLConnection conn = openConnection(url, mode, proxy);
try {
conn.setAuthenticator(null);
throw new RuntimeException("Expected NullPointerException"
+ " trying to set a null authenticator"
+ " not raised.");
} catch (NullPointerException npe) {
System.out.println("Client: caught expected NPE"
+ " trying to set a null authenticator: "
+ npe);
}
conn.connect();
try {
try {
conn.setAuthenticator(authOne);
throw new RuntimeException("Expected IllegalStateException"
+ " trying to set an authenticator after connect"
+ " not raised.");
} catch (IllegalStateException ise) {
System.out.println("Client: caught expected ISE"
+ " trying to set an authenticator after connect: "
+ ise);
}
// Uncomment the code below when 8169068 is available.
try {
conn.setAuthenticator(Authenticator.getDefault());
throw new RuntimeException("Expected IllegalStateException"
+ " trying to set an authenticator after connect"
+ " not raised.");
} catch (IllegalStateException ise) {
System.out.println("Client: caught expected ISE"
+ " trying to set an authenticator after connect: "
+ ise);
}
try {
conn.setAuthenticator(null);
throw new RuntimeException("Expected"
+ " IllegalStateException or NullPointerException"
+ " trying to set a null authenticator after connect"
+ " not raised.");
} catch (IllegalStateException | NullPointerException xxe) {
System.out.println("Client: caught expected "
+ xxe.getClass().getSimpleName()
+ " trying to set a null authenticator after connect: "
+ xxe);
}
} finally {
conn.disconnect();
}
// double check that authOne and authTwo haven't been invoked.
count = authOne.count.get();
if (count != expectedIncrement) {
throw new AssertionError("Authenticator #1 called " + count(count)
+ " expected it to be called " + expected(expectedIncrement));
}
count = authTwo.count.get();
if (count != expectedIncrement) {
throw new AssertionError("Authenticator #2 called " + count(count)
+ " expected it to be called " + expected(expectedIncrement));
}
// All good!
// return the number of times the default authenticator is supposed
// to have been called.
return scheme == HttpSchemeType.NONE ? 0 : 2 * EXPECTED_AUTH_CALLS_PER_TEST;
}
static String toString(Authenticator a) {
return a == null ? "null" : a.toString();
}
}

View file

@ -0,0 +1,306 @@
/*
* Copyright (c) 2016, 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.IOException;
import java.io.UncheckedIOException;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.URL;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import jdk.test.lib.net.SimpleSSLContext;
import static java.net.Proxy.NO_PROXY;
/*
* @test
* @bug 8169415
* @library /test/lib
* @modules java.logging
* java.base/sun.net.www
* jdk.httpserver/sun.net.httpserver
* @build jdk.test.lib.net.SimpleSSLContext HTTPTest HTTPTestServer HTTPTestClient
* @summary A simple HTTP test that starts an echo server supporting Digest
* authentication, then starts a regular HTTP client to invoke it.
* The client first does a GET request on "/", then follows on
* with a POST request that sends "Hello World!" to the server.
* The client expects to receive "Hello World!" in return.
* The test supports several execution modes:
* SERVER: The server performs Digest Server authentication;
* PROXY: The server pretends to be a proxy and performs
* Digest Proxy authentication;
* SERVER307: The server redirects the client (307) to another
* server that perform Digest authentication;
* PROXY305: The server attempts to redirect
* the client to a proxy using 305 code;
* @run main/othervm -Dtest.debug=true -Dtest.digest.algorithm=SHA-512 HTTPTest SERVER
* @run main/othervm -Dtest.debug=true -Dtest.digest.algorithm=SHA-256 HTTPTest SERVER
* @run main/othervm -Dtest.debug=true -Dhttp.auth.digest.reEnabledAlgorithms=MD5 HTTPTest SERVER
* @run main/othervm -Dtest.debug=true -Dhttp.auth.digest.reEnabledAlgorithms=MD5 HTTPTest PROXY
* @run main/othervm -Dtest.debug=true -Dhttp.auth.digest.reEnabledAlgorithms=MD5 HTTPTest SERVER307
* @run main/othervm -Dtest.debug=true -Dhttp.auth.digest.reEnabledAlgorithms=MD5 HTTPTest PROXY305
*
* @author danielfuchs
*/
public class HTTPTest {
public static final boolean DEBUG =
Boolean.parseBoolean(System.getProperty("test.debug", "false"));
public static enum HttpAuthType { SERVER, PROXY, SERVER307, PROXY305 };
public static enum HttpProtocolType { HTTP, HTTPS };
public static enum HttpSchemeType { NONE, BASICSERVER, BASIC, DIGEST };
public static final HttpAuthType DEFAULT_HTTP_AUTH_TYPE = HttpAuthType.SERVER;
public static final HttpProtocolType DEFAULT_PROTOCOL_TYPE = HttpProtocolType.HTTP;
public static final HttpSchemeType DEFAULT_SCHEME_TYPE = HttpSchemeType.DIGEST;
public static class HttpTestAuthenticator extends Authenticator {
private final String realm;
private final String username;
// Used to prevent incrementation of 'count' when calling the
// authenticator from the server side.
private final ThreadLocal<Boolean> skipCount = new ThreadLocal<>();
// count will be incremented every time getPasswordAuthentication()
// is called from the client side.
final AtomicInteger count = new AtomicInteger();
private final String name;
public HttpTestAuthenticator(String name, String realm, String username) {
this.name = name;
this.realm = realm;
this.username = username;
}
@Override
protected PasswordAuthentication getPasswordAuthentication() {
if (skipCount.get() == null || skipCount.get().booleanValue() == false) {
System.out.println("Authenticator " + name + " called: " + count.incrementAndGet());
}
return new PasswordAuthentication(getUserName(),
new char[] {'b','a','r'});
}
// Called by the server side to get the password of the user
// being authentified.
public final char[] getPassword(String user) {
if (user.equals(username)) {
skipCount.set(Boolean.TRUE);
try {
return getPasswordAuthentication().getPassword();
} finally {
skipCount.set(Boolean.FALSE);
}
}
throw new SecurityException("User unknown: " + user);
}
@Override
public String toString() {
return super.toString() + "[name=\"" + name + "\"]";
}
public final String getUserName() {
return username;
}
public final String getRealm() {
return realm;
}
}
public static final HttpTestAuthenticator AUTHENTICATOR;
static {
AUTHENTICATOR = new HttpTestAuthenticator("AUTHENTICATOR","dublin", "foox");
Authenticator.setDefault(AUTHENTICATOR);
}
static {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
SSLContext.setDefault(SimpleSSLContext.findSSLContext());
}
static final Logger logger = Logger.getLogger ("com.sun.net.httpserver");
static {
if (DEBUG) logger.setLevel(Level.ALL);
Stream.of(Logger.getLogger("").getHandlers())
.forEach(h -> h.setLevel(Level.ALL));
}
static final int EXPECTED_AUTH_CALLS_PER_TEST = 1;
public static void main(String[] args) throws Exception {
// new HTTPTest().execute(HttpAuthType.SERVER.name());
new HTTPTest().execute(args);
}
public void execute(String... args) throws Exception {
Stream<HttpAuthType> modes;
if (args == null || args.length == 0) {
modes = Stream.of(HttpAuthType.values());
} else {
modes = Stream.of(args).map(HttpAuthType::valueOf);
}
modes.forEach(this::test);
System.out.println("Test PASSED - Authenticator called: "
+ expected(AUTHENTICATOR.count.get()));
}
public void test(HttpAuthType mode) {
for (HttpProtocolType type: HttpProtocolType.values()) {
test(type, mode);
}
}
public HttpSchemeType getHttpSchemeType() {
return DEFAULT_SCHEME_TYPE;
}
public void test(HttpProtocolType protocol, HttpAuthType mode) {
if (mode == HttpAuthType.PROXY305 && protocol == HttpProtocolType.HTTPS ) {
// silently skip unsupported test combination
return;
}
String digestalg = System.getProperty("test.digest.algorithm");
if (digestalg == null || "".equals(digestalg))
digestalg = "MD5";
System.out.println("\n**** Testing " + protocol + " "
+ mode + " mode ****\n");
int authCount = AUTHENTICATOR.count.get();
int expectedIncrement = 0;
try {
// Creates an HTTP server that echoes back whatever is in the
// request body.
HTTPTestServer server =
HTTPTestServer.create(protocol,
mode,
AUTHENTICATOR,
getHttpSchemeType(),
null,
digestalg);
try {
expectedIncrement += run(server, protocol, mode);
} finally {
server.stop();
}
} catch (IOException ex) {
ex.printStackTrace(System.err);
throw new UncheckedIOException(ex);
}
int count = AUTHENTICATOR.count.get();
if (count != authCount + expectedIncrement) {
throw new AssertionError("Authenticator called " + count(count)
+ " expected it to be called "
+ expected(authCount + expectedIncrement));
}
}
/**
* Runs the test with the given parameters.
* @param server The server
* @param protocol The protocol (HTTP/HTTPS)
* @param mode The mode (PROXY, SERVER, SERVER307...)
* @return The number of times the default authenticator should have been
* called.
* @throws IOException in case of connection or protocol issues
*/
public int run(HTTPTestServer server,
HttpProtocolType protocol,
HttpAuthType mode)
throws IOException
{
// Connect to the server with a GET request, then with a
// POST that contains "Hello World!"
HTTPTestClient.connect(protocol, server, mode, null);
// return the number of times the default authenticator is supposed
// to have been called.
return EXPECTED_AUTH_CALLS_PER_TEST;
}
public static String count(int count) {
switch(count) {
case 0: return "not even once";
case 1: return "once";
case 2: return "twice";
default: return String.valueOf(count) + " times";
}
}
public static String expected(int count) {
switch(count) {
default: return count(count);
}
}
public static String protocol(HttpProtocolType type) {
return type.name().toLowerCase(Locale.US);
}
public static URL url(HttpProtocolType protocol, InetSocketAddress address,
String path) throws MalformedURLException {
return new URL(protocol(protocol),
address.getAddress().getHostAddress(),
address.getPort(), path);
}
public static Proxy proxy(HTTPTestServer server, HttpAuthType authType) {
if (authType != HttpAuthType.PROXY) return null;
InetSocketAddress proxyAddress = server.getProxyAddress();
if (!proxyAddress.isUnresolved()) {
// Forces the proxy to use an unresolved address created
// from the actual IP address to avoid using the proxy
// address hostname which would result in resolving to
// a posibly different address. For instance we want to
// avoid cases such as:
// ::1 => "localhost" => 127.0.0.1
proxyAddress = InetSocketAddress.
createUnresolved(proxyAddress.getAddress().getHostAddress(),
proxyAddress.getPort());
}
return new Proxy(Proxy.Type.HTTP, proxyAddress);
}
public static HttpURLConnection openConnection(URL url,
HttpAuthType authType,
Proxy proxy)
throws IOException {
HttpURLConnection conn = (HttpURLConnection)
(authType == HttpAuthType.PROXY
? url.openConnection(proxy)
: url.openConnection(NO_PROXY));
return conn;
}
}

View file

@ -0,0 +1,119 @@
/*
* Copyright (c) 2016, 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.IOException;
import java.net.Authenticator;
import java.net.BindException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.time.Duration;
import javax.net.ssl.HttpsURLConnection;
/**
* A simple Http client that connects to the HTTPTestServer.
* @author danielfuchs
*/
public class HTTPTestClient extends HTTPTest {
public static final long DELAY_BEFORE_RETRY = 2500; // milliseconds
public static void connect(HttpProtocolType protocol,
HTTPTestServer server,
HttpAuthType authType,
Authenticator auth)
throws IOException {
try {
doConnect(protocol, server, authType, auth);
} catch (BindException ex) {
// sleep a bit then try again once
System.out.println("WARNING: Unexpected BindException: " + ex);
System.out.println("\tSleeping a bit and try again...");
long start = System.nanoTime();
System.gc();
try {
Thread.sleep(DELAY_BEFORE_RETRY);
} catch (InterruptedException iex) {
// ignore
}
System.gc();
System.out.println("\tRetrying after "
+ Duration.ofNanos(System.nanoTime() - start).toMillis()
+ " milliseconds");
doConnect(protocol, server, authType, auth);
}
}
public static void doConnect(HttpProtocolType protocol,
HTTPTestServer server,
HttpAuthType authType,
Authenticator auth)
throws IOException {
InetSocketAddress address = server.getAddress();
final URL url = url(protocol, address, "/");
final Proxy proxy = proxy(server, authType);
System.out.println("Client: FIRST request: " + url + " GET");
HttpURLConnection conn = openConnection(url, authType, proxy);
configure(conn, auth);
System.out.println("Response code: " + conn.getResponseCode());
String result = new String(conn.getInputStream().readAllBytes(), "UTF-8");
System.out.println("Response body: " + result);
if (!result.isEmpty()) {
throw new RuntimeException("Unexpected response to GET: " + result);
}
System.out.println("\nClient: NEXT request: " + url + " POST");
conn = openConnection(url, authType, proxy);
configure(conn, auth);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setDoInput(true);
conn.getOutputStream().write("Hello World!".getBytes("UTF-8"));
System.out.println("Response code: " + conn.getResponseCode());
result = new String(conn.getInputStream().readAllBytes(), "UTF-8");
System.out.println("Response body: " + result);
if ("Hello World!".equals(result)) {
System.out.println("Test passed!");
} else {
throw new RuntimeException("Unexpected response to POST: " + result);
}
}
private static void configure(HttpURLConnection conn, Authenticator auth)
throws IOException {
if (auth != null) {
conn.setAuthenticator(auth);
}
if (conn instanceof HttpsURLConnection) {
System.out.println("Client: configuring SSL connection");
// We have set a default SSLContext so we don't need to do
// anything here. Otherwise it could look like:
// HttpsURLConnection httpsConn = (HttpsURLConnection)conn;
// httpsConn.setSSLSocketFactory(
// SimpleSSLContext.findSSLContext().getSocketFactory());
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,157 @@
/*
* Copyright (c) 2012, 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 7128648
* @library /test/lib
* @modules jdk.httpserver
* @summary HttpURLConnection.getHeaderFields should return an unmodifiable Map
*/
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.HttpURLConnection;
import java.util.Collection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.Headers;
import static java.net.Proxy.NO_PROXY;
import jdk.test.lib.net.URIBuilder;
public class UnmodifiableMaps {
void test(String[] args) throws Exception {
HttpServer server = startHttpServer();
try {
InetSocketAddress address = server.getAddress();
URI uri = URIBuilder.newBuilder()
.scheme("http")
.host(address.getAddress())
.port(address.getPort())
.path("/foo")
.build();
doClient(uri);
} finally {
server.stop(0);
}
}
void doClient(URI uri) throws Exception {
HttpURLConnection uc = (HttpURLConnection) uri.toURL().openConnection(NO_PROXY);
// Test1: getRequestProperties is unmodifiable
System.out.println("Check getRequestProperties");
checkUnmodifiable(uc.getRequestProperties());
uc.addRequestProperty("X", "V");
uc.addRequestProperty("X1", "V1");
checkUnmodifiable(uc.getRequestProperties());
int resp = uc.getResponseCode();
check(resp == 200,
"Unexpected response code. Expected 200, got " + resp);
// Test2: getHeaderFields is unmodifiable
System.out.println("Check getHeaderFields");
checkUnmodifiable(uc.getHeaderFields());
// If the implementation does caching, check again.
checkUnmodifiable(uc.getHeaderFields());
}
// HTTP Server
HttpServer startHttpServer() throws IOException {
InetAddress loopback = InetAddress.getLoopbackAddress();
HttpServer httpServer = HttpServer.create(new InetSocketAddress(loopback, 0), 0);
httpServer.createContext("/foo", new SimpleHandler());
httpServer.start();
return httpServer;
}
class SimpleHandler implements HttpHandler {
@Override
public void handle(HttpExchange t) throws IOException {
Headers respHeaders = t.getResponseHeaders();
// ensure some response headers, over the usual ones
respHeaders.add("RespHdr1", "Value1");
respHeaders.add("RespHdr2", "Value2");
respHeaders.add("RespHdr3", "Value3");
t.sendResponseHeaders(200, -1);
t.close();
}
}
void checkUnmodifiable(Map<String,List<String>> map) {
checkUnmodifiableMap(map);
// Now check the individual values
Collection<List<String>> values = map.values();
for (List<String> value : values) {
checkUnmodifiableList(value);
}
}
void checkUnmodifiableMap(final Map<String,List<String>> map) {
expectThrow( new Runnable() {
public void run() { map.clear(); }});
expectThrow( new Runnable() {
public void run() { map.put("X", new ArrayList<String>()); }});
expectThrow( new Runnable() {
public void run() { map.remove("X"); }});
}
void checkUnmodifiableList(final List<String> list) {
expectThrow( new Runnable() {
public void run() { list.clear(); }});
expectThrow( new Runnable() {
public void run() { list.add("X"); }});
expectThrow( new Runnable() {
public void run() { list.remove("X"); }});
}
void expectThrow(Runnable r) {
try { r.run(); fail("Excepted UOE to be thrown."); Thread.dumpStack(); }
catch (UnsupportedOperationException e) { pass(); }
}
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++;}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);}
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,64 @@
/*
* Copyright (c) 2002, 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 4666195
* @build getResponseCode
* @run main getResponseCode
* @summary REGRESSION: HttpURLConnection.getResponseCode() returns always -1
*/
import java.net.*;
import java.io.*;
public class getResponseCode {
public static void main(String[] args) throws Exception {
try {
MyHttpURLConnectionImpl myCon = new MyHttpURLConnectionImpl(null);
int responseCode = myCon.getResponseCode();
if (responseCode == -1) {
throw new RuntimeException("java.net.HttpURLConnection "
+"should provide implementation "
+"for getResponseCode()");
}
} catch (java.net.UnknownServiceException e) {
System.out.println("PASS");
}
}
}
class MyHttpURLConnectionImpl extends java.net.HttpURLConnection {
MyHttpURLConnectionImpl(URL url) {
super(url);
}
public boolean usingProxy(){
return true;
}
public void connect(){
}
public void disconnect(){
}
}