< prev index next >

test/jdk/java/net/httpclient/ShortRequestBody.java

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 2015, 2016, 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. --- 1,7 ---- /* ! * 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.
*** 19,72 **** * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ ! import java.io.*; ! import jdk.incubator.http.HttpClient; ! import jdk.incubator.http.HttpResponse; ! import jdk.incubator.http.HttpRequest; import java.net.ServerSocket; import java.net.Socket; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.ByteBuffer; 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 static java.nio.charset.StandardCharsets.US_ASCII; import static jdk.incubator.http.HttpResponse.BodyHandler.discard; import static java.nio.charset.StandardCharsets.UTF_8; /** * @test * @bug 8151441 * @summary Request body of incorrect (larger or smaller) sizes than that ! * reported by the body processor * @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"; static final byte[] BYTE_ARRAY_BODY = new byte[] { (byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE }; --- 19,68 ---- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ ! 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; import java.nio.file.Files; 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.ExecutionException; import java.util.concurrent.Flow; import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeUnit; ! 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; /** * @test * @bug 8151441 * @summary Request body of incorrect (larger or smaller) sizes than that ! * reported by the body publisher * @run main/othervm ShortRequestBody */ public class ShortRequestBody { static final Path testSrc = Paths.get(System.getProperty("test.src", ".")); // Some body types ( sources ) for testing. static final String STRING_BODY = "Hello world"; static final byte[] BYTE_ARRAY_BODY = new byte[] { (byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE };
*** 77,94 **** static final int[] BODY_LENGTHS = new int[] { STRING_BODY.length(), BYTE_ARRAY_BODY.length, 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. static abstract class AbstractDelegateRequestBody ! implements HttpRequest.BodyProcessor { ! final HttpRequest.BodyProcessor delegate; final long contentLength; ! AbstractDelegateRequestBody(HttpRequest.BodyProcessor delegate, long contentLength) { this.delegate = delegate; this.contentLength = contentLength; } --- 73,90 ---- static final int[] BODY_LENGTHS = new int[] { STRING_BODY.length(), BYTE_ARRAY_BODY.length, fileSize(FILE_BODY) }; static final int[] BODY_OFFSETS = new int[] { 0, +1, -1, +2, -2, +3, -3 }; ! // A delegating Body Publisher. Subtypes will have a concrete body type. static abstract class AbstractDelegateRequestBody ! implements HttpRequest.BodyPublisher { ! final HttpRequest.BodyPublisher delegate; final long contentLength; ! AbstractDelegateRequestBody(HttpRequest.BodyPublisher delegate, long contentLength) { this.delegate = delegate; this.contentLength = contentLength; }
*** 99,206 **** @Override public long contentLength() { return contentLength; /* may be wrong! */ } } ! // Request body processors 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), body.getBytes(UTF_8).length + additionalLength); } } static class ByteArrayRequestBody extends AbstractDelegateRequestBody { ByteArrayRequestBody(byte[] body, int additionalLength) { ! super(HttpRequest.BodyProcessor.fromByteArray(body), body.length + additionalLength); } } static class FileRequestBody extends AbstractDelegateRequestBody { FileRequestBody(Path path, int additionalLength) throws IOException { ! super(HttpRequest.BodyProcessor.fromFile(path), Files.size(path) + additionalLength); } } // --- public static void main(String[] args) throws Exception { try (Server server = new Server()) { URI uri = new URI("http://127.0.0.1:" + server.getPort() + "/"); ! // sanity ! success(uri, new StringRequestBody(STRING_BODY, 0)); ! success(uri, new ByteArrayRequestBody(BYTE_ARRAY_BODY, 0)); ! success(uri, new FileRequestBody(FILE_BODY, 0)); ! 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])); ! 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(); } } } ! static void success(URI uri, HttpRequest.BodyProcessor processor) throws Exception { CompletableFuture<HttpResponse<Void>> cf; HttpRequest request = HttpRequest.newBuilder(uri) ! .POST(processor) .build(); ! cf = defaultClient().sendAsync(request, discard(null)); HttpResponse<Void> resp = cf.get(30, TimeUnit.SECONDS); ! out.println("Response code: " + resp.statusCode()); check(resp.statusCode() == 200, "Expected 200, got ", resp.statusCode()); } ! static void failureNonBlocking(URI uri, HttpRequest.BodyProcessor processor) throws Exception { CompletableFuture<HttpResponse<Void>> cf; HttpRequest request = HttpRequest.newBuilder(uri) ! .POST(processor) .build(); ! cf = defaultClient().sendAsync(request, discard(null)); try { HttpResponse<Void> r = cf.get(30, TimeUnit.SECONDS); throw new RuntimeException("Unexpected response: " + r.statusCode()); } catch (TimeoutException x) { throw new RuntimeException("Unexpected timeout", x); } catch (ExecutionException expected) { ! out.println("Caught expected: " + expected); ! check(expected.getCause() instanceof IOException, "Expected cause IOException, but got: ", expected.getCause()); } } ! static void failureBlocking(URI uri, HttpRequest.BodyProcessor processor) throws Exception { HttpRequest request = HttpRequest.newBuilder(uri) ! .POST(processor) .build(); try { ! HttpResponse<Void> r = defaultClient().send(request, discard(null)); throw new RuntimeException("Unexpected response: " + r.statusCode()); } catch (IOException expected) { ! out.println("Caught expected: " + expected); } } static class Server extends Thread implements AutoCloseable { --- 95,223 ---- @Override public long contentLength() { return contentLength; /* may be wrong! */ } } ! // 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.BodyPublisher.fromString(body), body.getBytes(UTF_8).length + additionalLength); } } static class ByteArrayRequestBody extends AbstractDelegateRequestBody { ByteArrayRequestBody(byte[] body, int additionalLength) { ! super(HttpRequest.BodyPublisher.fromByteArray(body), body.length + additionalLength); } } static class FileRequestBody extends AbstractDelegateRequestBody { FileRequestBody(Path path, int additionalLength) throws IOException { ! super(HttpRequest.BodyPublisher.fromFile(path), Files.size(path) + additionalLength); } } // --- public static void main(String[] args) throws Exception { + HttpClient sharedClient = HttpClient.newHttpClient(); + List<Supplier<HttpClient>> clientSuppliers = new ArrayList<>(); + clientSuppliers.add(() -> HttpClient.newHttpClient()); + clientSuppliers.add(() -> sharedClient); + 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() + "/"); ! // 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)); ! 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(Supplier<HttpClient> clientSupplier, ! URI uri, ! HttpRequest.BodyPublisher publisher) throws Exception { CompletableFuture<HttpResponse<Void>> cf; HttpRequest request = HttpRequest.newBuilder(uri) ! .POST(publisher) .build(); ! cf = clientSupplier.get().sendAsync(request, discard(null)); HttpResponse<Void> resp = cf.get(30, TimeUnit.SECONDS); ! err.println("Response code: " + resp.statusCode()); check(resp.statusCode() == 200, "Expected 200, got ", resp.statusCode()); } ! static void failureNonBlocking(Supplier<HttpClient> clientSupplier, ! URI uri, ! HttpRequest.BodyPublisher publisher) throws Exception { CompletableFuture<HttpResponse<Void>> cf; HttpRequest request = HttpRequest.newBuilder(uri) ! .POST(publisher) .build(); ! cf = clientSupplier.get().sendAsync(request, discard(null)); try { HttpResponse<Void> r = cf.get(30, TimeUnit.SECONDS); throw new RuntimeException("Unexpected response: " + r.statusCode()); } catch (TimeoutException x) { throw new RuntimeException("Unexpected timeout", x); } catch (ExecutionException expected) { ! 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(Supplier<HttpClient> clientSupplier, ! URI uri, ! HttpRequest.BodyPublisher publisher) throws Exception { HttpRequest request = HttpRequest.newBuilder(uri) ! .POST(publisher) .build(); try { ! 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) { ! 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); } } static class Server extends Thread implements AutoCloseable {
*** 223,246 **** int count = 0; int offset = 0; while (!closed) { try (Socket s = ss.accept()) { 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); ! ! OutputStream os = s.getOutputStream(); ! os.write(RESPONSE.getBytes(US_ASCII)); count++; if (count % 6 == 0) // 6 is the number of failure requests per offset offset++; } catch (IOException e) { if (!closed) System.out.println("Unexpected" + e); } } --- 240,283 ---- int count = 0; int offset = 0; 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]; + 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"); ! // 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); } }
< prev index next >