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