/* * Copyright (c) 2015, 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 * @modules java.net.http * java.logging * jdk.httpserver * @library /test/lib * @build jdk.test.lib.net.SimpleSSLContext * @compile ../../../com/sun/net/httpserver/LogFilter.java * @compile ../../../com/sun/net/httpserver/EchoHandler.java * @compile ../../../com/sun/net/httpserver/FileServerHandler.java * @run main/othervm/timeout=40 ManyRequestsLegacy * @run main/othervm/timeout=40 -Dtest.insertDelay=true ManyRequestsLegacy * @run main/othervm/timeout=40 -Dtest.chunkSize=64 ManyRequestsLegacy * @run main/othervm/timeout=40 -Dtest.insertDelay=true * -Dtest.chunkSize=64 ManyRequestsLegacy * @summary Send a large number of requests asynchronously using the legacy * URL.openConnection(), to help sanitize results of the test * ManyRequest.java.
*/
static String now(long start) { long elapsed = System.nanoTime() - start; long ms = elapsed / 1000_000L; long s = ms / 1000L; if (s == 0) return ms + "ms: "; return s + "s, " + (ms - s * 1000L) + "ms: ";
}
static String failure(Throwable t) {
String s = "\n\t failed: " + t; for (t = t.getCause(); t != null ; t = t.getCause()) {
s = s + "\n\t\t Caused by: " + t;
} return s;
}
staticvoid test(HttpsServer server, LegacyHttpClient client) throws Exception { int port = server.getAddress().getPort();
URI baseURI = new URI("https://localhost:" + port + "/foo/x");
server.createContext("/foo", new TestEchoHandler());
server.start();
// This loop implements a retry mechanism to work around an issue // on some systems (observed on Windows 10) that seem to be trying to // throttle the number of connections that can be made concurrently by // rejecting connection attempts. // On the first iteration of this loop, we will attempt 20 concurrent // requests. If this fails with ConnectException, we will retry the // 20 requests, but limiting the concurrency to 10 (LIMIT <- 10). // If this fails again, the test will fail. boolean done = false;
LOOP: do {
RequestLimiter limiter = new RequestLimiter(LIMIT.get());
Random rand = RANDOM;
CompletableFuture<?>[] results = new CompletableFuture<?>[REQUESTS];
Map<HttpRequest,byte[]> bodies = new ConcurrentHashMap<>(); long start = System.nanoTime();
for (int i = 0; i < REQUESTS; i++) { byte[] buf = newbyte[(i + 1) * CHUNK_SIZE + i + 1]; // different size bodies
rand.nextBytes(buf);
URI uri = new URI(baseURI.toString() + String.valueOf(i + 1));
HttpRequest r = HttpRequest.newBuilder(uri)
.header("XFixed", "true")
.POST(BodyPublishers.ofByteArray(buf))
.build();
bodies.put(r, buf);
results[i] =
limiter.whenOkToSend()
.thenCompose((v) -> {
System.out.println("Client: sendAsync: " + r.uri()); return client.sendAsync(r, buf);
})
.handle((resp, t) -> {
limiter.requestComplete();
CompletionStage<Pair<HttpResponse<byte[]>, byte[]>> res;
String now = now(start); if (t == null) { if (resp.statusCode() != 200) {
String s = "Expected 200, got: " + resp.statusCode();
System.out.println(now + s + " from "
+ resp.request().uri().getPath());
res = completedWithIOException(s); return res;
} else { int counter = COUNT.incrementAndGet();
System.out.println(now + "Result (" + counter + ") from "
+ resp.request().uri().getPath());
}
res = CompletableFuture.completedStage(resp.body())
.thenApply((b) -> new Pair<>(resp, b)); return res;
} else { int counter = COUNT.incrementAndGet();
System.out.println(now + "Result (" + counter + ") from "
+ r.uri().getPath()
+ failure(t));
res = CompletableFuture.failedFuture(t); return res;
}
})
.thenCompose(c -> c)
.thenAccept((pair) -> {
HttpRequest request = pair.t.request(); byte[] requestBody = bodies.get(request);
check(Arrays.equals(requestBody, pair.u), "bodies not equal:[" + bytesToHexString(requestBody)
+ "] [" + bytesToHexString(pair.u) + "]");
});
}
try { // wait for them all to complete and throw exception in case of error
CompletableFuture.allOf(results).join();
done = true;
} catch (CompletionException e) { if (!Platform.isWindows()) throw e; if (LIMIT.get() < REQUESTS) throw e;
Throwable cause = e; while ((cause = cause.getCause()) != null) { if (cause instanceof ConnectException) { // try again, limit concurrency by half
COUNT.set(0);
LIMIT.set(REQUESTS/2);
System.out.println("*** Retrying due to " + cause); continue LOOP;
}
} throw e;
}
} while (!done);
}
static String bytesToHexString(byte[] bytes) { if (bytes == null) return"null";
StringBuilder sb = new StringBuilder(bytes.length * 2);
Formatter formatter = new Formatter(sb); for (byte b : bytes) {
formatter.format("%02x", b);
}
return sb.toString();
}
record Pair<T,U>(T t, U u) { }
/** * A simple limiter for controlling the number of requests to be run in * parallel whenOkToSend() is called which returns a CF<Void> that allows * each individual request to proceed, or block temporarily (blocking occurs * on the waiters list here. As each request actually completes * requestComplete() is called to notify this object, and allow some * requests to continue.
*/ staticclass RequestLimiter {
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.