Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/net/httpclient/DigestEchoClient.java
41152 views
1
/*
2
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
import java.io.IOException;
25
import java.io.UncheckedIOException;
26
import java.math.BigInteger;
27
import java.net.ProxySelector;
28
import java.net.URI;
29
import java.net.http.HttpClient;
30
import java.net.http.HttpClient.Version;
31
import java.net.http.HttpRequest;
32
import java.net.http.HttpRequest.BodyPublisher;
33
import java.net.http.HttpRequest.BodyPublishers;
34
import java.net.http.HttpResponse;
35
import java.net.http.HttpResponse.BodyHandler;
36
import java.net.http.HttpResponse.BodyHandlers;
37
import java.nio.charset.StandardCharsets;
38
import java.security.NoSuchAlgorithmException;
39
import java.util.Arrays;
40
import java.util.Base64;
41
import java.util.EnumSet;
42
import java.util.List;
43
import java.util.Optional;
44
import java.util.Random;
45
import java.util.concurrent.CompletableFuture;
46
import java.util.concurrent.CompletionException;
47
import java.util.concurrent.ConcurrentHashMap;
48
import java.util.concurrent.ConcurrentMap;
49
import java.util.concurrent.atomic.AtomicInteger;
50
import java.util.concurrent.atomic.AtomicLong;
51
import java.util.stream.Collectors;
52
import java.util.stream.Stream;
53
import javax.net.ssl.SSLContext;
54
import jdk.test.lib.net.SimpleSSLContext;
55
import sun.net.NetProperties;
56
import sun.net.www.HeaderParser;
57
import static java.lang.System.out;
58
import static java.lang.String.format;
59
60
/**
61
* @test
62
* @summary this test verifies that a client may provides authorization
63
* headers directly when connecting with a server.
64
* @bug 8087112
65
* @library /test/lib http2/server
66
* @build jdk.test.lib.net.SimpleSSLContext HttpServerAdapters DigestEchoServer
67
* ReferenceTracker DigestEchoClient
68
* @modules java.net.http/jdk.internal.net.http.common
69
* java.net.http/jdk.internal.net.http.frame
70
* java.net.http/jdk.internal.net.http.hpack
71
* java.logging
72
* java.base/sun.net.www.http
73
* java.base/sun.net.www
74
* java.base/sun.net
75
* @run main/othervm DigestEchoClient
76
* @run main/othervm -Djdk.http.auth.proxying.disabledSchemes=
77
* -Djdk.http.auth.tunneling.disabledSchemes=
78
* DigestEchoClient
79
*/
80
81
public class DigestEchoClient {
82
83
static final String data[] = {
84
"Lorem ipsum",
85
"dolor sit amet",
86
"consectetur adipiscing elit, sed do eiusmod tempor",
87
"quis nostrud exercitation ullamco",
88
"laboris nisi",
89
"ut",
90
"aliquip ex ea commodo consequat." +
91
"Duis aute irure dolor in reprehenderit in voluptate velit esse" +
92
"cillum dolore eu fugiat nulla pariatur.",
93
"Excepteur sint occaecat cupidatat non proident."
94
};
95
96
static final AtomicLong serverCount = new AtomicLong();
97
static final class EchoServers {
98
final DigestEchoServer.HttpAuthType authType;
99
final DigestEchoServer.HttpAuthSchemeType authScheme;
100
final String protocolScheme;
101
final String key;
102
final DigestEchoServer server;
103
final Version serverVersion;
104
105
private EchoServers(DigestEchoServer server,
106
Version version,
107
String protocolScheme,
108
DigestEchoServer.HttpAuthType authType,
109
DigestEchoServer.HttpAuthSchemeType authScheme) {
110
this.authType = authType;
111
this.authScheme = authScheme;
112
this.protocolScheme = protocolScheme;
113
this.key = key(version, protocolScheme, authType, authScheme);
114
this.server = server;
115
this.serverVersion = version;
116
}
117
118
static String key(Version version,
119
String protocolScheme,
120
DigestEchoServer.HttpAuthType authType,
121
DigestEchoServer.HttpAuthSchemeType authScheme) {
122
return String.format("%s:%s:%s:%s", version, protocolScheme, authType, authScheme);
123
}
124
125
private static EchoServers create(Version version,
126
String protocolScheme,
127
DigestEchoServer.HttpAuthType authType,
128
DigestEchoServer.HttpAuthSchemeType authScheme) {
129
try {
130
serverCount.incrementAndGet();
131
DigestEchoServer server =
132
DigestEchoServer.create(version, protocolScheme, authType, authScheme);
133
return new EchoServers(server, version, protocolScheme, authType, authScheme);
134
} catch (IOException x) {
135
throw new UncheckedIOException(x);
136
}
137
}
138
139
public static DigestEchoServer of(Version version,
140
String protocolScheme,
141
DigestEchoServer.HttpAuthType authType,
142
DigestEchoServer.HttpAuthSchemeType authScheme) {
143
String key = key(version, protocolScheme, authType, authScheme);
144
return servers.computeIfAbsent(key, (k) ->
145
create(version, protocolScheme, authType, authScheme)).server;
146
}
147
148
public static void stop() {
149
for (EchoServers s : servers.values()) {
150
s.server.stop();
151
}
152
}
153
154
private static final ConcurrentMap<String, EchoServers> servers = new ConcurrentHashMap<>();
155
}
156
157
final static String PROXY_DISABLED = NetProperties.get("jdk.http.auth.proxying.disabledSchemes");
158
final static String TUNNEL_DISABLED = NetProperties.get("jdk.http.auth.tunneling.disabledSchemes");
159
static {
160
System.out.println("jdk.http.auth.proxying.disabledSchemes=" + PROXY_DISABLED);
161
System.out.println("jdk.http.auth.tunneling.disabledSchemes=" + TUNNEL_DISABLED);
162
}
163
164
165
166
static final AtomicInteger NC = new AtomicInteger();
167
static final Random random = new Random();
168
static final SSLContext context;
169
static {
170
try {
171
context = new SimpleSSLContext().get();
172
SSLContext.setDefault(context);
173
} catch (Exception x) {
174
throw new ExceptionInInitializerError(x);
175
}
176
}
177
static final List<Boolean> BOOLEANS = List.of(true, false);
178
179
final boolean useSSL;
180
final DigestEchoServer.HttpAuthSchemeType authScheme;
181
final DigestEchoServer.HttpAuthType authType;
182
DigestEchoClient(boolean useSSL,
183
DigestEchoServer.HttpAuthSchemeType authScheme,
184
DigestEchoServer.HttpAuthType authType)
185
throws IOException {
186
this.useSSL = useSSL;
187
this.authScheme = authScheme;
188
this.authType = authType;
189
}
190
191
static final AtomicLong clientCount = new AtomicLong();
192
static final ReferenceTracker TRACKER = ReferenceTracker.INSTANCE;
193
public HttpClient newHttpClient(DigestEchoServer server) {
194
clientCount.incrementAndGet();
195
HttpClient.Builder builder = HttpClient.newBuilder();
196
builder = builder.proxy(ProxySelector.of(null));
197
if (useSSL) {
198
builder.sslContext(context);
199
}
200
switch (authScheme) {
201
case BASIC:
202
builder = builder.authenticator(DigestEchoServer.AUTHENTICATOR);
203
break;
204
case BASICSERVER:
205
// don't set the authenticator: we will handle the header ourselves.
206
// builder = builder.authenticator(DigestEchoServer.AUTHENTICATOR);
207
break;
208
default:
209
break;
210
}
211
switch (authType) {
212
case PROXY:
213
builder = builder.proxy(ProxySelector.of(server.getProxyAddress()));
214
break;
215
case PROXY305:
216
builder = builder.proxy(ProxySelector.of(server.getProxyAddress()));
217
builder = builder.followRedirects(HttpClient.Redirect.NORMAL);
218
break;
219
case SERVER307:
220
builder = builder.followRedirects(HttpClient.Redirect.NORMAL);
221
break;
222
default:
223
break;
224
}
225
return TRACKER.track(builder.build());
226
}
227
228
public static List<Version> serverVersions(Version clientVersion) {
229
if (clientVersion == Version.HTTP_1_1) {
230
return List.of(clientVersion);
231
} else {
232
return List.of(Version.values());
233
}
234
}
235
236
public static List<Version> clientVersions() {
237
return List.of(Version.values());
238
}
239
240
public static List<Boolean> expectContinue(Version serverVersion) {
241
if (serverVersion == Version.HTTP_1_1) {
242
return BOOLEANS;
243
} else {
244
// our test HTTP/2 server does not support Expect: 100-Continue
245
return List.of(Boolean.FALSE);
246
}
247
}
248
249
public static void main(String[] args) throws Exception {
250
HttpServerAdapters.enableServerLogging();
251
boolean useSSL = false;
252
EnumSet<DigestEchoServer.HttpAuthType> types =
253
EnumSet.complementOf(EnumSet.of(DigestEchoServer.HttpAuthType.PROXY305));
254
Throwable failed = null;
255
if (args != null && args.length >= 1) {
256
useSSL = "SSL".equals(args[0]);
257
if (args.length > 1) {
258
List<DigestEchoServer.HttpAuthType> httpAuthTypes =
259
Stream.of(Arrays.copyOfRange(args, 1, args.length))
260
.map(DigestEchoServer.HttpAuthType::valueOf)
261
.collect(Collectors.toList());
262
types = EnumSet.copyOf(httpAuthTypes);
263
}
264
}
265
try {
266
for (DigestEchoServer.HttpAuthType authType : types) {
267
// The test server does not support PROXY305 properly
268
if (authType == DigestEchoServer.HttpAuthType.PROXY305) continue;
269
EnumSet<DigestEchoServer.HttpAuthSchemeType> basics =
270
EnumSet.of(DigestEchoServer.HttpAuthSchemeType.BASICSERVER,
271
DigestEchoServer.HttpAuthSchemeType.BASIC);
272
for (DigestEchoServer.HttpAuthSchemeType authScheme : basics) {
273
DigestEchoClient dec = new DigestEchoClient(useSSL,
274
authScheme,
275
authType);
276
for (Version clientVersion : clientVersions()) {
277
for (Version serverVersion : serverVersions(clientVersion)) {
278
for (boolean expectContinue : expectContinue(serverVersion)) {
279
for (boolean async : BOOLEANS) {
280
for (boolean preemptive : BOOLEANS) {
281
dec.testBasic(clientVersion,
282
serverVersion, async,
283
expectContinue, preemptive);
284
}
285
}
286
}
287
}
288
}
289
}
290
EnumSet<DigestEchoServer.HttpAuthSchemeType> digests =
291
EnumSet.of(DigestEchoServer.HttpAuthSchemeType.DIGEST);
292
for (DigestEchoServer.HttpAuthSchemeType authScheme : digests) {
293
DigestEchoClient dec = new DigestEchoClient(useSSL,
294
authScheme,
295
authType);
296
for (Version clientVersion : clientVersions()) {
297
for (Version serverVersion : serverVersions(clientVersion)) {
298
for (boolean expectContinue : expectContinue(serverVersion)) {
299
for (boolean async : BOOLEANS) {
300
dec.testDigest(clientVersion, serverVersion,
301
async, expectContinue);
302
}
303
}
304
}
305
}
306
}
307
}
308
} catch(Throwable t) {
309
out.println(DigestEchoServer.now()
310
+ ": Unexpected exception: " + t);
311
t.printStackTrace();
312
failed = t;
313
throw t;
314
} finally {
315
Thread.sleep(100);
316
AssertionError trackFailed = TRACKER.check(500);
317
EchoServers.stop();
318
System.out.println(" ---------------------------------------------------------- ");
319
System.out.println(String.format("DigestEchoClient %s %s", useSSL ? "SSL" : "CLEAR", types));
320
System.out.println(String.format("Created %d clients and %d servers",
321
clientCount.get(), serverCount.get()));
322
System.out.println(String.format("basics: %d requests sent, %d ns / req",
323
basicCount.get(), basics.get()));
324
System.out.println(String.format("digests: %d requests sent, %d ns / req",
325
digestCount.get(), digests.get()));
326
System.out.println(" ---------------------------------------------------------- ");
327
if (trackFailed != null) {
328
if (failed != null) {
329
failed.addSuppressed(trackFailed);
330
if (failed instanceof Error) throw (Error) failed;
331
if (failed instanceof Exception) throw (Exception) failed;
332
}
333
throw trackFailed;
334
}
335
}
336
}
337
338
boolean isSchemeDisabled() {
339
String disabledSchemes;
340
if (isProxy(authType)) {
341
disabledSchemes = useSSL
342
? TUNNEL_DISABLED
343
: PROXY_DISABLED;
344
} else return false;
345
if (disabledSchemes == null
346
|| disabledSchemes.isEmpty()) {
347
return false;
348
}
349
String scheme;
350
switch (authScheme) {
351
case DIGEST:
352
scheme = "Digest";
353
break;
354
case BASIC:
355
scheme = "Basic";
356
break;
357
case BASICSERVER:
358
scheme = "Basic";
359
break;
360
case NONE:
361
return false;
362
default:
363
throw new InternalError("Unknown auth scheme: " + authScheme);
364
}
365
return Stream.of(disabledSchemes.split(","))
366
.map(String::trim)
367
.filter(scheme::equalsIgnoreCase)
368
.findAny()
369
.isPresent();
370
}
371
372
final static AtomicLong basics = new AtomicLong();
373
final static AtomicLong basicCount = new AtomicLong();
374
// @Test
375
void testBasic(Version clientVersion, Version serverVersion, boolean async,
376
boolean expectContinue, boolean preemptive)
377
throws Exception
378
{
379
final boolean addHeaders = authScheme == DigestEchoServer.HttpAuthSchemeType.BASICSERVER;
380
// !preemptive has no meaning if we don't handle the authorization
381
// headers ourselves
382
if (!preemptive && !addHeaders) return;
383
384
out.println(format("*** testBasic: client: %s, server: %s, async: %s, useSSL: %s, " +
385
"authScheme: %s, authType: %s, expectContinue: %s preemptive: %s***",
386
clientVersion, serverVersion, async, useSSL, authScheme, authType,
387
expectContinue, preemptive));
388
389
DigestEchoServer server = EchoServers.of(serverVersion,
390
useSSL ? "https" : "http", authType, authScheme);
391
URI uri = DigestEchoServer.uri(useSSL ? "https" : "http",
392
server.getServerAddress(), "/foo/");
393
394
HttpClient client = newHttpClient(server);
395
HttpResponse<String> r;
396
CompletableFuture<HttpResponse<String>> cf1;
397
String auth = null;
398
399
try {
400
for (int i=0; i<data.length; i++) {
401
out.println(DigestEchoServer.now() + " ----- iteration " + i + " -----");
402
List<String> lines = List.of(Arrays.copyOfRange(data, 0, i+1));
403
assert lines.size() == i + 1;
404
String body = lines.stream().collect(Collectors.joining("\r\n"));
405
BodyPublisher reqBody = BodyPublishers.ofString(body);
406
HttpRequest.Builder builder = HttpRequest.newBuilder(uri).version(clientVersion)
407
.POST(reqBody).expectContinue(expectContinue);
408
boolean isTunnel = isProxy(authType) && useSSL;
409
if (addHeaders) {
410
// handle authentication ourselves
411
assert !client.authenticator().isPresent();
412
if (auth == null) auth = "Basic " + getBasicAuth("arthur");
413
try {
414
if ((i > 0 || preemptive)
415
&& (!isTunnel || i == 0 || isSchemeDisabled())) {
416
// In case of a SSL tunnel through proxy then only the
417
// first request should require proxy authorization
418
// Though this might be invalidated if the server decides
419
// to close the connection...
420
out.println(String.format("%s adding %s: %s",
421
DigestEchoServer.now(),
422
authorizationKey(authType),
423
auth));
424
builder = builder.header(authorizationKey(authType), auth);
425
}
426
} catch (IllegalArgumentException x) {
427
throw x;
428
}
429
} else {
430
// let the stack do the authentication
431
assert client.authenticator().isPresent();
432
}
433
long start = System.nanoTime();
434
HttpRequest request = builder.build();
435
HttpResponse<Stream<String>> resp;
436
try {
437
if (async) {
438
resp = client.sendAsync(request, BodyHandlers.ofLines()).join();
439
} else {
440
resp = client.send(request, BodyHandlers.ofLines());
441
}
442
} catch (Throwable t) {
443
long stop = System.nanoTime();
444
synchronized (basicCount) {
445
long n = basicCount.getAndIncrement();
446
basics.set((basics.get() * n + (stop - start)) / (n + 1));
447
}
448
// unwrap CompletionException
449
if (t instanceof CompletionException) {
450
assert t.getCause() != null;
451
t = t.getCause();
452
}
453
out.println(DigestEchoServer.now()
454
+ ": Unexpected exception: " + t);
455
throw new RuntimeException("Unexpected exception: " + t, t);
456
}
457
458
if (addHeaders && !preemptive && (i==0 || isSchemeDisabled())) {
459
assert resp.statusCode() == 401 || resp.statusCode() == 407;
460
Stream<String> respBody = resp.body();
461
if (respBody != null) {
462
System.out.printf("Response body (%s):\n", resp.statusCode());
463
respBody.forEach(System.out::println);
464
}
465
System.out.println(String.format("%s received: adding header %s: %s",
466
resp.statusCode(), authorizationKey(authType), auth));
467
request = HttpRequest.newBuilder(uri).version(clientVersion)
468
.POST(reqBody).header(authorizationKey(authType), auth).build();
469
if (async) {
470
resp = client.sendAsync(request, BodyHandlers.ofLines()).join();
471
} else {
472
resp = client.send(request, BodyHandlers.ofLines());
473
}
474
}
475
final List<String> respLines;
476
try {
477
if (isSchemeDisabled()) {
478
if (resp.statusCode() != 407) {
479
throw new RuntimeException("expected 407 not received");
480
}
481
System.out.println("Scheme disabled for [" + authType
482
+ ", " + authScheme
483
+ ", " + (useSSL ? "HTTP" : "HTTPS")
484
+ "]: Received expected " + resp.statusCode());
485
continue;
486
} else {
487
System.out.println("Scheme enabled for [" + authType
488
+ ", " + authScheme
489
+ ", " + (useSSL ? "HTTPS" : "HTTP")
490
+ "]: Expecting 200, response is: " + resp);
491
assert resp.statusCode() == 200 : "200 expected, received " + resp;
492
respLines = resp.body().collect(Collectors.toList());
493
}
494
} finally {
495
long stop = System.nanoTime();
496
synchronized (basicCount) {
497
long n = basicCount.getAndIncrement();
498
basics.set((basics.get() * n + (stop - start)) / (n + 1));
499
}
500
}
501
if (!lines.equals(respLines)) {
502
throw new RuntimeException("Unexpected response: " + respLines);
503
}
504
}
505
} finally {
506
}
507
System.out.println("OK");
508
}
509
510
String getBasicAuth(String username) {
511
StringBuilder builder = new StringBuilder(username);
512
builder.append(':');
513
for (char c : DigestEchoServer.AUTHENTICATOR.getPassword(username)) {
514
builder.append(c);
515
}
516
return Base64.getEncoder().encodeToString(builder.toString().getBytes(StandardCharsets.UTF_8));
517
}
518
519
final static AtomicLong digests = new AtomicLong();
520
final static AtomicLong digestCount = new AtomicLong();
521
// @Test
522
void testDigest(Version clientVersion, Version serverVersion,
523
boolean async, boolean expectContinue)
524
throws Exception
525
{
526
String test = format("testDigest: client: %s, server: %s, async: %s, useSSL: %s, " +
527
"authScheme: %s, authType: %s, expectContinue: %s",
528
clientVersion, serverVersion, async, useSSL,
529
authScheme, authType, expectContinue);
530
out.println("*** " + test + " ***");
531
DigestEchoServer server = EchoServers.of(serverVersion,
532
useSSL ? "https" : "http", authType, authScheme);
533
534
URI uri = DigestEchoServer.uri(useSSL ? "https" : "http",
535
server.getServerAddress(), "/foo/");
536
537
HttpClient client = newHttpClient(server);
538
HttpResponse<String> r;
539
CompletableFuture<HttpResponse<String>> cf1;
540
byte[] cnonce = new byte[16];
541
String cnonceStr = null;
542
DigestEchoServer.DigestResponse challenge = null;
543
544
try {
545
for (int i=0; i<data.length; i++) {
546
out.println(DigestEchoServer.now() + "----- iteration " + i + " -----");
547
List<String> lines = List.of(Arrays.copyOfRange(data, 0, i+1));
548
assert lines.size() == i + 1;
549
String body = lines.stream().collect(Collectors.joining("\r\n"));
550
HttpRequest.BodyPublisher reqBody = HttpRequest.BodyPublishers.ofString(body);
551
HttpRequest.Builder reqBuilder = HttpRequest
552
.newBuilder(uri).version(clientVersion).POST(reqBody)
553
.expectContinue(expectContinue);
554
555
boolean isTunnel = isProxy(authType) && useSSL;
556
String digestMethod = isTunnel ? "CONNECT" : "POST";
557
558
// In case of a tunnel connection only the first request
559
// which establishes the tunnel needs to authenticate with
560
// the proxy.
561
if (challenge != null && (!isTunnel || isSchemeDisabled())) {
562
assert cnonceStr != null;
563
String auth = digestResponse(uri, digestMethod, challenge, cnonceStr);
564
try {
565
reqBuilder = reqBuilder.header(authorizationKey(authType), auth);
566
} catch (IllegalArgumentException x) {
567
throw x;
568
}
569
}
570
571
long start = System.nanoTime();
572
HttpRequest request = reqBuilder.build();
573
HttpResponse<Stream<String>> resp;
574
if (async) {
575
resp = client.sendAsync(request, BodyHandlers.ofLines()).join();
576
} else {
577
resp = client.send(request, BodyHandlers.ofLines());
578
}
579
System.out.println(resp);
580
assert challenge != null || resp.statusCode() == 401 || resp.statusCode() == 407
581
: "challenge=" + challenge + ", resp=" + resp + ", test=[" + test + "]";
582
if (resp.statusCode() == 401 || resp.statusCode() == 407) {
583
// This assert may need to be relaxed if our server happened to
584
// decide to close the tunnel connection, in which case we would
585
// receive 407 again...
586
assert challenge == null || !isTunnel || isSchemeDisabled()
587
: "No proxy auth should be required after establishing an SSL tunnel";
588
589
System.out.println("Received " + resp.statusCode() + " answering challenge...");
590
random.nextBytes(cnonce);
591
cnonceStr = new BigInteger(1, cnonce).toString(16);
592
System.out.println("Response headers: " + resp.headers());
593
Optional<String> authenticateOpt = resp.headers().firstValue(authenticateKey(authType));
594
String authenticate = authenticateOpt.orElseThrow(
595
() -> new RuntimeException(authenticateKey(authType) + ": not found"));
596
assert authenticate.startsWith("Digest ");
597
HeaderParser hp = new HeaderParser(authenticate.substring("Digest ".length()));
598
String qop = hp.findValue("qop");
599
String nonce = hp.findValue("nonce");
600
if (qop == null && nonce == null) {
601
throw new RuntimeException("QOP and NONCE not found");
602
}
603
challenge = DigestEchoServer.DigestResponse
604
.create(authenticate.substring("Digest ".length()));
605
String auth = digestResponse(uri, digestMethod, challenge, cnonceStr);
606
try {
607
request = HttpRequest.newBuilder(uri).version(clientVersion)
608
.POST(reqBody).header(authorizationKey(authType), auth).build();
609
} catch (IllegalArgumentException x) {
610
throw x;
611
}
612
613
if (async) {
614
resp = client.sendAsync(request, BodyHandlers.ofLines()).join();
615
} else {
616
resp = client.send(request, BodyHandlers.ofLines());
617
}
618
System.out.println(resp);
619
}
620
final List<String> respLines;
621
try {
622
if (isSchemeDisabled()) {
623
if (resp.statusCode() != 407) {
624
throw new RuntimeException("expected 407 not received");
625
}
626
System.out.println("Scheme disabled for [" + authType
627
+ ", " + authScheme +
628
", " + (useSSL ? "HTTP" : "HTTPS")
629
+ "]: Received expected " + resp.statusCode());
630
continue;
631
} else {
632
assert resp.statusCode() == 200;
633
respLines = resp.body().collect(Collectors.toList());
634
}
635
} finally {
636
long stop = System.nanoTime();
637
synchronized (digestCount) {
638
long n = digestCount.getAndIncrement();
639
digests.set((digests.get() * n + (stop - start)) / (n + 1));
640
}
641
}
642
if (!lines.equals(respLines)) {
643
throw new RuntimeException("Unexpected response: " + respLines);
644
}
645
}
646
} finally {
647
}
648
System.out.println("OK");
649
}
650
651
// WARNING: This is not a full fledged implementation of DIGEST.
652
// It does contain bugs and inaccuracy.
653
static String digestResponse(URI uri, String method, DigestEchoServer.DigestResponse challenge, String cnonce)
654
throws NoSuchAlgorithmException {
655
int nc = NC.incrementAndGet();
656
DigestEchoServer.DigestResponse response1 = new DigestEchoServer.DigestResponse("earth",
657
"arthur", challenge.nonce, cnonce, String.valueOf(nc), uri.toASCIIString(),
658
challenge.algorithm, challenge.qop, challenge.opaque, null);
659
String response = DigestEchoServer.DigestResponse.computeDigest(true, method,
660
DigestEchoServer.AUTHENTICATOR.getPassword("arthur"), response1);
661
String auth = "Digest username=\"arthur\", realm=\"earth\""
662
+ ", response=\"" + response + "\", uri=\""+uri.toASCIIString()+"\""
663
+ ", qop=\"" + response1.qop + "\", cnonce=\"" + response1.cnonce
664
+ "\", nc=\"" + nc + "\", nonce=\"" + response1.nonce + "\"";
665
if (response1.opaque != null) {
666
auth = auth + ", opaque=\"" + response1.opaque + "\"";
667
}
668
return auth;
669
}
670
671
static String authenticateKey(DigestEchoServer.HttpAuthType authType) {
672
switch (authType) {
673
case SERVER: return "www-authenticate";
674
case SERVER307: return "www-authenticate";
675
case PROXY: return "proxy-authenticate";
676
case PROXY305: return "proxy-authenticate";
677
default: throw new InternalError("authType: " + authType);
678
}
679
}
680
681
static String authorizationKey(DigestEchoServer.HttpAuthType authType) {
682
switch (authType) {
683
case SERVER: return "authorization";
684
case SERVER307: return "Authorization";
685
case PROXY: return "Proxy-Authorization";
686
case PROXY305: return "proxy-Authorization";
687
default: throw new InternalError("authType: " + authType);
688
}
689
}
690
691
static boolean isProxy(DigestEchoServer.HttpAuthType authType) {
692
switch (authType) {
693
case SERVER: return false;
694
case SERVER307: return false;
695
case PROXY: return true;
696
case PROXY305: return true;
697
default: throw new InternalError("authType: " + authType);
698
}
699
}
700
}
701
702