8306940: test/jdk/java/net/httpclient/XxxxInURI.java should call HttpClient::close

Reviewed-by: jpai, djelinski
This commit is contained in:
Daniel Fuchs 2023-04-27 08:25:40 +00:00
parent d94ce6566d
commit 41d58533ac
3 changed files with 315 additions and 194 deletions

View File

@ -36,9 +36,6 @@
*/
//* -Djdk.internal.httpclient.debug=true
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;
import jdk.test.lib.net.SimpleSSLContext;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterTest;
@ -48,6 +45,7 @@ import org.testng.annotations.Test;
import javax.net.ServerSocketFactory;
import javax.net.ssl.SSLContext;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -57,6 +55,7 @@ import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpClient.Version;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublisher;
import java.net.http.HttpRequest.BodyPublishers;
@ -74,14 +73,11 @@ import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import jdk.httpclient.test.lib.common.HttpServerAdapters;
import jdk.httpclient.test.lib.http2.Http2TestServer;
import static java.lang.String.format;
import static java.lang.System.in;
import static java.lang.System.err;
import static java.lang.System.out;
import static java.net.http.HttpClient.Version.HTTP_1_1;
import static java.net.http.HttpClient.Version.HTTP_2;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.net.http.HttpClient.Builder.NO_PROXY;
import static org.testng.Assert.assertEquals;
@ -94,8 +90,8 @@ public class EncodedCharsInURI implements HttpServerAdapters {
HttpTestServer httpsTestServer; // HTTPS/1.1
HttpTestServer http2TestServer; // HTTP/2 ( h2c )
HttpTestServer https2TestServer; // HTTP/2 ( h2 )
DummyServer httpDummyServer; // HTTP/1.1 [ 2 servers ]
DummyServer httpsDummyServer; // HTTPS/1.1
DummyServer httpDummyServer; // HTTP/1.1 [ 2 servers ]
DummyServer httpsDummyServer; // HTTPS/1.1
String httpURI_fixed;
String httpURI_chunk;
String httpsURI_fixed;
@ -140,8 +136,8 @@ public class EncodedCharsInURI implements HttpServerAdapters {
command.run();
} catch (Throwable t) {
tasksFailed = true;
System.out.printf(now() + "Task %s failed: %s%n", id, t);
System.err.printf(now() + "Task %s failed: %s%n", id, t);
out.printf(now() + "Task %s failed: %s%n", id, t);
err.printf(now() + "Task %s failed: %s%n", id, t);
FAILURES.putIfAbsent("Task " + id, t);
throw t;
}
@ -162,7 +158,7 @@ public class EncodedCharsInURI implements HttpServerAdapters {
e.getValue().printStackTrace(out);
});
if (tasksFailed) {
System.out.println("WARNING: Some tasks failed");
out.println("WARNING: Some tasks failed");
}
} finally {
out.println("\n=========================\n");
@ -201,6 +197,14 @@ public class EncodedCharsInURI implements HttpServerAdapters {
return result;
}
static Version version(String uri) {
if (uri.contains("/http1/") || uri.contains("/https1/"))
return HTTP_1_1;
if (uri.contains("/http2/") || uri.contains("/https2/"))
return HTTP_2;
return null;
}
private HttpClient makeNewClient() {
clientCount.incrementAndGet();
return HttpClient.newBuilder()
@ -225,6 +229,14 @@ public class EncodedCharsInURI implements HttpServerAdapters {
final String ENCODED = "/01%252F03/";
record CloseableClient(HttpClient client, boolean shared)
implements Closeable {
public void close() {
if (shared) return;
client.close();
}
}
@Test(dataProvider = "noThrows")
public void testEncodedChars(String uri, boolean sameClient)
throws Exception {
@ -232,29 +244,34 @@ public class EncodedCharsInURI implements HttpServerAdapters {
out.printf("%n%s testEncodedChars(%s, %b)%n", now(), uri, sameClient);
uri = uri + ENCODED;
for (int i=0; i< ITERATION_COUNT; i++) {
if (!sameClient || client == null)
if (!sameClient || client == null) {
client = newHttpClient(sameClient);
}
try (var cl = new CloseableClient(client, sameClient)) {
BodyPublisher bodyPublisher = BodyPublishers.ofString(uri);
BodyPublisher bodyPublisher = BodyPublishers.ofString(uri);
HttpRequest req = HttpRequest.newBuilder(URI.create(uri))
.POST(bodyPublisher)
.build();
BodyHandler<String> handler = BodyHandlers.ofString();
CompletableFuture<HttpResponse<String>> responseCF = client.sendAsync(req, handler);
HttpResponse<String> response = responseCF.join();
String body = response.body();
if (!uri.contains(body)) {
System.err.println("Test failed: " + response);
throw new RuntimeException(uri + " doesn't contain '" + body + "'");
} else {
System.out.println("Found expected " + body + " in " + uri);
HttpRequest req = HttpRequest.newBuilder(URI.create(uri))
.POST(bodyPublisher)
.build();
BodyHandler<String> handler = BodyHandlers.ofString();
CompletableFuture<HttpResponse<String>> responseCF = client.sendAsync(req, handler);
HttpResponse<String> response = responseCF.join();
String body = response.body();
if (!uri.contains(body)) {
err.println("Test failed: " + response);
throw new RuntimeException(uri + " doesn't contain '" + body + "'");
} else {
out.println("Found expected " + body + " in " + uri);
}
assertEquals(response.version(), version(uri));
}
}
}
@BeforeTest
public void setup() throws Exception {
out.println(now() + "begin setup");
sslContext = new SimpleSSLContext().get();
if (sslContext == null)
throw new AssertionError("Unexpected null sslContext");
@ -297,6 +314,7 @@ public class EncodedCharsInURI implements HttpServerAdapters {
httpDummy = "http://" + httpDummyServer.serverAuthority() + "/http1/dummy/x";
httpsDummy = "https://" + httpsDummyServer.serverAuthority() + "/https1/dummy/x";
err.println(now() + "Starting servers");
serverCount.addAndGet(6);
httpTestServer.start();
@ -305,11 +323,21 @@ public class EncodedCharsInURI implements HttpServerAdapters {
https2TestServer.start();
httpDummyServer.start();
httpsDummyServer.start();
out.println("HTTP/1.1 dummy server (http) listening at: " + httpDummyServer.serverAuthority());
out.println("HTTP/1.1 dummy server (TLS) listening at: " + httpsDummyServer.serverAuthority());
out.println("HTTP/1.1 server (http) listening at: " + httpTestServer.serverAuthority());
out.println("HTTP/1.1 server (TLS) listening at: " + httpsTestServer.serverAuthority());
out.println("HTTP/2 server (h2c) listening at: " + http2TestServer.serverAuthority());
out.println("HTTP/2 server (h2) listening at: " + https2TestServer.serverAuthority());
out.println(now() + "setup done");
err.println(now() + "setup done");
}
@AfterTest
public void teardown() throws Exception {
sharedClient = null;
sharedClient.close();
httpTestServer.stop();
httpsTestServer.stop();
http2TestServer.stop();
@ -390,14 +418,13 @@ public class EncodedCharsInURI implements HttpServerAdapters {
while(!stopped) {
Socket clientConnection = ss.accept();
connections.add(clientConnection);
System.out.println(now() + getName() + ": Client accepted");
out.println(now() + getName() + ": Client accepted");
StringBuilder headers = new StringBuilder();
Socket targetConnection = null;
InputStream ccis = clientConnection.getInputStream();
OutputStream ccos = clientConnection.getOutputStream();
System.out.println(now() + getName() + ": Reading request line");
out.println(now() + getName() + ": Reading request line");
String requestLine = readLine(ccis);
System.out.println(now() + getName() + ": Request line: " + requestLine);
out.println(now() + getName() + ": Request line: " + requestLine);
StringTokenizer tokenizer = new StringTokenizer(requestLine);
String method = tokenizer.nextToken();
@ -408,7 +435,7 @@ public class EncodedCharsInURI implements HttpServerAdapters {
String hostport = serverAuthority();
uri = new URI((secure ? "https" : "http") +"://" + hostport + path);
} catch (Throwable x) {
System.err.printf("Bad target address: \"%s\" in \"%s\"%n",
err.printf("Bad target address: \"%s\" in \"%s\"%n",
path, requestLine);
clientConnection.close();
continue;
@ -418,7 +445,7 @@ public class EncodedCharsInURI implements HttpServerAdapters {
// signals the end of all headers.
String line = requestLine;
while (!line.equals("")) {
System.out.println(now() + getName() + ": Reading header: "
out.println(now() + getName() + ": Reading header: "
+ (line = readLine(ccis)));
headers.append(line).append("\r\n");
}
@ -435,11 +462,11 @@ public class EncodedCharsInURI implements HttpServerAdapters {
StringTokenizer tk = new StringTokenizer(cl);
int len = Integer.parseInt(tk.nextToken());
assert len < b.length * 2;
System.out.println(now() + getName()
out.println(now() + getName()
+ ": received body: "
+ new String(ccis.readNBytes(len), UTF_8));
}
System.out.println(now()
out.println(now()
+ getName() + ": sending back " + uri);
response.append("HTTP/1.1 200 OK\r\nContent-Length: ")
@ -447,21 +474,21 @@ public class EncodedCharsInURI implements HttpServerAdapters {
.append("\r\n\r\n");
// Then send the 200 OK response to the client
System.out.println(now() + getName() + ": Sending "
out.println(now() + getName() + ": Sending "
+ response);
ccos.write(response.toString().getBytes(UTF_8));
ccos.flush();
System.out.println(now() + getName() + ": sent response headers");
out.println(now() + getName() + ": sent response headers");
ccos.write(b);
ccos.flush();
ccos.close();
System.out.println(now() + getName() + ": sent " + b.length + " body bytes");
out.println(now() + getName() + ": sent " + b.length + " body bytes");
connections.remove(clientConnection);
clientConnection.close();
}
} catch (Throwable t) {
if (!stopped) {
System.out.println(now() + getName() + ": failed: " + t);
out.println(now() + getName() + ": failed: " + t);
t.printStackTrace();
try {
stopServer();
@ -470,7 +497,7 @@ public class EncodedCharsInURI implements HttpServerAdapters {
}
}
} finally {
System.out.println(now() + getName() + ": exiting");
out.println(now() + getName() + ": exiting");
}
}
@ -504,7 +531,6 @@ public class EncodedCharsInURI implements HttpServerAdapters {
return new DummyServer(ss, true);
}
}
}

View File

@ -32,11 +32,7 @@
* EscapedOctetsInURI
*/
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -45,37 +41,43 @@ import java.net.InetSocketAddress;
import java.net.URI;
import javax.net.ssl.SSLContext;
import java.net.http.HttpClient;
import java.net.http.HttpClient.Version;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import jdk.httpclient.test.lib.http2.Http2TestServer;
import jdk.httpclient.test.lib.http2.Http2TestExchange;
import jdk.httpclient.test.lib.http2.Http2Handler;
import jdk.httpclient.test.lib.common.HttpServerAdapters;
import jdk.test.lib.net.SimpleSSLContext;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static java.lang.System.err;
import static java.lang.System.out;
import static java.net.http.HttpClient.Version.HTTP_1_1;
import static java.net.http.HttpClient.Version.HTTP_2;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.net.http.HttpClient.Builder.NO_PROXY;
import static org.testng.Assert.assertEquals;
public class EscapedOctetsInURI {
public class EscapedOctetsInURI implements HttpServerAdapters {
SSLContext sslContext;
HttpServer httpTestServer; // HTTP/1.1 [ 4 servers ]
HttpsServer httpsTestServer; // HTTPS/1.1
Http2TestServer http2TestServer; // HTTP/2 ( h2c )
Http2TestServer https2TestServer; // HTTP/2 ( h2 )
HttpTestServer httpTestServer; // HTTP/1.1 [ 4 servers ]
HttpTestServer httpsTestServer; // HTTPS/1.1
HttpTestServer http2TestServer; // HTTP/2 ( h2c )
HttpTestServer https2TestServer; // HTTP/2 ( h2 )
String httpURI;
String httpsURI;
String http2URI;
String https2URI;
private volatile HttpClient sharedClient;
static final String[][] pathsAndQueryStrings = new String[][] {
// partial-path URI query
{ "/001/noSpace", "?noQuotedOctets" },
@ -110,6 +112,52 @@ public class EscapedOctetsInURI {
static final int ITERATION_COUNT = 3; // checks upgrade and re-use
static final long start = System.nanoTime();
public static String now() {
long now = System.nanoTime() - start;
long secs = now / 1000_000_000;
long mill = (now % 1000_000_000) / 1000_000;
long nan = now % 1000_000;
return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan);
}
static Version version(String uri) {
if (uri.contains("/http1/") || uri.contains("/https1/"))
return HTTP_1_1;
if (uri.contains("/http2/") || uri.contains("/https2/"))
return HTTP_2;
return null;
}
private HttpClient makeNewClient() {
return HttpClient.newBuilder()
.proxy(NO_PROXY)
.sslContext(sslContext)
.build();
}
HttpClient newHttpClient(boolean share) {
if (!share) return makeNewClient();
HttpClient shared = sharedClient;
if (shared != null) return shared;
synchronized (this) {
shared = sharedClient;
if (shared == null) {
shared = sharedClient = makeNewClient();
}
return shared;
}
}
record CloseableClient(HttpClient client, boolean shared)
implements Closeable {
public void close() {
if (shared) return;
client.close();
}
}
@Test(dataProvider = "variants")
void test(String uriString, boolean sameClient) throws Exception {
System.out.println("\n--- Starting ");
@ -121,122 +169,114 @@ public class EscapedOctetsInURI {
HttpClient client = null;
for (int i=0; i< ITERATION_COUNT; i++) {
if (!sameClient || client == null)
client = HttpClient.newBuilder()
.proxy(NO_PROXY)
.sslContext(sslContext)
.build();
if (!sameClient || client == null) {
client = newHttpClient(sameClient);
}
HttpRequest request = HttpRequest.newBuilder(uri).build();
HttpResponse<String> resp = client.send(request, BodyHandlers.ofString());
try (var cl = new CloseableClient(client, sameClient)) {
HttpRequest request = HttpRequest.newBuilder(uri).build();
HttpResponse<String> resp = client.send(request, BodyHandlers.ofString());
out.println("Got response: " + resp);
out.println("Got body: " + resp.body());
assertEquals(resp.statusCode(), 200,
"Expected 200, got:" + resp.statusCode());
out.println("Got response: " + resp);
out.println("Got body: " + resp.body());
assertEquals(resp.statusCode(), 200,
"Expected 200, got:" + resp.statusCode());
// the response body should contain the exact escaped request URI
URI retrievedURI = URI.create(resp.body());
assertEquals(retrievedURI.getRawPath(), uri.getRawPath());
assertEquals(retrievedURI.getRawQuery(), uri.getRawQuery());
// the response body should contain the exact escaped request URI
URI retrievedURI = URI.create(resp.body());
assertEquals(retrievedURI.getRawPath(), uri.getRawPath());
assertEquals(retrievedURI.getRawQuery(), uri.getRawQuery());
assertEquals(resp.version(), version(uriString));
}
}
}
@Test(dataProvider = "variants")
void testAsync(String uriString, boolean sameClient) {
void testAsync(String uriString, boolean sameClient) throws Exception {
System.out.println("\n--- Starting ");
URI uri = URI.create(uriString);
HttpClient client = null;
for (int i=0; i< ITERATION_COUNT; i++) {
if (!sameClient || client == null)
client = HttpClient.newBuilder()
.proxy(NO_PROXY)
.sslContext(sslContext)
.build();
if (!sameClient || client == null) {
client = newHttpClient(sameClient);
}
HttpRequest request = HttpRequest.newBuilder(uri).build();
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(response -> {
out.println("Got response: " + response);
out.println("Got body: " + response.body());
assertEquals(response.statusCode(), 200);
return response.body(); })
.thenApply(body -> URI.create(body))
.thenAccept(retrievedURI -> {
// the body should contain the exact escaped request URI
assertEquals(retrievedURI.getRawPath(), uri.getRawPath());
assertEquals(retrievedURI.getRawQuery(), uri.getRawQuery()); })
.join();
try (var cl = new CloseableClient(client, sameClient)) {
HttpRequest request = HttpRequest.newBuilder(uri).build();
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(response -> {
out.println("Got response: " + response);
out.println("Got body: " + response.body());
assertEquals(response.statusCode(), 200);
assertEquals(response.version(), version(uriString));
return response.body();
})
.thenApply(body -> URI.create(body))
.thenAccept(retrievedURI -> {
// the body should contain the exact escaped request URI
assertEquals(retrievedURI.getRawPath(), uri.getRawPath());
assertEquals(retrievedURI.getRawQuery(), uri.getRawQuery());
}).join();
}
}
}
static String serverAuthority(HttpServer server) {
return InetAddress.getLoopbackAddress().getHostName() + ":"
+ server.getAddress().getPort();
}
@BeforeTest
public void setup() throws Exception {
out.println(now() + "begin setup");
sslContext = new SimpleSSLContext().get();
if (sslContext == null)
throw new AssertionError("Unexpected null sslContext");
InetSocketAddress sa = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
httpTestServer = HttpServer.create(sa, 0);
httpTestServer.createContext("/http1", new Http1ASCIIUriStringHandler());
httpURI = "http://" + serverAuthority(httpTestServer) + "/http1";
httpTestServer = HttpTestServer.create(HTTP_1_1);
httpTestServer.addHandler(new HttpASCIIUriStringHandler(), "/http1/get");
httpURI = "http://" + httpTestServer.serverAuthority() + "/http1/get";
httpsTestServer = HttpsServer.create(sa, 0);
httpsTestServer.setHttpsConfigurator(new HttpsConfigurator(sslContext));
httpsTestServer.createContext("/https1", new Http1ASCIIUriStringHandler());
httpsURI = "https://" + serverAuthority(httpsTestServer) + "/https1";
httpsTestServer = HttpTestServer.create(HTTP_1_1, sslContext);
httpsTestServer.addHandler(new HttpASCIIUriStringHandler(), "/https1/get");
httpsURI = "https://" + httpsTestServer.serverAuthority() + "/https1/get";
http2TestServer = new Http2TestServer("localhost", false, 0);
http2TestServer.addHandler(new HttpASCIIUriStringHandler(), "/http2");
http2URI = "http://" + http2TestServer.serverAuthority() + "/http2";
http2TestServer = HttpTestServer.create(HTTP_2);
http2TestServer.addHandler(new HttpASCIIUriStringHandler(), "/http2/get");
http2URI = "http://" + http2TestServer.serverAuthority() + "/http2/get";
https2TestServer = new Http2TestServer("localhost", true, sslContext);
https2TestServer.addHandler(new HttpASCIIUriStringHandler(), "/https2");
https2URI = "https://" + https2TestServer.serverAuthority() + "/https2";
https2TestServer = HttpTestServer.create(HTTP_2, sslContext);
https2TestServer.addHandler(new HttpASCIIUriStringHandler(), "/https2/get");
https2URI = "https://" + https2TestServer.serverAuthority() + "/https2/get";
err.println(now() + "Starting servers");
httpTestServer.start();
httpsTestServer.start();
http2TestServer.start();
https2TestServer.start();
out.println("HTTP/1.1 server (http) listening at: " + httpTestServer.serverAuthority());
out.println("HTTP/1.1 server (TLS) listening at: " + httpsTestServer.serverAuthority());
out.println("HTTP/2 server (h2c) listening at: " + http2TestServer.serverAuthority());
out.println("HTTP/2 server (h2) listening at: " + https2TestServer.serverAuthority());
out.println(now() + "setup done");
err.println(now() + "setup done");
}
@AfterTest
public void teardown() throws Exception {
httpTestServer.stop(0);
httpsTestServer.stop(0);
sharedClient.close();
httpTestServer.stop();
httpsTestServer.stop();
http2TestServer.stop();
https2TestServer.stop();
}
/** A handler that returns as its body the exact escaped request URI. */
static class Http1ASCIIUriStringHandler implements HttpHandler {
static class HttpASCIIUriStringHandler implements HttpTestHandler {
@Override
public void handle(HttpExchange t) throws IOException {
public void handle(HttpTestExchange t) throws IOException {
String asciiUriString = t.getRequestURI().toASCIIString();
out.println("Http1ASCIIUriString received, asciiUriString: " + asciiUriString);
try (InputStream is = t.getRequestBody();
OutputStream os = t.getResponseBody()) {
is.readAllBytes();
byte[] bytes = asciiUriString.getBytes(US_ASCII);
t.sendResponseHeaders(200, bytes.length);
os.write(bytes);
}
}
}
/** A handler that returns as its body the exact escaped request URI. */
static class HttpASCIIUriStringHandler implements Http2Handler {
@Override
public void handle(Http2TestExchange t) throws IOException {
String asciiUriString = t.getRequestURI().toASCIIString();
out.println("Http2ASCIIUriString received, asciiUriString: " + asciiUriString);
out.println("HttpASCIIUriString received, asciiUriString: " + asciiUriString);
try (InputStream is = t.getRequestBody();
OutputStream os = t.getResponseBody()) {
is.readAllBytes();

View File

@ -34,17 +34,14 @@
* NonAsciiCharsInURI
*/
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URI;
import javax.net.ssl.SSLContext;
import java.net.http.HttpClient;
import java.net.http.HttpClient.Version;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
@ -52,7 +49,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import jdk.httpclient.test.lib.common.HttpServerAdapters;
import jdk.httpclient.test.lib.http2.Http2TestServer;
import jdk.test.lib.net.SimpleSSLContext;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
@ -78,6 +74,8 @@ public class NonAsciiCharsInURI implements HttpServerAdapters {
String http2URI;
String https2URI;
private volatile HttpClient sharedClient;
// = '\u20AC' => 0xE20x820xAC
static final String[][] pathsAndQueryStrings = new String[][] {
// partial-path
@ -110,6 +108,51 @@ public class NonAsciiCharsInURI implements HttpServerAdapters {
return list.stream().toArray(Object[][]::new);
}
static final long start = System.nanoTime();
public static String now() {
long now = System.nanoTime() - start;
long secs = now / 1000_000_000;
long mill = (now % 1000_000_000) / 1000_000;
long nan = now % 1000_000;
return String.format("[%d s, %d ms, %d ns] ", secs, mill, nan);
}
static Version version(String uri) {
if (uri.contains("/http1/") || uri.contains("/https1/"))
return HTTP_1_1;
if (uri.contains("/http2/") || uri.contains("/https2/"))
return HTTP_2;
return null;
}
private HttpClient makeNewClient() {
return HttpClient.newBuilder()
.proxy(NO_PROXY)
.sslContext(sslContext)
.build();
}
HttpClient newHttpClient(boolean share) {
if (!share) return makeNewClient();
HttpClient shared = sharedClient;
if (shared != null) return shared;
synchronized (this) {
shared = sharedClient;
if (shared == null) {
shared = sharedClient = makeNewClient();
}
return shared;
}
}
record CloseableClient(HttpClient client, boolean shared)
implements Closeable {
public void close() {
if (shared) return;
client.close();
}
}
static final int ITERATION_COUNT = 3; // checks upgrade and re-use
@Test(dataProvider = "variants")
@ -122,106 +165,118 @@ public class NonAsciiCharsInURI implements HttpServerAdapters {
HttpClient client = null;
for (int i=0; i< ITERATION_COUNT; i++) {
if (!sameClient || client == null)
client = HttpClient.newBuilder()
.proxy(NO_PROXY)
.sslContext(sslContext)
.build();
if (!sameClient || client == null) {
client = newHttpClient(sameClient);
}
HttpRequest request = HttpRequest.newBuilder(uri).build();
HttpResponse<String> resp = client.send(request, BodyHandlers.ofString());
out.println("Got response: " + resp);
out.println("Got body: " + resp.body());
assertEquals(resp.statusCode(), 200,
"Expected 200, got:" + resp.statusCode());
try (var cl = new CloseableClient(client, sameClient)) {
HttpRequest request = HttpRequest.newBuilder(uri).build();
HttpResponse<String> resp = client.send(request, BodyHandlers.ofString());
// the response body should contain the toASCIIString
// representation of the URI
String expectedURIString = uri.toASCIIString();
if (!expectedURIString.contains(resp.body())) {
err.println("Test failed: " + resp);
throw new AssertionError(expectedURIString +
" does not contain '" + resp.body() + "'");
} else {
out.println("Found expected " + resp.body() + " in " + expectedURIString);
out.println("Got response: " + resp);
out.println("Got body: " + resp.body());
assertEquals(resp.statusCode(), 200,
"Expected 200, got:" + resp.statusCode());
// the response body should contain the toASCIIString
// representation of the URI
String expectedURIString = uri.toASCIIString();
if (!expectedURIString.contains(resp.body())) {
err.println("Test failed: " + resp);
throw new AssertionError(expectedURIString +
" does not contain '" + resp.body() + "'");
} else {
out.println("Found expected " + resp.body() + " in " + expectedURIString);
}
assertEquals(resp.version(), version(uriString));
}
}
}
@Test(dataProvider = "variants")
void testAsync(String uriString, boolean sameClient) {
void testAsync(String uriString, boolean sameClient) throws Exception {
out.println("\n--- Starting ");
URI uri = URI.create(uriString);
HttpClient client = null;
for (int i=0; i< ITERATION_COUNT; i++) {
if (!sameClient || client == null)
client = HttpClient.newBuilder()
.proxy(NO_PROXY)
.sslContext(sslContext)
.build();
if (!sameClient || client == null) {
client = newHttpClient(sameClient);
}
HttpRequest request = HttpRequest.newBuilder(uri).build();
try (var cl = new CloseableClient(client, sameClient)) {
HttpRequest request = HttpRequest.newBuilder(uri).build();
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(response -> {
out.println("Got response: " + response);
out.println("Got body: " + response.body());
assertEquals(response.statusCode(), 200);
return response.body(); })
.thenAccept(body -> {
// the response body should contain the toASCIIString
// representation of the URI
String expectedURIString = uri.toASCIIString();
if (!expectedURIString.contains(body)) {
err.println("Test failed: " + body);
throw new AssertionError(expectedURIString +
" does not contain '" + body + "'");
} else {
out.println("Found expected " + body + " in "
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(response -> {
out.println("Got response: " + response);
out.println("Got body: " + response.body());
assertEquals(response.statusCode(), 200);
assertEquals(response.version(), version(uriString));
return response.body();
})
.thenAccept(body -> {
// the response body should contain the toASCIIString
// representation of the URI
String expectedURIString = uri.toASCIIString();
if (!expectedURIString.contains(body)) {
err.println("Test failed: " + body);
throw new AssertionError(expectedURIString +
" does not contain '" + body + "'");
} else {
out.println("Found expected " + body + " in "
+ expectedURIString);
} })
.join();
}
})
.join();
}
}
}
static String serverAuthority(HttpTestServer server) {
return InetAddress.getLoopbackAddress().getHostName() + ":"
+ server.getAddress().getPort();
}
@BeforeTest
public void setup() throws Exception {
out.println(now() + "begin setup");
sslContext = new SimpleSSLContext().get();
if (sslContext == null)
throw new AssertionError("Unexpected null sslContext");
HttpTestHandler handler = new HttpUriStringHandler();
httpTestServer = HttpTestServer.create(HTTP_1_1);
httpTestServer.addHandler(handler, "/http1");
httpURI = "http://" + serverAuthority(httpTestServer) + "/http1";
httpTestServer.addHandler(handler, "/http1/get");
httpURI = "http://" + httpTestServer.serverAuthority() + "/http1/get";
httpsTestServer = HttpTestServer.create(HTTP_1_1, sslContext);
httpsTestServer.addHandler(handler, "/https1");
httpsURI = "https://" + serverAuthority(httpsTestServer) + "/https1";
httpsTestServer.addHandler(handler, "/https1/get");
httpsURI = "https://" + httpsTestServer.serverAuthority() + "/https1/get";
http2TestServer = HttpTestServer.create(HTTP_2);
http2TestServer.addHandler(handler, "/http2");
http2URI = "http://" + http2TestServer.serverAuthority() + "/http2";
http2TestServer.addHandler(handler, "/http2/get");
http2URI = "http://" + http2TestServer.serverAuthority() + "/http2/get";
https2TestServer = HttpTestServer.create(HTTP_2, sslContext);
https2TestServer.addHandler(handler, "/https2");
https2URI = "https://" + https2TestServer.serverAuthority() + "/https2";
https2TestServer.addHandler(handler, "/https2/get");
https2URI = "https://" + https2TestServer.serverAuthority() + "/https2/get";
err.println(now() + "Starting servers");
httpTestServer.start();
httpsTestServer.start();
http2TestServer.start();
https2TestServer.start();
out.println("HTTP/1.1 server (http) listening at: " + httpTestServer.serverAuthority());
out.println("HTTP/1.1 server (TLS) listening at: " + httpsTestServer.serverAuthority());
out.println("HTTP/2 server (h2c) listening at: " + http2TestServer.serverAuthority());
out.println("HTTP/2 server (h2) listening at: " + https2TestServer.serverAuthority());
out.println(now() + "setup done");
err.println(now() + "setup done");
}
@AfterTest
public void teardown() throws Exception {
sharedClient.close();
httpTestServer.stop();
httpsTestServer.stop();
http2TestServer.stop();
@ -233,7 +288,7 @@ public class NonAsciiCharsInURI implements HttpServerAdapters {
@Override
public void handle(HttpTestExchange t) throws IOException {
String uri = t.getRequestURI().toString();
out.println("Http1UriStringHandler received, uri: " + uri);
out.println("HttpUriStringHandler received, uri: " + uri);
try (InputStream is = t.getRequestBody();
OutputStream os = t.getResponseBody()) {
is.readAllBytes();