test/jdk/java/net/httpclient/ShortRequestBody.java
changeset 48083 b1c1b4ef4be2
parent 47216 71c04702a3d5
child 49765 ee6f7a61f3a5
child 56082 1da51fab3032
--- a/test/jdk/java/net/httpclient/ShortRequestBody.java	Fri Nov 03 10:01:08 2017 -0700
+++ b/test/jdk/java/net/httpclient/ShortRequestBody.java	Wed Dec 06 11:11:59 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -21,10 +21,10 @@
  * questions.
  */
 
-import java.io.*;
-import jdk.incubator.http.HttpClient;
-import jdk.incubator.http.HttpResponse;
-import jdk.incubator.http.HttpRequest;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UncheckedIOException;
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.URI;
@@ -32,14 +32,20 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Flow;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.TimeUnit;
-import static java.lang.System.out;
+import java.util.function.Supplier;
+import jdk.incubator.http.HttpClient;
+import jdk.incubator.http.HttpResponse;
+import jdk.incubator.http.HttpRequest;
+import jdk.incubator.http.HttpTimeoutException;
+
+import static java.lang.System.err;
 import static java.nio.charset.StandardCharsets.US_ASCII;
 import static jdk.incubator.http.HttpResponse.BodyHandler.discard;
 import static java.nio.charset.StandardCharsets.UTF_8;
@@ -48,23 +54,13 @@
  * @test
  * @bug 8151441
  * @summary Request body of incorrect (larger or smaller) sizes than that
- *          reported by the body processor
+ *          reported by the body publisher
  * @run main/othervm ShortRequestBody
  */
 
 public class ShortRequestBody {
 
     static final Path testSrc = Paths.get(System.getProperty("test.src", "."));
-    static volatile HttpClient staticDefaultClient;
-
-    static HttpClient defaultClient() {
-        if (staticDefaultClient == null) {
-            synchronized (ShortRequestBody.class) {
-                staticDefaultClient = HttpClient.newHttpClient();
-            }
-        }
-        return staticDefaultClient;
-    }
 
     // Some body types ( sources ) for testing.
     static final String STRING_BODY = "Hello world";
@@ -79,14 +75,14 @@
                                                   fileSize(FILE_BODY) };
     static final int[] BODY_OFFSETS = new int[] { 0, +1, -1, +2, -2, +3, -3 };
 
-    // A delegating body processor. Subtypes will have a concrete body type.
+    // A delegating Body Publisher. Subtypes will have a concrete body type.
     static abstract class AbstractDelegateRequestBody
-            implements HttpRequest.BodyProcessor {
+            implements HttpRequest.BodyPublisher {
 
-        final HttpRequest.BodyProcessor delegate;
+        final HttpRequest.BodyPublisher delegate;
         final long contentLength;
 
-        AbstractDelegateRequestBody(HttpRequest.BodyProcessor delegate,
+        AbstractDelegateRequestBody(HttpRequest.BodyPublisher delegate,
                                     long contentLength) {
             this.delegate = delegate;
             this.contentLength = contentLength;
@@ -101,26 +97,26 @@
         public long contentLength() { return contentLength; /* may be wrong! */ }
     }
 
-    // Request body processors that may generate a different number of actual
+    // Request body Publishers that may generate a different number of actual
     // bytes to that of what is reported through their {@code contentLength}.
 
     static class StringRequestBody extends AbstractDelegateRequestBody {
         StringRequestBody(String body, int additionalLength) {
-            super(HttpRequest.BodyProcessor.fromString(body),
+            super(HttpRequest.BodyPublisher.fromString(body),
                   body.getBytes(UTF_8).length + additionalLength);
         }
     }
 
     static class ByteArrayRequestBody extends AbstractDelegateRequestBody {
         ByteArrayRequestBody(byte[] body, int additionalLength) {
-            super(HttpRequest.BodyProcessor.fromByteArray(body),
+            super(HttpRequest.BodyPublisher.fromByteArray(body),
                   body.length + additionalLength);
         }
     }
 
     static class FileRequestBody extends AbstractDelegateRequestBody {
         FileRequestBody(Path path, int additionalLength) throws IOException {
-            super(HttpRequest.BodyProcessor.fromFile(path),
+            super(HttpRequest.BodyPublisher.fromFile(path),
                   Files.size(path) + additionalLength);
         }
     }
@@ -128,53 +124,63 @@
     // ---
 
     public static void main(String[] args) throws Exception {
-        try (Server server = new Server()) {
-            URI uri = new URI("http://127.0.0.1:" + server.getPort() + "/");
+        HttpClient sharedClient = HttpClient.newHttpClient();
+        List<Supplier<HttpClient>> clientSuppliers = new ArrayList<>();
+        clientSuppliers.add(() -> HttpClient.newHttpClient());
+        clientSuppliers.add(() -> sharedClient);
 
-            // sanity
-            success(uri, new StringRequestBody(STRING_BODY, 0));
-            success(uri, new ByteArrayRequestBody(BYTE_ARRAY_BODY, 0));
-            success(uri, new FileRequestBody(FILE_BODY, 0));
+        try (Server server = new Server()) {
+            for (Supplier<HttpClient> cs : clientSuppliers) {
+                err.println("\n---- next supplier ----\n");
+                URI uri = new URI("http://127.0.0.1:" + server.getPort() + "/");
 
-            for (int i=1; i< BODY_OFFSETS.length; i++) {
-                failureBlocking(uri, new StringRequestBody(STRING_BODY, BODY_OFFSETS[i]));
-                failureBlocking(uri, new ByteArrayRequestBody(BYTE_ARRAY_BODY, BODY_OFFSETS[i]));
-                failureBlocking(uri, new FileRequestBody(FILE_BODY, BODY_OFFSETS[i]));
+                // sanity ( 6 requests to keep client and server offsets easy to workout )
+                success(cs, uri, new StringRequestBody(STRING_BODY, 0));
+                success(cs, uri, new ByteArrayRequestBody(BYTE_ARRAY_BODY, 0));
+                success(cs, uri, new FileRequestBody(FILE_BODY, 0));
+                success(cs, uri, new StringRequestBody(STRING_BODY, 0));
+                success(cs, uri, new ByteArrayRequestBody(BYTE_ARRAY_BODY, 0));
+                success(cs, uri, new FileRequestBody(FILE_BODY, 0));
 
-                failureNonBlocking(uri, new StringRequestBody(STRING_BODY, BODY_OFFSETS[i]));
-                failureNonBlocking(uri, new ByteArrayRequestBody(BYTE_ARRAY_BODY, BODY_OFFSETS[i]));
-                failureNonBlocking(uri, new FileRequestBody(FILE_BODY, BODY_OFFSETS[i]));
-            }
-        } finally {
-            Executor def = defaultClient().executor();
-            if (def instanceof ExecutorService) {
-               ((ExecutorService)def).shutdownNow();
+                for (int i = 1; i < BODY_OFFSETS.length; i++) {
+                    failureBlocking(cs, uri, new StringRequestBody(STRING_BODY, BODY_OFFSETS[i]));
+                    failureBlocking(cs, uri, new ByteArrayRequestBody(BYTE_ARRAY_BODY, BODY_OFFSETS[i]));
+                    failureBlocking(cs, uri, new FileRequestBody(FILE_BODY, BODY_OFFSETS[i]));
+
+                    failureNonBlocking(cs, uri, new StringRequestBody(STRING_BODY, BODY_OFFSETS[i]));
+                    failureNonBlocking(cs, uri, new ByteArrayRequestBody(BYTE_ARRAY_BODY, BODY_OFFSETS[i]));
+                    failureNonBlocking(cs, uri, new FileRequestBody(FILE_BODY, BODY_OFFSETS[i]));
+                }
             }
         }
     }
 
-    static void success(URI uri, HttpRequest.BodyProcessor processor)
+    static void success(Supplier<HttpClient> clientSupplier,
+                        URI uri,
+                        HttpRequest.BodyPublisher publisher)
         throws Exception
     {
         CompletableFuture<HttpResponse<Void>> cf;
         HttpRequest request = HttpRequest.newBuilder(uri)
-                                         .POST(processor)
+                                         .POST(publisher)
                                          .build();
-        cf = defaultClient().sendAsync(request, discard(null));
+        cf = clientSupplier.get().sendAsync(request, discard(null));
 
         HttpResponse<Void> resp = cf.get(30, TimeUnit.SECONDS);
-        out.println("Response code: " + resp.statusCode());
+        err.println("Response code: " + resp.statusCode());
         check(resp.statusCode() == 200, "Expected 200, got ", resp.statusCode());
     }
 
-    static void failureNonBlocking(URI uri, HttpRequest.BodyProcessor processor)
+    static void failureNonBlocking(Supplier<HttpClient> clientSupplier,
+                                   URI uri,
+                                   HttpRequest.BodyPublisher publisher)
         throws Exception
     {
         CompletableFuture<HttpResponse<Void>> cf;
         HttpRequest request = HttpRequest.newBuilder(uri)
-                                         .POST(processor)
+                                         .POST(publisher)
                                          .build();
-        cf = defaultClient().sendAsync(request, discard(null));
+        cf = clientSupplier.get().sendAsync(request, discard(null));
 
         try {
             HttpResponse<Void> r = cf.get(30, TimeUnit.SECONDS);
@@ -182,23 +188,34 @@
         } catch (TimeoutException x) {
             throw new RuntimeException("Unexpected timeout", x);
         } catch (ExecutionException expected) {
-            out.println("Caught expected: " + expected);
-            check(expected.getCause() instanceof IOException,
+            err.println("Caught expected: " + expected);
+            Throwable t = expected.getCause();
+            check(t instanceof IOException,
                   "Expected cause IOException, but got: ", expected.getCause());
+            String msg = t.getMessage();
+            check(msg.contains("Too many") || msg.contains("Too few"),
+                    "Expected Too many|Too few, got: ", t);
         }
     }
 
-    static void failureBlocking(URI uri, HttpRequest.BodyProcessor processor)
+    static void failureBlocking(Supplier<HttpClient> clientSupplier,
+                                URI uri,
+                                HttpRequest.BodyPublisher publisher)
         throws Exception
     {
         HttpRequest request = HttpRequest.newBuilder(uri)
-                                         .POST(processor)
+                                         .POST(publisher)
                                          .build();
         try {
-            HttpResponse<Void> r = defaultClient().send(request, discard(null));
+            HttpResponse<Void> r = clientSupplier.get().send(request, discard(null));
             throw new RuntimeException("Unexpected response: " + r.statusCode());
+        } catch (HttpTimeoutException x) {
+            throw new RuntimeException("Unexpected timeout", x);
         } catch (IOException expected) {
-            out.println("Caught expected: " + expected);
+            err.println("Caught expected: " + expected);
+            String msg = expected.getMessage();
+            check(msg.contains("Too many") || msg.contains("Too few"),
+                    "Expected Too many|Too few, got: ", expected);
         }
     }
 
@@ -225,20 +242,40 @@
 
             while (!closed) {
                 try (Socket s = ss.accept()) {
+                    err.println("Server: got connection");
                     InputStream is = s.getInputStream();
                     readRequestHeaders(is);
                     byte[] ba = new byte[1024];
 
                     int length = BODY_LENGTHS[count % 3];
                     length += BODY_OFFSETS[offset];
-
-                    is.readNBytes(ba, 0, length);
+                    err.println("Server: count=" + count + ", offset=" + offset);
+                    err.println("Server: expecting " +length+ " bytes");
+                    int read = is.readNBytes(ba, 0, length);
+                    err.println("Server: actually read " + read + " bytes");
 
-                    OutputStream os = s.getOutputStream();
-                    os.write(RESPONSE.getBytes(US_ASCII));
+                    // Update the counts before replying, to prevent the
+                    // client-side racing reset with this thread.
                     count++;
                     if (count % 6 == 0) // 6 is the number of failure requests per offset
                         offset++;
+                    if (count % 42 == 0) {
+                        count = 0;  // reset, for second iteration
+                        offset = 0;
+                    }
+
+                    if (read < length) {
+                        // no need to reply, client has already closed
+                        // ensure closed
+                        if (is.read() != -1)
+                            new AssertionError("Unexpected read");
+                    } else {
+                        OutputStream os = s.getOutputStream();
+                        err.println("Server: writing "
+                                + RESPONSE.getBytes(US_ASCII).length + " bytes");
+                        os.write(RESPONSE.getBytes(US_ASCII));
+                    }
+
                 } catch (IOException e) {
                     if (!closed)
                         System.out.println("Unexpected" + e);