test/jdk/java/net/httpclient/SmokeTest.java
changeset 47216 71c04702a3d5
parent 45708 3512073b446f
child 48083 b1c1b4ef4be2
child 55763 634d8e14c172
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     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 }