< prev index next >

test/jdk/java/net/httpclient/SmokeTest.java

Print this page




  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


 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 


 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 


 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();


 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);


 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) {}




  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


 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 


 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 


 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();


 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);


 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) {}


< prev index next >