staticfinal String data[] = { "Lorem ipsum", "dolor sit amet", "consectetur adipiscing elit, sed do eiusmod tempor", "quis nostrud exercitation ullamco", "laboris nisi", "ut", "aliquip ex ea commodo consequat." + "Duis aute irure dolor in reprehenderit in voluptate velit esse" + "cillum dolore eu fugiat nulla pariatur.", "Excepteur sint occaecat cupidatat non proident."
};
staticfinal AtomicLong serverCount = new AtomicLong(); staticfinalclass EchoServers { final DigestEchoServer.HttpAuthType authType; final DigestEchoServer.HttpAuthSchemeType authScheme; final String protocolScheme; final String key; final DigestEchoServer server; final Version serverVersion;
publicstatic List<Boolean> expectContinue(Version serverVersion) { if (serverVersion == Version.HTTP_1_1) { return BOOLEANS;
} else { // our test HTTP/2 server does not support Expect: 100-Continue return List.of(Boolean.FALSE);
}
}
publicstaticvoid main(String[] args) throws Exception {
HttpServerAdapters.enableServerLogging(); boolean useSSL = false;
EnumSet<DigestEchoServer.HttpAuthType> types =
EnumSet.complementOf(EnumSet.of(DigestEchoServer.HttpAuthType.PROXY305));
Throwable failed = null; if (args != null && args.length >= 1) {
useSSL = "SSL".equals(args[0]); if (args.length > 1) {
List<DigestEchoServer.HttpAuthType> httpAuthTypes =
Stream.of(Arrays.copyOfRange(args, 1, args.length))
.map(DigestEchoServer.HttpAuthType::valueOf)
.collect(Collectors.toList());
types = EnumSet.copyOf(httpAuthTypes);
}
} try { for (DigestEchoServer.HttpAuthType authType : types) { // The test server does not support PROXY305 properly if (authType == DigestEchoServer.HttpAuthType.PROXY305) continue;
EnumSet<DigestEchoServer.HttpAuthSchemeType> basics =
EnumSet.of(DigestEchoServer.HttpAuthSchemeType.BASICSERVER,
DigestEchoServer.HttpAuthSchemeType.BASIC); for (DigestEchoServer.HttpAuthSchemeType authScheme : basics) {
DigestEchoClient dec = new DigestEchoClient(useSSL,
authScheme,
authType); for (Version clientVersion : clientVersions()) { for (Version serverVersion : serverVersions(clientVersion)) { for (boolean expectContinue : expectContinue(serverVersion)) { for (boolean async : BOOLEANS) { for (boolean preemptive : BOOLEANS) {
dec.testBasic(clientVersion,
serverVersion, async,
expectContinue, preemptive);
}
}
}
}
}
}
EnumSet<DigestEchoServer.HttpAuthSchemeType> digests =
EnumSet.of(DigestEchoServer.HttpAuthSchemeType.DIGEST); for (DigestEchoServer.HttpAuthSchemeType authScheme : digests) {
DigestEchoClient dec = new DigestEchoClient(useSSL,
authScheme,
authType); for (Version clientVersion : clientVersions()) { for (Version serverVersion : serverVersions(clientVersion)) { for (boolean expectContinue : expectContinue(serverVersion)) { for (boolean async : BOOLEANS) {
dec.testDigest(clientVersion, serverVersion,
async, expectContinue);
}
}
}
}
}
}
} catch(Throwable t) {
out.println(DigestEchoServer.now()
+ ": Unexpected exception: " + t);
t.printStackTrace();
failed = t; throw t;
} finally { Thread.sleep(100);
AssertionError trackFailed = TRACKER.check(500);
EchoServers.stop();
System.out.println(" ---------------------------------------------------------- ");
System.out.println(String.format("DigestEchoClient %s %s", useSSL ? "SSL" : "CLEAR", types));
System.out.println(String.format("Created %d clients and %d servers",
clientCount.get(), serverCount.get()));
System.out.println(String.format("basics: %d requests sent, %d ns / req",
basicCount.get(), basics.get()));
System.out.println(String.format("digests: %d requests sent, %d ns / req",
digestCount.get(), digests.get()));
System.out.println(" ---------------------------------------------------------- "); if (trackFailed != null) { if (failed != null) {
failed.addSuppressed(trackFailed); if (failed instanceof Error) throw (Error) failed; if (failed instanceof Exception) throw (Exception) failed;
} throw trackFailed;
}
}
}
// In case of a tunnel connection only the first request // which establishes the tunnel needs to authenticate with // the proxy. if (challenge != null && (!isTunnel || isSchemeDisabled())) { assert cnonceStr != null;
String auth = digestResponse(uri, digestMethod, challenge, cnonceStr); try {
reqBuilder = reqBuilder.header(authorizationKey(authType), auth);
} catch (IllegalArgumentException x) { throw x;
}
}
long start = System.nanoTime();
HttpRequest request = reqBuilder.build();
HttpResponse<Stream<String>> resp; if (async) {
resp = client.sendAsync(request, BodyHandlers.ofLines()).join();
} else {
resp = client.send(request, BodyHandlers.ofLines());
}
System.out.println(resp); assert challenge != null || resp.statusCode() == 401 || resp.statusCode() == 407
: "challenge=" + challenge + ", resp=" + resp + ", test=[" + test + "]"; if (resp.statusCode() == 401 || resp.statusCode() == 407) { // This assert may need to be relaxed if our server happened to // decide to close the tunnel connection, in which case we would // receive 407 again... assert challenge == null || !isTunnel || isSchemeDisabled()
: "No proxy auth should be required after establishing an SSL tunnel";
if (async) {
resp = client.sendAsync(request, BodyHandlers.ofLines()).join();
} else {
resp = client.send(request, BodyHandlers.ofLines());
}
System.out.println(resp);
} final List<String> respLines; try { if (isSchemeDisabled()) { if (resp.statusCode() != 407) { thrownew RuntimeException("expected 407 not received");
}
System.out.println("Scheme disabled for [" + authType
+ ", " + authScheme + ", " + (useSSL ? "HTTP" : "HTTPS")
+ "]: Received expected " + resp.statusCode()); continue;
} else { assert resp.statusCode() == 200;
respLines = resp.body().collect(Collectors.toList());
}
} finally { long stop = System.nanoTime(); synchronized (digestCount) { long n = digestCount.getAndIncrement();
digests.set((digests.get() * n + (stop - start)) / (n + 1));
}
} if (!lines.equals(respLines)) { thrownew RuntimeException("Unexpected response: " + respLines);
}
}
} finally {
}
System.out.println("OK");
}
// WARNING: This is not a full fledged implementation of DIGEST. // It does contain bugs and inaccuracy. static String digestResponse(URI uri, String method, DigestEchoServer.DigestResponse challenge, String cnonce) throws NoSuchAlgorithmException { int nc = NC.incrementAndGet();
DigestEchoServer.DigestResponse response1 = new DigestEchoServer.DigestResponse("earth", "arthur", challenge.nonce, cnonce, String.valueOf(nc), uri.toASCIIString(),
challenge.algorithm, challenge.qop, challenge.opaque, null);
String response = DigestEchoServer.DigestResponse.computeDigest(true, method,
DigestEchoServer.AUTHENTICATOR.getPassword("arthur"), response1);
String auth = "Digest username=\"arthur\", realm=\"earth\""
+ ", response=\"" + response + "\", uri=\""+uri.toASCIIString()+"\""
+ ", qop=\"" + response1.qop + "\", cnonce=\"" + response1.cnonce
+ "\", nc=\"" + nc + "\", nonce=\"" + response1.nonce + "\""; if (response1.opaque != null) {
auth = auth + ", opaque=\"" + response1.opaque + "\"";
} return auth;
}
static String authenticateKey(DigestEchoServer.HttpAuthType authType) { switch (authType) { case SERVER: return"www-authenticate"; case SERVER307: return"www-authenticate"; case PROXY: return"proxy-authenticate"; case PROXY305: return"proxy-authenticate"; default: thrownew InternalError("authType: " + authType);
}
}
static String authorizationKey(DigestEchoServer.HttpAuthType authType) { switch (authType) { case SERVER: return"authorization"; case SERVER307: return"Authorization"; case PROXY: return"Proxy-Authorization"; case PROXY305: return"proxy-Authorization"; default: thrownew InternalError("authType: " + authType);
}
}
staticboolean isProxy(DigestEchoServer.HttpAuthType authType) { switch (authType) { case SERVER: returnfalse; case SERVER307: returnfalse; case PROXY: returntrue; case PROXY305: returntrue; default: thrownew InternalError("authType: " + authType);
}
}
}
Messung V0.5 in Prozent
¤ 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.0.21Bemerkung:
(vorverarbeitet am 2026-06-10)
¤
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 und die Messung sind noch experimentell.