test/jdk/java/net/httpclient/SplitResponse.java
changeset 48083 b1c1b4ef4be2
parent 47216 71c04702a3d5
child 49765 ee6f7a61f3a5
child 55973 4d9b002587db
equal deleted inserted replaced
48081:89829dd3cc54 48083:b1c1b4ef4be2
     1 /*
     1 /*
     2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
     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.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     7  * published by the Free Software Foundation.
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    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
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    21  * questions.
    22  */
    22  */
    23 
    23 
    24 
       
    25 import java.io.IOException;
    24 import java.io.IOException;
       
    25 import java.net.URI;
       
    26 import java.util.concurrent.CompletableFuture;
       
    27 import javax.net.ssl.SSLContext;
       
    28 import javax.net.ServerSocketFactory;
       
    29 import javax.net.ssl.SSLServerSocketFactory;
    26 import jdk.incubator.http.HttpClient;
    30 import jdk.incubator.http.HttpClient;
       
    31 import jdk.incubator.http.HttpClient.Version;
    27 import jdk.incubator.http.HttpRequest;
    32 import jdk.incubator.http.HttpRequest;
    28 import jdk.incubator.http.HttpResponse;
    33 import jdk.incubator.http.HttpResponse;
    29 import java.net.URI;
    34 import jdk.testlibrary.SimpleSSLContext;
    30 import java.util.concurrent.CompletableFuture;
    35 import static java.lang.System.out;
    31 import java.util.concurrent.Executor;
    36 import static java.lang.String.format;
    32 import java.util.concurrent.ExecutorService;
       
    33 import static jdk.incubator.http.HttpResponse.BodyHandler.asString;
    37 import static jdk.incubator.http.HttpResponse.BodyHandler.asString;
    34 
    38 
    35 /**
    39 /**
    36  * @test
    40  * @test
    37  * @bug 8087112
    41  * @bug 8087112
    38  * @key intermittent
    42  * @library /lib/testlibrary
    39  * @build Server
    43  * @build jdk.testlibrary.SimpleSSLContext
    40  * @run main/othervm -Djava.net.HttpClient.log=all SplitResponse
    44  * @build MockServer
       
    45  * @run main/othervm -Djdk.internal.httpclient.debug=true -Djdk.httpclient.HttpClient.log=all SplitResponse
    41  */
    46  */
    42 
    47 
    43 /**
    48 /**
    44  * Similar test to QuickResponses except that each byte of the response
    49  * Similar test to QuickResponses except that each byte of the response
    45  * is sent in a separate packet, which tests the stability of the implementation
    50  * is sent in a separate packet, which tests the stability of the implementation
    46  * for receiving unusual packet sizes.
    51  * for receiving unusual packet sizes. Additionally, tests scenarios there
       
    52  * connections that are retrieved from the connection pool may reach EOF before
       
    53  * being reused.
    47  */
    54  */
    48 public class SplitResponse {
    55 public class SplitResponse {
    49 
    56 
    50     static Server server;
    57     static String response(String body, boolean serverKeepalive) {
    51 
    58         StringBuilder sb = new StringBuilder();
    52     static String response(String body) {
    59         sb.append("HTTP/1.1 200 OK\r\n");
    53         return "HTTP/1.1 200 OK\r\nConnection: Close\r\nContent-length: "
    60         if (!serverKeepalive)
    54                 + Integer.toString(body.length())
    61             sb.append("Connection: Close\r\n");
    55                 + "\r\n\r\n" + body;
    62 
       
    63         sb.append("Content-length: ").append(body.length()).append("\r\n");
       
    64         sb.append("\r\n");
       
    65         sb.append(body);
       
    66         return sb.toString();
    56     }
    67     }
    57 
    68 
    58     static final String responses[] = {
    69     static final String responses[] = {
    59         "Lorem ipsum",
    70         "Lorem ipsum",
    60         "dolor sit amet",
    71         "dolor sit amet",
    66         "Duis aute irure dolor in reprehenderit in voluptate velit esse" +
    77         "Duis aute irure dolor in reprehenderit in voluptate velit esse" +
    67         "cillum dolore eu fugiat nulla pariatur.",
    78         "cillum dolore eu fugiat nulla pariatur.",
    68         "Excepteur sint occaecat cupidatat non proident."
    79         "Excepteur sint occaecat cupidatat non proident."
    69     };
    80     };
    70 
    81 
       
    82     final ServerSocketFactory factory;
       
    83     final SSLContext context;
       
    84     final boolean useSSL;
       
    85     SplitResponse(boolean useSSL) throws IOException {
       
    86         this.useSSL = useSSL;
       
    87         context = new SimpleSSLContext().get();
       
    88         SSLContext.setDefault(context);
       
    89         factory = useSSL ? SSLServerSocketFactory.getDefault()
       
    90                          : ServerSocketFactory.getDefault();
       
    91     }
       
    92 
       
    93     public HttpClient newHttpClient() {
       
    94         HttpClient client;
       
    95         if (useSSL) {
       
    96             client = HttpClient.newBuilder()
       
    97                                .sslContext(context)
       
    98                                .build();
       
    99         } else {
       
   100             client = HttpClient.newHttpClient();
       
   101         }
       
   102         return client;
       
   103     }
       
   104 
    71     public static void main(String[] args) throws Exception {
   105     public static void main(String[] args) throws Exception {
    72         server = new Server(0);
   106         boolean useSSL = false;
       
   107         if (args != null && args.length == 1) {
       
   108             useSSL = "SSL".equals(args[0]);
       
   109         }
       
   110         SplitResponse sp = new SplitResponse(useSSL);
       
   111 
       
   112         for (Version version : Version.values()) {
       
   113             for (boolean serverKeepalive : new boolean[]{ true, false }) {
       
   114                 // Note: the mock server doesn't support Keep-Alive, but
       
   115                 // pretending that it might exercises code paths in and out of
       
   116                 // the connection pool, and retry logic
       
   117                 for (boolean async : new boolean[]{ true, false }) {
       
   118                     sp.test(version, serverKeepalive, async);
       
   119                 }
       
   120             }
       
   121         }
       
   122     }
       
   123 
       
   124     // @Test
       
   125     void test(Version version, boolean serverKeepalive, boolean async)
       
   126         throws Exception
       
   127     {
       
   128         out.println(format("*** version %s, serverKeepAlive: %s, async: %s ***",
       
   129                            version, serverKeepalive, async));
       
   130         MockServer server = new MockServer(0, factory);
    73         URI uri = new URI(server.getURL());
   131         URI uri = new URI(server.getURL());
       
   132         out.println("server is: " + uri);
    74         server.start();
   133         server.start();
    75 
   134 
    76         HttpClient client = HttpClient.newHttpClient();
   135 
    77         HttpRequest request = HttpRequest.newBuilder(uri).build();
   136         // The following code can be uncommented to verify that the
       
   137         // MockServer will reject rogue requests whose URI does not
       
   138         // contain "/foo/".
       
   139         //
       
   140         //        Thread rogue = new Thread() {
       
   141         //            public void run() {
       
   142         //                try {
       
   143         //                    HttpClient client = newHttpClient();
       
   144         //                    URI uri2 = URI.create(uri.toString().replace("/foo/","/"));
       
   145         //                    HttpRequest request = HttpRequest
       
   146         //                        .newBuilder(uri2).version(version).build();
       
   147         //                    while (true) {
       
   148         //                        try {
       
   149         //                            client.send(request, HttpResponse.BodyHandler.asString());
       
   150         //                        } catch (IOException ex) {
       
   151         //                            System.out.println("Client rejected " + request);
       
   152         //                        }
       
   153         //                        sleep(250);
       
   154         //                    }
       
   155         //                } catch ( Throwable x) {
       
   156         //                }
       
   157         //            }
       
   158         //        };
       
   159         //        rogue.setDaemon(true);
       
   160         //        rogue.start();
       
   161 
       
   162 
       
   163         HttpClient client = newHttpClient();
       
   164         HttpRequest request = HttpRequest.newBuilder(uri).version(version).build();
    78         HttpResponse<String> r;
   165         HttpResponse<String> r;
    79         CompletableFuture<HttpResponse<String>> cf1;
   166         CompletableFuture<HttpResponse<String>> cf1;
    80 
   167 
    81         try {
   168         try {
    82             for (int i=0; i<responses.length; i++) {
   169             for (int i=0; i<responses.length; i++) {
    83                 cf1 = client.sendAsync(request, asString());
   170                 out.println("----- iteration " + i + " -----");
    84                 String body = responses[i];
   171                 String body = responses[i];
    85 
   172                 Thread t = sendSplitResponse(response(body, serverKeepalive), server);
    86                 Server.Connection c = server.activity();
   173 
    87                 sendSplitResponse(response(body), c);
   174                 if (async) {
    88                 r = cf1.get();
   175                     out.println("send async: " + request);
    89                 if (r.statusCode()!= 200)
   176                     cf1 = client.sendAsync(request, asString());
       
   177                     r = cf1.get();
       
   178                 } else { // sync
       
   179                     out.println("send sync: " + request);
       
   180                     r = client.send(request, asString());
       
   181                 }
       
   182 
       
   183                 if (r.statusCode() != 200)
    90                     throw new RuntimeException("Failed");
   184                     throw new RuntimeException("Failed");
    91 
   185 
    92                 String rxbody = r.body();
   186                 String rxbody = r.body();
    93                 System.out.println("received " + rxbody);
   187                 out.println("received " + rxbody);
    94                 if (!rxbody.equals(body))
   188                 if (!rxbody.equals(body))
    95                     throw new RuntimeException("Failed");
   189                     throw new RuntimeException(format("Expected:%s, got:%s", body, rxbody));
    96                 c.close();
   190 
       
   191                 t.join();
       
   192                 conn.close();
    97             }
   193             }
    98         } finally {
   194         } finally {
    99             Executor def = client.executor();
   195             server.close();
   100             if (def instanceof ExecutorService) {
       
   101                 ((ExecutorService)def).shutdownNow();
       
   102             }
       
   103         }
   196         }
   104         System.out.println("OK");
   197         System.out.println("OK");
   105     }
   198     }
   106 
   199 
   107     // send the response one byte at a time with a small delay between bytes
   200     // required for cleanup
   108     // to ensure that each byte is read in a separate read
   201     volatile MockServer.Connection conn;
   109     static void sendSplitResponse(String s, Server.Connection conn) {
   202 
       
   203     // Sends the response, mostly, one byte at a time with a small delay
       
   204     // between bytes, to encourage that each byte is read in a separate read
       
   205     Thread sendSplitResponse(String s, MockServer server) {
   110         System.out.println("Sending: ");
   206         System.out.println("Sending: ");
   111         Thread t = new Thread(() -> {
   207         Thread t = new Thread(() -> {
       
   208             System.out.println("Waiting for server to receive headers");
       
   209             conn = server.activity();
       
   210             System.out.println("Start sending response");
       
   211 
   112             try {
   212             try {
   113                 int len = s.length();
   213                 int len = s.length();
       
   214                 out.println("sending " + s);
   114                 for (int i = 0; i < len; i++) {
   215                 for (int i = 0; i < len; i++) {
   115                     String onechar = s.substring(i, i + 1);
   216                     String onechar = s.substring(i, i + 1);
   116                     conn.send(onechar);
   217                     conn.send(onechar);
   117                     Thread.sleep(30);
   218                     Thread.sleep(10);
   118                 }
   219                 }
   119                 System.out.println("sent");
   220                 out.println("sent " + s);
   120             } catch (IOException | InterruptedException e) {
   221             } catch (IOException | InterruptedException e) {
       
   222                 throw new RuntimeException(e);
   121             }
   223             }
   122         });
   224         });
   123         t.setDaemon(true);
   225         t.setDaemon(true);
   124         t.start();
   226         t.start();
       
   227         return t;
   125     }
   228     }
   126 }
   229 }