8a47429dc0
Reviewed-by: dfuchs
308 lines
13 KiB
Java
308 lines
13 KiB
Java
/*
|
|
* Copyright (c) 2015, 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.
|
|
*/
|
|
|
|
/*
|
|
* @test
|
|
* @bug 8087112 8159814
|
|
* @library /test/lib /test/jdk/java/net/httpclient/lib
|
|
* @build jdk.test.lib.net.SimpleSSLContext jdk.httpclient.test.lib.http2.Http2TestServer
|
|
* jdk.httpclient.test.lib.common.TestUtil jdk.httpclient.test.lib.http2.PushHandler
|
|
* @run testng/othervm
|
|
* -Djdk.httpclient.HttpClient.log=errors,requests,responses
|
|
* ServerPush
|
|
*/
|
|
|
|
import java.io.*;
|
|
import java.net.*;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.file.*;
|
|
import java.net.http.*;
|
|
import java.net.http.HttpResponse.BodyHandler;
|
|
import java.net.http.HttpResponse.BodyHandlers;
|
|
import java.net.http.HttpResponse.BodySubscribers;
|
|
import java.net.http.HttpResponse.PushPromiseHandler;
|
|
import java.util.*;
|
|
import java.util.concurrent.*;
|
|
import java.util.function.Consumer;
|
|
import jdk.httpclient.test.lib.common.TestUtil;
|
|
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.http2.PushHandler;
|
|
import org.testng.annotations.AfterTest;
|
|
import org.testng.annotations.BeforeTest;
|
|
import org.testng.annotations.Test;
|
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
|
import static org.testng.Assert.*;
|
|
|
|
public class ServerPush {
|
|
|
|
static final int LOOPS = 13;
|
|
static final int FILE_SIZE = 512 * 1024 + 343;
|
|
|
|
static Path tempFile;
|
|
|
|
Http2TestServer server;
|
|
URI uri;
|
|
|
|
@BeforeTest
|
|
public void setup() throws Exception {
|
|
tempFile = TestUtil.getAFile(FILE_SIZE);
|
|
server = new Http2TestServer(false, 0);
|
|
server.addHandler(new PushHandler(tempFile, LOOPS), "/");
|
|
System.out.println("Using temp file:" + tempFile);
|
|
|
|
System.err.println("Server listening on port " + server.getAddress().getPort());
|
|
server.start();
|
|
int port = server.getAddress().getPort();
|
|
uri = new URI("http://localhost:" + port + "/foo/a/b/c");
|
|
}
|
|
|
|
@AfterTest
|
|
public void teardown() {
|
|
server.stop();
|
|
}
|
|
|
|
// Test 1 - custom written push promise handler, everything as a String
|
|
@Test
|
|
public void testTypeString() throws Exception {
|
|
String tempFileAsString = new String(Files.readAllBytes(tempFile), UTF_8);
|
|
ConcurrentMap<HttpRequest, CompletableFuture<HttpResponse<String>>>
|
|
resultMap = new ConcurrentHashMap<>();
|
|
|
|
PushPromiseHandler<String> pph = (initial, pushRequest, acceptor) -> {
|
|
BodyHandler<String> s = BodyHandlers.ofString(UTF_8);
|
|
CompletableFuture<HttpResponse<String>> cf = acceptor.apply(s);
|
|
resultMap.put(pushRequest, cf);
|
|
};
|
|
|
|
HttpClient client = HttpClient.newHttpClient();
|
|
HttpRequest request = HttpRequest.newBuilder(uri).GET().build();
|
|
CompletableFuture<HttpResponse<String>> cf =
|
|
client.sendAsync(request, BodyHandlers.ofString(UTF_8), pph);
|
|
cf.join();
|
|
resultMap.put(request, cf);
|
|
System.err.println("results.size: " + resultMap.size());
|
|
for (HttpRequest r : resultMap.keySet()) {
|
|
HttpResponse<String> response = resultMap.get(r).join();
|
|
assertEquals(response.statusCode(), 200);
|
|
assertEquals(response.body(), tempFileAsString);
|
|
}
|
|
assertEquals(resultMap.size(), LOOPS + 1);
|
|
}
|
|
|
|
// Test 2 - of(...) populating the given Map, everything as a String
|
|
@Test
|
|
public void testTypeStringOfMap() throws Exception {
|
|
String tempFileAsString = new String(Files.readAllBytes(tempFile), UTF_8);
|
|
ConcurrentMap<HttpRequest, CompletableFuture<HttpResponse<String>>>
|
|
resultMap = new ConcurrentHashMap<>();
|
|
|
|
PushPromiseHandler<String> pph =
|
|
PushPromiseHandler.of(pushPromise -> BodyHandlers.ofString(UTF_8),
|
|
resultMap);
|
|
|
|
HttpClient client = HttpClient.newHttpClient();
|
|
HttpRequest request = HttpRequest.newBuilder(uri).GET().build();
|
|
CompletableFuture<HttpResponse<String>> cf =
|
|
client.sendAsync(request, BodyHandlers.ofString(UTF_8), pph);
|
|
cf.join();
|
|
resultMap.put(request, cf);
|
|
System.err.println("results.size: " + resultMap.size());
|
|
for (HttpRequest r : resultMap.keySet()) {
|
|
HttpResponse<String> response = resultMap.get(r).join();
|
|
assertEquals(response.statusCode(), 200);
|
|
assertEquals(response.body(), tempFileAsString);
|
|
}
|
|
assertEquals(resultMap.size(), LOOPS + 1);
|
|
}
|
|
|
|
// --- Path ---
|
|
|
|
static final Path dir = Paths.get(".", "serverPush");
|
|
static BodyHandler<Path> requestToPath(HttpRequest req) {
|
|
URI u = req.uri();
|
|
Path path = Paths.get(dir.toString(), u.getPath());
|
|
try {
|
|
Files.createDirectories(path.getParent());
|
|
} catch (IOException ee) {
|
|
throw new UncheckedIOException(ee);
|
|
}
|
|
return BodyHandlers.ofFile(path);
|
|
}
|
|
|
|
// Test 3 - custom written push promise handler, everything as a Path
|
|
@Test
|
|
public void testTypePath() throws Exception {
|
|
String tempFileAsString = new String(Files.readAllBytes(tempFile), UTF_8);
|
|
ConcurrentMap<HttpRequest, CompletableFuture<HttpResponse<Path>>> resultsMap
|
|
= new ConcurrentHashMap<>();
|
|
|
|
PushPromiseHandler<Path> pushPromiseHandler = (initial, pushRequest, acceptor) -> {
|
|
BodyHandler<Path> pp = requestToPath(pushRequest);
|
|
CompletableFuture<HttpResponse<Path>> cf = acceptor.apply(pp);
|
|
resultsMap.put(pushRequest, cf);
|
|
};
|
|
|
|
HttpClient client = HttpClient.newHttpClient();
|
|
HttpRequest request = HttpRequest.newBuilder(uri).GET().build();
|
|
CompletableFuture<HttpResponse<Path>> cf =
|
|
client.sendAsync(request, requestToPath(request), pushPromiseHandler);
|
|
cf.join();
|
|
resultsMap.put(request, cf);
|
|
|
|
for (HttpRequest r : resultsMap.keySet()) {
|
|
HttpResponse<Path> response = resultsMap.get(r).join();
|
|
assertEquals(response.statusCode(), 200);
|
|
String fileAsString = new String(Files.readAllBytes(response.body()), UTF_8);
|
|
assertEquals(fileAsString, tempFileAsString);
|
|
}
|
|
assertEquals(resultsMap.size(), LOOPS + 1);
|
|
}
|
|
|
|
// Test 4 - of(...) populating the given Map, everything as a Path
|
|
@Test
|
|
public void testTypePathOfMap() throws Exception {
|
|
String tempFileAsString = new String(Files.readAllBytes(tempFile), UTF_8);
|
|
ConcurrentMap<HttpRequest, CompletableFuture<HttpResponse<Path>>> resultsMap
|
|
= new ConcurrentHashMap<>();
|
|
|
|
PushPromiseHandler<Path> pushPromiseHandler =
|
|
PushPromiseHandler.of(pushRequest -> requestToPath(pushRequest),
|
|
resultsMap);
|
|
|
|
HttpClient client = HttpClient.newHttpClient();
|
|
HttpRequest request = HttpRequest.newBuilder(uri).GET().build();
|
|
CompletableFuture<HttpResponse<Path>> cf =
|
|
client.sendAsync(request, requestToPath(request), pushPromiseHandler);
|
|
cf.join();
|
|
resultsMap.put(request, cf);
|
|
|
|
for (HttpRequest r : resultsMap.keySet()) {
|
|
HttpResponse<Path> response = resultsMap.get(r).join();
|
|
assertEquals(response.statusCode(), 200);
|
|
String fileAsString = new String(Files.readAllBytes(response.body()), UTF_8);
|
|
assertEquals(fileAsString, tempFileAsString);
|
|
}
|
|
assertEquals(resultsMap.size(), LOOPS + 1);
|
|
}
|
|
|
|
// --- Consumer<byte[]> ---
|
|
|
|
static class ByteArrayConsumer implements Consumer<Optional<byte[]>> {
|
|
volatile List<byte[]> listByteArrays = new ArrayList<>();
|
|
volatile byte[] accumulatedBytes;
|
|
|
|
public byte[] getAccumulatedBytes() { return accumulatedBytes; }
|
|
|
|
@Override
|
|
public void accept(Optional<byte[]> optionalBytes) {
|
|
assert accumulatedBytes == null;
|
|
if (!optionalBytes.isPresent()) {
|
|
int size = listByteArrays.stream().mapToInt(ba -> ba.length).sum();
|
|
ByteBuffer bb = ByteBuffer.allocate(size);
|
|
listByteArrays.stream().forEach(ba -> bb.put(ba));
|
|
accumulatedBytes = bb.array();
|
|
} else {
|
|
listByteArrays.add(optionalBytes.get());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test 5 - custom written handler, everything as a consumer of optional byte[]
|
|
@Test
|
|
public void testTypeByteArrayConsumer() throws Exception {
|
|
String tempFileAsString = new String(Files.readAllBytes(tempFile), UTF_8);
|
|
ConcurrentMap<HttpRequest, CompletableFuture<HttpResponse<Void>>> resultsMap
|
|
= new ConcurrentHashMap<>();
|
|
Map<HttpRequest,ByteArrayConsumer> byteArrayConsumerMap
|
|
= new ConcurrentHashMap<>();
|
|
|
|
HttpClient client = HttpClient.newHttpClient();
|
|
HttpRequest request = HttpRequest.newBuilder(uri).GET().build();
|
|
ByteArrayConsumer bac = new ByteArrayConsumer();
|
|
byteArrayConsumerMap.put(request, bac);
|
|
|
|
PushPromiseHandler<Void> pushPromiseHandler = (initial, pushRequest, acceptor) -> {
|
|
CompletableFuture<HttpResponse<Void>> cf = acceptor.apply(
|
|
(info) -> {
|
|
ByteArrayConsumer bc = new ByteArrayConsumer();
|
|
byteArrayConsumerMap.put(pushRequest, bc);
|
|
return BodySubscribers.ofByteArrayConsumer(bc); } );
|
|
resultsMap.put(pushRequest, cf);
|
|
};
|
|
|
|
CompletableFuture<HttpResponse<Void>> cf =
|
|
client.sendAsync(request, BodyHandlers.ofByteArrayConsumer(bac), pushPromiseHandler);
|
|
cf.join();
|
|
resultsMap.put(request, cf);
|
|
|
|
for (HttpRequest r : resultsMap.keySet()) {
|
|
HttpResponse<Void> response = resultsMap.get(r).join();
|
|
assertEquals(response.statusCode(), 200);
|
|
byte[] ba = byteArrayConsumerMap.get(r).getAccumulatedBytes();
|
|
String result = new String(ba, UTF_8);
|
|
assertEquals(result, tempFileAsString);
|
|
}
|
|
assertEquals(resultsMap.size(), LOOPS + 1);
|
|
}
|
|
|
|
// Test 6 - of(...) populating the given Map, everything as a consumer of optional byte[]
|
|
@Test
|
|
public void testTypeByteArrayConsumerOfMap() throws Exception {
|
|
String tempFileAsString = new String(Files.readAllBytes(tempFile), UTF_8);
|
|
ConcurrentMap<HttpRequest, CompletableFuture<HttpResponse<Void>>> resultsMap
|
|
= new ConcurrentHashMap<>();
|
|
Map<HttpRequest,ByteArrayConsumer> byteArrayConsumerMap
|
|
= new ConcurrentHashMap<>();
|
|
|
|
HttpClient client = HttpClient.newHttpClient();
|
|
HttpRequest request = HttpRequest.newBuilder(uri).GET().build();
|
|
ByteArrayConsumer bac = new ByteArrayConsumer();
|
|
byteArrayConsumerMap.put(request, bac);
|
|
|
|
PushPromiseHandler<Void> pushPromiseHandler =
|
|
PushPromiseHandler.of(
|
|
pushRequest -> {
|
|
ByteArrayConsumer bc = new ByteArrayConsumer();
|
|
byteArrayConsumerMap.put(pushRequest, bc);
|
|
return BodyHandlers.ofByteArrayConsumer(bc);
|
|
},
|
|
resultsMap);
|
|
|
|
CompletableFuture<HttpResponse<Void>> cf =
|
|
client.sendAsync(request, BodyHandlers.ofByteArrayConsumer(bac), pushPromiseHandler);
|
|
cf.join();
|
|
resultsMap.put(request, cf);
|
|
|
|
for (HttpRequest r : resultsMap.keySet()) {
|
|
HttpResponse<Void> response = resultsMap.get(r).join();
|
|
assertEquals(response.statusCode(), 200);
|
|
byte[] ba = byteArrayConsumerMap.get(r).getAccumulatedBytes();
|
|
String result = new String(ba, UTF_8);
|
|
assertEquals(result, tempFileAsString);
|
|
}
|
|
assertEquals(resultsMap.size(), LOOPS + 1);
|
|
}
|
|
}
|