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