1 /* 2 * Copyright (c) 2015, 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 /* 25 * @test 26 * @bug 8087112 8178699 27 * @modules java.net.http 28 * java.logging 29 * jdk.httpserver 30 * @library /lib/testlibrary/ / 31 * @build jdk.testlibrary.SimpleSSLContext ProxyServer 32 * @compile ../../../com/sun/net/httpserver/LogFilter.java 33 * @compile ../../../com/sun/net/httpserver/EchoHandler.java 34 * @compile ../../../com/sun/net/httpserver/FileServerHandler.java 35 * @run main/othervm 36 * -Djdk.internal.httpclient.debug=true 37 * -Djdk.httpclient.HttpClient.log=errors,ssl,trace 38 * SmokeTest 39 */ 40 41 import com.sun.net.httpserver.Headers; 42 import com.sun.net.httpserver.HttpContext; 43 import com.sun.net.httpserver.HttpExchange; 44 import com.sun.net.httpserver.HttpHandler; 45 import com.sun.net.httpserver.HttpServer; 46 import com.sun.net.httpserver.HttpsConfigurator; 47 import com.sun.net.httpserver.HttpsParameters; 48 import com.sun.net.httpserver.HttpsServer; 49 50 import java.net.InetAddress; 51 import java.net.Proxy; 52 import java.net.SocketAddress; 53 import java.util.Collections; 54 import java.util.Set; 55 import java.util.concurrent.atomic.AtomicInteger; 56 import java.net.InetSocketAddress; 57 import java.net.PasswordAuthentication; 58 import java.net.ProxySelector; 59 import java.net.URI; 60 import java.net.http.HttpClient; 61 import java.net.http.HttpRequest; 62 import java.net.http.HttpRequest.BodyPublishers; 63 import java.net.http.HttpResponse; 64 import java.net.http.HttpResponse.BodyHandlers; 65 import java.io.File; 66 import java.io.FileInputStream; 67 import java.io.FileOutputStream; 68 import java.io.FileNotFoundException; 69 import java.io.IOException; 70 import java.io.BufferedInputStream; 71 import java.io.InputStream; 72 import java.io.OutputStream; 73 import java.io.UncheckedIOException; 74 import java.util.concurrent.BlockingQueue; 75 import java.util.concurrent.CompletableFuture; 76 import java.util.concurrent.CompletionException; 77 import java.util.concurrent.CyclicBarrier; 78 import java.util.concurrent.Executors; 79 import java.util.concurrent.ExecutorService; 80 import java.util.concurrent.LinkedBlockingQueue; 81 import java.util.concurrent.TimeUnit; 82 import javax.net.ssl.SSLContext; 83 import javax.net.ssl.SSLParameters; 84 import java.nio.file.Files; 85 import java.nio.file.Path; 86 import java.nio.file.Paths; 87 import java.util.HashSet; 88 import java.util.LinkedList; 89 import java.util.List; 90 import java.util.Random; 91 import jdk.testlibrary.SimpleSSLContext; 92 import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; 93 import static java.nio.file.StandardOpenOption.WRITE; 94 95 import java.util.concurrent.CountDownLatch; 96 import java.util.logging.ConsoleHandler; 97 import java.util.logging.Level; 98 import java.util.logging.Logger; 99 100 /** 101 * * Basic smoke test for Http/1.1 client 102 * - basic request response 103 * - request body POST 104 * - response body GET 105 * - redirect 106 * - chunked request/response 107 * - SSL 108 * - proxies 109 * - 100 continue 110 * - check keep alive appears to be working 111 * - cancel of long request 112 * 113 * Uses a FileServerHandler serving a couple of known files 114 * in docs directory. 115 */ 116 public class SmokeTest { 117 static SSLContext ctx; 118 static SSLParameters sslparams; 119 static HttpServer s1 ; 120 static HttpsServer s2; 121 static ExecutorService executor; 122 static int port; 123 static int httpsport; 124 static String httproot; 125 static String httpsroot; 126 static HttpClient client; 127 static ProxyServer proxy; 128 static int proxyPort; 129 static RedirectErrorHandler redirectErrorHandler, redirectErrorHandlerSecure; 130 static RedirectHandler redirectHandler, redirectHandlerSecure; 131 static DelayHandler delayHandler; 132 final static String midSizedFilename = "/files/notsobigfile.txt"; 133 final static String smallFilename = "/files/smallfile.txt"; 134 static Path midSizedFile; 135 static Path smallFile; 136 static String fileroot; 137 getFileContent(String path)138 static String getFileContent(String path) throws IOException { 139 FileInputStream fis = new FileInputStream(path); 140 byte[] buf = new byte[2000]; 141 StringBuilder sb = new StringBuilder(); 142 int n; 143 while ((n=fis.read(buf)) != -1) { 144 sb.append(new String(buf, 0, n, "US-ASCII")); 145 } 146 fis.close(); 147 return sb.toString(); 148 } 149 cmpFileContent(Path path1, Path path2)150 static void cmpFileContent(Path path1, Path path2) throws IOException { 151 InputStream fis1 = new BufferedInputStream(new FileInputStream(path1.toFile())); 152 InputStream fis2 = new BufferedInputStream(new FileInputStream(path2.toFile())); 153 154 int n1, n2; 155 while ((n1=fis1.read()) != -1) { 156 n2 = fis2.read(); 157 if (n1 != n2) 158 throw new IOException("Content not the same"); 159 } 160 fis1.close(); 161 fis2.close(); 162 } 163 main(String[] args)164 public static void main(String[] args) throws Exception { 165 initServer(); 166 fileroot = System.getProperty ("test.src", ".")+ "/docs"; 167 midSizedFile = Paths.get(fileroot + midSizedFilename); 168 smallFile = Paths.get(fileroot + smallFilename); 169 ExecutorService e = Executors.newCachedThreadPool(); 170 System.out.println(e); 171 client = HttpClient.newBuilder() 172 .sslContext(ctx) 173 .executor(e) 174 .version(HttpClient.Version.HTTP_1_1) 175 .sslParameters(sslparams) 176 .followRedirects(HttpClient.Redirect.ALWAYS) 177 .build(); 178 179 try { 180 test1(httproot + "files/foo.txt", true); 181 test1(httproot + "files/foo.txt", false); 182 test1(httpsroot + "files/foo.txt", true); 183 test1(httpsroot + "files/foo.txt", false); 184 185 test2(httproot + "echo/foo", "This is a short test"); 186 test2(httpsroot + "echo/foo", "This is a short test"); 187 188 test2a(httproot + "echo/foo"); 189 test2a(httpsroot + "echo/foo"); 190 191 test3(httproot + "redirect/foo.txt"); 192 test3(httpsroot + "redirect/foo.txt"); 193 194 test4(httproot + "files/foo.txt"); 195 196 test4(httpsroot + "files/foo.txt"); 197 198 test5(httproot + "echo/foo", true); 199 200 test5(httpsroot + "echo/foo", true); 201 test5(httproot + "echo/foo", false); 202 203 test5(httpsroot + "echo/foo", false); 204 205 test6(httproot + "echo/foo", true); 206 test6(httpsroot + "echo/foo", true); 207 test6(httproot + "echo/foo", false); 208 test6(httpsroot + "echo/foo", false); 209 210 test7(httproot + "keepalive/foo"); 211 /* 212 test10(httproot + "redirecterror/foo.txt"); 213 214 test10(httpsroot + "redirecterror/foo.txt"); 215 216 test11(httproot + "echo/foo"); 217 test11(httpsroot + "echo/foo"); 218 */ 219 //test12(httproot + "delay/foo", delayHandler); 220 221 } finally { 222 s1.stop(0); 223 s2.stop(0); 224 proxy.close(); 225 e.shutdownNow(); 226 executor.shutdownNow(); 227 } 228 } 229 230 static class Auth extends java.net.Authenticator { 231 volatile int count = 0; 232 @Override getPasswordAuthentication()233 protected PasswordAuthentication getPasswordAuthentication() { 234 if (count++ == 0) { 235 return new PasswordAuthentication("user", "passwd".toCharArray()); 236 } else { 237 return new PasswordAuthentication("user", "goober".toCharArray()); 238 } 239 } count()240 int count() { 241 return count; 242 } 243 } 244 245 // Basic test test1(String target, boolean fixedLen)246 static void test1(String target, boolean fixedLen) throws Exception { 247 System.out.print("test1: " + target); 248 URI uri = new URI(target); 249 250 HttpRequest.Builder builder = HttpRequest.newBuilder().uri(uri).GET(); 251 252 if (fixedLen) { 253 builder.header("XFixed", "yes"); 254 } 255 256 HttpRequest request = builder.build(); 257 258 HttpResponse<String> response = client.send(request, BodyHandlers.ofString()); 259 260 String body = response.body(); 261 if (!body.equals("This is foo.txt\r\n")) { 262 throw new RuntimeException("Did not get expected body: " 263 + "\n\t expected \"This is foo.txt\\r\\n\"" 264 + "\n\t received \"" 265 + body.replace("\r", "\\r").replace("\n","\\n") + "\""); 266 } 267 268 // repeat async 269 HttpResponse<String> response1 = client.sendAsync(request, BodyHandlers.ofString()) 270 .join(); 271 272 String body1 = response1.body(); 273 if (!body1.equals("This is foo.txt\r\n")) { 274 throw new RuntimeException(); 275 } 276 System.out.println(" OK"); 277 } 278 279 // POST use echo to check reply test2(String s, String body)280 static void test2(String s, String body) throws Exception { 281 System.out.print("test2: " + s); 282 URI uri = new URI(s); 283 284 HttpRequest request = HttpRequest.newBuilder(uri) 285 .POST(BodyPublishers.ofString(body)) 286 .build(); 287 288 HttpResponse<String> response = client.send(request, BodyHandlers.ofString()); 289 290 if (response.statusCode() != 200) { 291 throw new RuntimeException( 292 "Expected 200, got [ " + response.statusCode() + " ]"); 293 } 294 String reply = response.body(); 295 if (!reply.equals(body)) { 296 throw new RuntimeException( 297 "Body mismatch: expected [" + body + "], got [" + reply + "]"); 298 } 299 System.out.println(" OK"); 300 } 301 302 // POST use echo to check reply test2a(String s)303 static void test2a(String s) throws Exception { 304 System.out.print("test2a: " + s); 305 URI uri = new URI(s); 306 Path p = getTempFile(128 * 1024); 307 308 HttpRequest request = HttpRequest.newBuilder(uri) 309 .POST(BodyPublishers.ofFile(p)) 310 .build(); 311 312 Path resp = getTempFile(1); // will be overwritten 313 314 HttpResponse<Path> response = client.send(request, 315 BodyHandlers.ofFile(resp, TRUNCATE_EXISTING, WRITE)); 316 317 if (response.statusCode() != 200) { 318 throw new RuntimeException( 319 "Expected 200, got [ " + response.statusCode() + " ]"); 320 } 321 // no redirection, etc, should be no previous response 322 if (response.previousResponse().isPresent()) { 323 throw new RuntimeException( 324 "Unexpected previous response: " + response.previousResponse().get()); 325 } 326 Path reply = response.body(); 327 //System.out.println("Reply stored in " + reply.toString()); 328 cmpFileContent(reply, p); 329 System.out.println(" OK"); 330 } 331 332 // Redirect test3(String s)333 static void test3(String s) throws Exception { 334 System.out.print("test3: " + s); 335 URI uri = new URI(s); 336 RedirectHandler handler = uri.getScheme().equals("https") 337 ? redirectHandlerSecure : redirectHandler; 338 339 HttpRequest request = HttpRequest.newBuilder() 340 .uri(uri) 341 .GET() 342 .build(); 343 344 HttpResponse<Path> response = client.send(request, 345 BodyHandlers.ofFile(Paths.get("redir1.txt"))); 346 347 if (response.statusCode() != 200) { 348 throw new RuntimeException( 349 "Expected 200, got [ " + response.statusCode() + " ]"); 350 } else { 351 response.body(); 352 } 353 354 Path downloaded = Paths.get("redir1.txt"); 355 if (Files.size(downloaded) != Files.size(midSizedFile)) { 356 throw new RuntimeException("Size mismatch"); 357 } 358 checkPreviousRedirectResponses(request, response); 359 System.out.printf(" (count: %d) ", handler.count()); 360 // repeat with async api 361 362 handler.reset(); 363 364 request = HttpRequest.newBuilder(uri).build(); 365 366 response = client.sendAsync(request, 367 BodyHandlers.ofFile(Paths.get("redir2.txt"))).join(); 368 369 if (response.statusCode() != 200) { 370 throw new RuntimeException( 371 "Expected 200, got [ " + response.statusCode() + " ]"); 372 } else { 373 response.body(); 374 } 375 376 downloaded = Paths.get("redir2.txt"); 377 if (Files.size(downloaded) != Files.size(midSizedFile)) { 378 throw new RuntimeException("Size mismatch 2"); 379 } 380 381 checkPreviousRedirectResponses(request, response); 382 System.out.printf(" (count: %d) ", handler.count()); 383 System.out.println(" OK"); 384 } 385 checkPreviousRedirectResponses(HttpRequest initialRequest, HttpResponse<?> finalResponse)386 static void checkPreviousRedirectResponses(HttpRequest initialRequest, 387 HttpResponse<?> finalResponse) { 388 // there must be at least one previous response 389 finalResponse.previousResponse() 390 .orElseThrow(() -> new RuntimeException("no previous response")); 391 392 HttpResponse<?> response = finalResponse; 393 do { 394 URI uri = response.uri(); 395 response = response.previousResponse().get(); 396 check(300 <= response.statusCode() && response.statusCode() <= 309, 397 "Expected 300 <= code <= 309, got:" + response.statusCode()); 398 check(response.body() == null, "Unexpected body: " + response.body()); 399 String locationHeader = response.headers().firstValue("Location") 400 .orElseThrow(() -> new RuntimeException("no previous Location")); 401 check(uri.toString().endsWith(locationHeader), 402 "URI: " + uri + ", Location: " + locationHeader); 403 } while (response.previousResponse().isPresent()); 404 405 // initial 406 check(initialRequest.equals(response.request()), 407 "Expected initial request [%s] to equal last prev req [%s]", 408 initialRequest, response.request()); 409 } 410 check(boolean cond, Object... msg)411 static void check(boolean cond, Object... msg) { 412 if (cond) 413 return; 414 StringBuilder sb = new StringBuilder(); 415 for (Object o : msg) 416 sb.append(o); 417 throw new RuntimeException(sb.toString()); 418 } 419 420 /** 421 * A Proxy Selector that wraps a ProxySelector.of(), and counts the number 422 * of times its select method has been invoked. This can be used to ensure 423 * that the Proxy Selector is invoked only once per HttpClient.sendXXX 424 * invocation. 425 */ 426 static class CountingProxySelector extends ProxySelector { 427 private final ProxySelector proxySelector; 428 private volatile int count; // 0 CountingProxySelector(InetSocketAddress proxyAddress)429 private CountingProxySelector(InetSocketAddress proxyAddress) { 430 proxySelector = ProxySelector.of(proxyAddress); 431 } 432 of(InetSocketAddress proxyAddress)433 public static CountingProxySelector of(InetSocketAddress proxyAddress) { 434 return new CountingProxySelector(proxyAddress); 435 } 436 count()437 int count() { return count; } 438 439 @Override select(URI uri)440 public List<Proxy> select(URI uri) { 441 count++; 442 return proxySelector.select(uri); 443 } 444 445 @Override connectFailed(URI uri, SocketAddress sa, IOException ioe)446 public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { 447 proxySelector.connectFailed(uri, sa, ioe); 448 } 449 } 450 451 // Proxies test4(String s)452 static void test4(String s) throws Exception { 453 System.out.print("test4: " + s); 454 URI uri = new URI(s); 455 InetSocketAddress proxyAddr = new InetSocketAddress(InetAddress.getLoopbackAddress(), 456 proxyPort); 457 String filename = fileroot + uri.getPath(); 458 459 ExecutorService e = Executors.newCachedThreadPool(); 460 461 CountingProxySelector ps = CountingProxySelector.of(proxyAddr); 462 HttpClient cl = HttpClient.newBuilder() 463 .executor(e) 464 .proxy(ps) 465 .sslContext(ctx) 466 .sslParameters(sslparams) 467 .build(); 468 469 HttpRequest request = HttpRequest.newBuilder(uri).GET().build(); 470 471 CompletableFuture<String> fut = cl.sendAsync(request, BodyHandlers.ofString()) 472 .thenApply((response) -> response.body()); 473 474 String body = fut.get(5, TimeUnit.HOURS); 475 476 String fc = getFileContent(filename); 477 478 if (!body.equals(fc)) { 479 throw new RuntimeException( 480 "Body mismatch: expected [" + body + "], got [" + fc + "]"); 481 } 482 if (ps.count() != 1) { 483 throw new RuntimeException("CountingProxySelector. Expected 1, got " + ps.count()); 484 } 485 e.shutdownNow(); 486 System.out.println(" OK"); 487 } 488 489 // 100 Continue: use echo target test5(String target, boolean fixedLen)490 static void test5(String target, boolean fixedLen) throws Exception { 491 System.out.print("test5: " + target); 492 URI uri = new URI(target); 493 String requestBody = generateString(12 * 1024 + 13); 494 495 HttpRequest.Builder builder = HttpRequest.newBuilder(uri) 496 .expectContinue(true) 497 .POST(BodyPublishers.ofString(requestBody)); 498 499 if (fixedLen) { 500 builder.header("XFixed", "yes"); 501 } 502 503 HttpRequest request = builder.build(); 504 505 HttpResponse<String> response = client.send(request, BodyHandlers.ofString()); 506 507 String body = response.body(); 508 509 if (!body.equals(requestBody)) { 510 throw new RuntimeException( 511 "Body mismatch: expected [" + body + "], got [" + body + "]"); 512 } 513 System.out.println(" OK"); 514 } 515 516 // use echo test6(String target, boolean fixedLen)517 static void test6(String target, boolean fixedLen) throws Exception { 518 System.out.print("test6: " + target); 519 URI uri = new URI(target); 520 String requestBody = generateString(12 * 1024 + 3); 521 522 HttpRequest.Builder builder = HttpRequest.newBuilder(uri).GET(); 523 524 if (fixedLen) { 525 builder.header("XFixed", "yes"); 526 } 527 528 HttpRequest request = builder.build(); 529 530 HttpResponse<String> response = client.send(request, BodyHandlers.ofString()); 531 532 if (response.statusCode() != 200) { 533 throw new RuntimeException( 534 "Expected 200, got [ " + response.statusCode() + " ]"); 535 } 536 537 String responseBody = response.body(); 538 539 if (responseBody.equals(requestBody)) { 540 throw new RuntimeException( 541 "Body mismatch: expected [" + requestBody + "], got [" + responseBody + "]"); 542 } 543 System.out.println(" OK"); 544 } 545 546 @SuppressWarnings("rawtypes") test7(String target)547 static void test7(String target) throws Exception { 548 System.out.print("test7: " + target); 549 Path requestBody = getTempFile(128 * 1024); 550 // First test 551 URI uri = new URI(target); 552 HttpRequest request = HttpRequest.newBuilder().uri(uri).GET().build(); 553 554 for (int i=0; i<4; i++) { 555 HttpResponse<String> r = client.send(request, BodyHandlers.ofString()); 556 String body = r.body(); 557 if (!body.equals("OK")) { 558 throw new RuntimeException("Expected OK, got: " + body); 559 } 560 } 561 562 // Second test: 4 x parallel 563 request = HttpRequest.newBuilder() 564 .uri(uri) 565 .POST(BodyPublishers.ofFile(requestBody)) 566 .build(); 567 List<CompletableFuture<String>> futures = new LinkedList<>(); 568 for (int i=0; i<4; i++) { 569 futures.add(client.sendAsync(request, BodyHandlers.ofString()) 570 .thenApply((response) -> { 571 if (response.statusCode() == 200) 572 return response.body(); 573 else 574 return "ERROR"; 575 })); 576 } 577 // all sent? 578 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) 579 .join(); 580 581 for (CompletableFuture<String> future : futures) { 582 String body = future.get(); 583 if (!body.equals("OK")) { 584 throw new RuntimeException("Expected OK, got: " + body); 585 } 586 } 587 588 // Third test: Multiple of 4 parallel requests 589 request = HttpRequest.newBuilder(uri).GET().build(); 590 BlockingQueue<String> q = new LinkedBlockingQueue<>(); 591 for (int i=0; i<4; i++) { 592 client.sendAsync(request, BodyHandlers.ofString()) 593 .thenApply((HttpResponse<String> resp) -> { 594 String body = resp.body(); 595 putQ(q, body); 596 return body; 597 }); 598 } 599 // we've sent four requests. Now, just send another request 600 // as each response is received. The idea is to ensure that 601 // only four sockets ever get used. 602 603 for (int i=0; i<100; i++) { 604 // block until response received 605 String body = takeQ(q); 606 if (!body.equals("OK")) { 607 throw new RuntimeException(body); 608 } 609 client.sendAsync(request, BodyHandlers.ofString()) 610 .thenApply((resp) -> { 611 if (resp.statusCode() == 200) 612 putQ(q, resp.body()); 613 else 614 putQ(q, "ERROR"); 615 return null; 616 }); 617 } 618 // should be four left 619 for (int i=0; i<4; i++) { 620 takeQ(q); 621 } 622 System.out.println(" OK"); 623 } 624 takeQ(BlockingQueue<String> q)625 static String takeQ(BlockingQueue<String> q) { 626 String r = null; 627 try { 628 r = q.take(); 629 } catch (InterruptedException e) {} 630 631 return r; 632 } 633 putQ(BlockingQueue<String> q, String o)634 static void putQ(BlockingQueue<String> q, String o) { 635 try { 636 q.put(o); 637 } catch (InterruptedException e) { 638 // can't happen 639 } 640 } 641 newStream()642 static FileInputStream newStream() { 643 try { 644 return new FileInputStream(smallFile.toFile()); 645 } catch (FileNotFoundException e) { 646 throw new UncheckedIOException(e); 647 } 648 } 649 // Chunked output stream test11(String target)650 static void test11(String target) throws Exception { 651 System.out.print("test11: " + target); 652 URI uri = new URI(target); 653 654 HttpRequest request = HttpRequest.newBuilder(uri) 655 .POST(BodyPublishers.ofInputStream(SmokeTest::newStream)) 656 .build(); 657 658 Path download = Paths.get("test11.txt"); 659 660 HttpResponse<Path> response = client.send(request, BodyHandlers.ofFile(download)); 661 662 if (response.statusCode() != 200) { 663 throw new RuntimeException("Wrong response code"); 664 } 665 666 download.toFile().delete(); 667 response.body(); 668 669 if (Files.size(download) != Files.size(smallFile)) { 670 System.out.println("Original size: " + Files.size(smallFile)); 671 System.out.println("Downloaded size: " + Files.size(download)); 672 throw new RuntimeException("Size mismatch"); 673 } 674 System.out.println(" OK"); 675 } 676 delay(int seconds)677 static void delay(int seconds) { 678 try { 679 Thread.sleep(seconds * 1000); 680 } catch (InterruptedException e) { 681 } 682 } 683 684 // Redirect loop: return an error after a certain number of redirects test10(String s)685 static void test10(String s) throws Exception { 686 System.out.print("test10: " + s); 687 URI uri = new URI(s); 688 RedirectErrorHandler handler = uri.getScheme().equals("https") 689 ? redirectErrorHandlerSecure : redirectErrorHandler; 690 691 HttpRequest request = HttpRequest.newBuilder(uri).GET().build(); 692 CompletableFuture<HttpResponse<String>> cf = 693 client.sendAsync(request, BodyHandlers.ofString()); 694 695 try { 696 HttpResponse<String> response = cf.join(); 697 throw new RuntimeException("Exepected Completion Exception"); 698 } catch (CompletionException e) { 699 //System.out.println(e); 700 } 701 702 System.out.printf(" (Calls %d) ", handler.count()); 703 System.out.println(" OK"); 704 } 705 706 static final int NUM = 50; 707 708 static Random random = new Random(); 709 static final String alphabet = "ABCDEFGHIJKLMNOPQRST"; 710 randomChar()711 static char randomChar() { 712 return alphabet.charAt(random.nextInt(alphabet.length())); 713 } 714 generateString(int length)715 static String generateString(int length) { 716 StringBuilder sb = new StringBuilder(length); 717 for (int i=0; i<length; i++) { 718 sb.append(randomChar()); 719 } 720 return sb.toString(); 721 } 722 initServer()723 static void initServer() throws Exception { 724 725 Logger logger = Logger.getLogger("com.sun.net.httpserver"); 726 ConsoleHandler ch = new ConsoleHandler(); 727 logger.setLevel(Level.SEVERE); 728 ch.setLevel(Level.SEVERE); 729 logger.addHandler(ch); 730 731 String root = System.getProperty ("test.src", ".")+ "/docs"; 732 InetSocketAddress addr = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); 733 s1 = HttpServer.create (addr, 0); 734 if (s1 instanceof HttpsServer) { 735 throw new RuntimeException ("should not be httpsserver"); 736 } 737 s2 = HttpsServer.create (addr, 0); 738 HttpHandler h = new FileServerHandler(root); 739 740 HttpContext c1 = s1.createContext("/files", h); 741 HttpContext c2 = s2.createContext("/files", h); 742 HttpContext c3 = s1.createContext("/echo", new EchoHandler()); 743 redirectHandler = new RedirectHandler("/redirect"); 744 redirectHandlerSecure = new RedirectHandler("/redirect"); 745 HttpContext c4 = s1.createContext("/redirect", redirectHandler); 746 HttpContext c41 = s2.createContext("/redirect", redirectHandlerSecure); 747 HttpContext c5 = s2.createContext("/echo", new EchoHandler()); 748 HttpContext c6 = s1.createContext("/keepalive", new KeepAliveHandler()); 749 redirectErrorHandler = new RedirectErrorHandler("/redirecterror"); 750 redirectErrorHandlerSecure = new RedirectErrorHandler("/redirecterror"); 751 HttpContext c7 = s1.createContext("/redirecterror", redirectErrorHandler); 752 HttpContext c71 = s2.createContext("/redirecterror", redirectErrorHandlerSecure); 753 delayHandler = new DelayHandler(); 754 HttpContext c8 = s1.createContext("/delay", delayHandler); 755 HttpContext c81 = s2.createContext("/delay", delayHandler); 756 757 executor = Executors.newCachedThreadPool(); 758 s1.setExecutor(executor); 759 s2.setExecutor(executor); 760 ctx = new SimpleSSLContext().get(); 761 sslparams = ctx.getDefaultSSLParameters(); 762 //sslparams.setProtocols(new String[]{"TLSv1.2"}); 763 s2.setHttpsConfigurator(new Configurator(ctx)); 764 s1.start(); 765 s2.start(); 766 767 port = s1.getAddress().getPort(); 768 System.out.println("HTTP server port = " + port); 769 httpsport = s2.getAddress().getPort(); 770 System.out.println("HTTPS server port = " + httpsport); 771 httproot = "http://localhost:" + port + "/"; 772 httpsroot = "https://localhost:" + httpsport + "/"; 773 774 proxy = new ProxyServer(0, false); 775 proxyPort = proxy.getPort(); 776 System.out.println("Proxy port = " + proxyPort); 777 } 778 779 static class RedirectHandler implements HttpHandler { 780 private final String root; 781 private volatile int count = 0; 782 RedirectHandler(String root)783 RedirectHandler(String root) { 784 this.root = root; 785 } 786 787 @Override handle(HttpExchange t)788 public synchronized void handle(HttpExchange t) throws IOException { 789 byte[] buf = new byte[2048]; 790 try (InputStream is = t.getRequestBody()) { 791 while (is.read(buf) != -1) ; 792 } 793 794 Headers responseHeaders = t.getResponseHeaders(); 795 796 if (count++ < 1) { 797 responseHeaders.add("Location", root + "/foo/" + count); 798 } else { 799 responseHeaders.add("Location", SmokeTest.midSizedFilename); 800 } 801 t.sendResponseHeaders(301, 64 * 1024); 802 byte[] bb = new byte[1024]; 803 OutputStream os = t.getResponseBody(); 804 for (int i=0; i<64; i++) { 805 os.write(bb); 806 } 807 os.close(); 808 t.close(); 809 } 810 count()811 int count() { 812 return count; 813 } 814 reset()815 void reset() { 816 count = 0; 817 } 818 } 819 820 static class RedirectErrorHandler implements HttpHandler { 821 private final String root; 822 private volatile int count = 1; 823 RedirectErrorHandler(String root)824 RedirectErrorHandler(String root) { 825 this.root = root; 826 } 827 count()828 synchronized int count() { 829 return count; 830 } 831 increment()832 synchronized void increment() { 833 count++; 834 } 835 836 @Override handle(HttpExchange t)837 public synchronized void handle(HttpExchange t) throws IOException { 838 try (InputStream is = t.getRequestBody()) { 839 is.readAllBytes(); 840 } 841 842 Headers map = t.getResponseHeaders(); 843 String redirect = root + "/foo/" + Integer.toString(count); 844 increment(); 845 map.add("Location", redirect); 846 t.sendResponseHeaders(301, -1); 847 t.close(); 848 } 849 } 850 851 static class DelayHandler implements HttpHandler { 852 853 CyclicBarrier bar1 = new CyclicBarrier(2); 854 CyclicBarrier bar2 = new CyclicBarrier(2); 855 CyclicBarrier bar3 = new CyclicBarrier(2); 856 barrier1()857 CyclicBarrier barrier1() { 858 return bar1; 859 } 860 barrier2()861 CyclicBarrier barrier2() { 862 return bar2; 863 } 864 865 @Override handle(HttpExchange he)866 public synchronized void handle(HttpExchange he) throws IOException { 867 he.getRequestBody().readAllBytes(); 868 try { 869 bar1.await(); 870 bar2.await(); 871 } catch (Exception e) { } 872 he.sendResponseHeaders(200, -1); // will probably fail 873 he.close(); 874 } 875 } 876 877 static class Configurator extends HttpsConfigurator { Configurator(SSLContext ctx)878 public Configurator(SSLContext ctx) { 879 super(ctx); 880 } 881 configure(HttpsParameters params)882 public void configure (HttpsParameters params) { 883 SSLParameters p = getSSLContext().getDefaultSSLParameters(); 884 //p.setProtocols(new String[]{"TLSv1.2"}); 885 params.setSSLParameters (p); 886 } 887 } 888 889 static final Path CWD = Paths.get("."); 890 getTempFile(int size)891 static Path getTempFile(int size) throws IOException { 892 File f = Files.createTempFile(CWD, "test", "txt").toFile(); 893 f.deleteOnExit(); 894 byte[] buf = new byte[2048]; 895 for (int i = 0; i < buf.length; i++) 896 buf[i] = (byte) i; 897 898 FileOutputStream fos = new FileOutputStream(f); 899 while (size > 0) { 900 int amount = Math.min(size, buf.length); 901 fos.write(buf, 0, amount); 902 size -= amount; 903 } 904 fos.close(); 905 return f.toPath(); 906 } 907 } 908 909 // check for simple hardcoded sequence and use remote address 910 // to check. 911 // First 4 requests executed in sequence (should use same connection/address) 912 // Next 4 requests parallel (should use different addresses) 913 // Then send 4 requests in parallel x 100 times (same four addresses used all time) 914 915 class KeepAliveHandler implements HttpHandler { 916 final AtomicInteger counter = new AtomicInteger(0); 917 final AtomicInteger nparallel = new AtomicInteger(0); 918 919 final Set<Integer> portSet = Collections.synchronizedSet(new HashSet<>()); 920 921 final int[] ports = new int[8]; 922 sleep(int n)923 void sleep(int n) { 924 try { 925 Thread.sleep(n); 926 } catch (InterruptedException e) {} 927 } 928 setPort(int index, int value)929 synchronized void setPort(int index, int value) { 930 ports[index] = value; 931 } 932 getPort(int index)933 synchronized int getPort(int index) { 934 return ports[index]; 935 } 936 getPorts(int[] dest, int from)937 synchronized void getPorts(int[] dest, int from) { 938 dest[0] = ports[from+0]; 939 dest[1] = ports[from+1]; 940 dest[2] = ports[from+2]; 941 dest[3] = ports[from+3]; 942 } 943 944 static final CountDownLatch latch = new CountDownLatch(4); 945 static final CountDownLatch latch7 = new CountDownLatch(4); 946 static final CountDownLatch latch8 = new CountDownLatch(1); 947 948 @Override handle(HttpExchange t)949 public void handle (HttpExchange t) 950 throws IOException 951 { 952 int np = nparallel.incrementAndGet(); 953 int remotePort = t.getRemoteAddress().getPort(); 954 String result = "OK"; 955 int[] lports = new int[4]; 956 957 int n = counter.getAndIncrement(); 958 959 /// First test 960 if (n < 4) { 961 setPort(n, remotePort); 962 } 963 if (n == 3) { 964 getPorts(lports, 0); 965 // check all values in ports[] are the same 966 if (lports[0] != lports[1] || lports[2] != lports[3] 967 || lports[0] != lports[2]) { 968 result = "Error " + Integer.toString(n); 969 System.out.println(result); 970 } 971 } 972 // Second test 973 if (n >=4 && n < 8) { 974 // delay so that this connection doesn't get reused 975 // before all 4 requests sent 976 setPort(n, remotePort); 977 latch.countDown(); 978 try {latch.await();} catch (InterruptedException e) {} 979 latch7.countDown(); 980 } 981 if (n == 7) { 982 // wait until all n <= 7 have called setPort(...) 983 try {latch7.await();} catch (InterruptedException e) {} 984 getPorts(lports, 4); 985 // should be all different 986 if (lports[0] == lports[1] || lports[2] == lports[3] 987 || lports[0] == lports[2]) { 988 result = "Error " + Integer.toString(n); 989 System.out.println(result); 990 } 991 // setup for third test 992 for (int i=0; i<4; i++) { 993 portSet.add(lports[i]); 994 } 995 System.out.printf("Ports: %d, %d, %d, %d\n", lports[0], lports[1], lports[2], lports[3]); 996 latch8.countDown(); 997 } 998 // Third test 999 if (n > 7) { 1000 // wait until all n == 7 has updated portSet 1001 try {latch8.await();} catch (InterruptedException e) {} 1002 if (np > 4) { 1003 System.err.println("XXX np = " + np); 1004 } 1005 // just check that port is one of the ones in portSet 1006 if (!portSet.contains(remotePort)) { 1007 System.out.println ("UNEXPECTED REMOTE PORT " 1008 + remotePort + " not in " + portSet); 1009 result = "Error " + Integer.toString(n); 1010 System.out.println(result); 1011 } 1012 } 1013 byte[] buf = new byte[2048]; 1014 1015 try (InputStream is = t.getRequestBody()) { 1016 while (is.read(buf) != -1) ; 1017 } 1018 t.sendResponseHeaders(200, result.length()); 1019 OutputStream o = t.getResponseBody(); 1020 o.write(result.getBytes("US-ASCII")); 1021 t.close(); 1022 nparallel.getAndDecrement(); 1023 } 1024 } 1025