/* * Copyright (c) 2018, 2019, 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. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * 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.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpHeaders; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.concurrent.Flow; /** * @test * @bug 8212926 * @summary Basic tests for response timeouts * @run main/othervm LargeResponseContent */ public class LargeResponseContent { final ServerSocket server; final int port; public LargeResponseContent() throws Exception { server = new ServerSocket(0, 10, InetAddress.getLoopbackAddress()); Thread serverThread = new Thread(this::handleConnection); serverThread.setDaemon(false); port = server.getLocalPort(); serverThread.start(); } final String serverAuthority() { return InetAddress.getLoopbackAddress().getHostName() + ":" + server.getLocalPort(); } void runClient() throws IOException, InterruptedException { URI uri = URI.create("http://" + serverAuthority() + "/foo"); HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder(uri) .GET() .build(); HttpResponse response = client.send(request, new ClientHandler()); System.out.println("Response code = " + response.statusCode()); long blen = response.body(); if (blen != CONTENT_LEN) throw new RuntimeException("wrong content length"); } public static void main(String[] args) throws Exception { System.out.println ("CONTENT_LEN = " + CONTENT_LEN); System.out.println ("CLEN_STR = " + CLEN_STR); LargeResponseContent test = new LargeResponseContent(); test.runClient(); } static class ClientHandler implements HttpResponse.BodyHandler { @Override public HttpResponse.BodySubscriber apply(HttpResponse.ResponseInfo responseInfo) { HttpHeaders headers = responseInfo.headers(); headers.firstValue("content-length"); long clen = headers.firstValueAsLong("content-length").orElse(-1); if (clen != CONTENT_LEN) return new Subscriber(new RuntimeException("Wrong content length received")); return new Subscriber(null); } } static class Subscriber implements HttpResponse.BodySubscriber { final CompletableFuture cf = new CompletableFuture<>(); volatile Flow.Subscription subscription; volatile long counter = 0; Subscriber(Throwable t) { if (t != null) cf.completeExceptionally(t); } @Override public CompletionStage getBody() { return cf; } @Override public void onSubscribe(Flow.Subscription subscription) { this.subscription = subscription; subscription.request(Long.MAX_VALUE); } @Override public void onNext(List item) { long v = 0; for (ByteBuffer b : item) v+= b.remaining(); counter += v; } @Override public void onError(Throwable throwable) { throwable.printStackTrace(); } @Override public void onComplete() { cf.complete(counter); } } static final long CONTENT_LEN = Integer.MAX_VALUE + 1000L; static final String CLEN_STR = Long.valueOf(CONTENT_LEN).toString(); static String RESPONSE = "HTTP/1.1 200 OK\r\n" + "Content-length: " + CLEN_STR + "\r\n" + "\r\n"; void readHeaders(InputStream is) throws IOException { String s = ""; byte[] buf = new byte[128]; while (!s.endsWith("\r\n\r\n")) { int c = is.read(buf); String f = new String(buf, 0, c, StandardCharsets.ISO_8859_1); s = s + f; } } public void handleConnection() { long remaining = CONTENT_LEN; try { Socket socket = server.accept(); InputStream is = socket.getInputStream(); readHeaders(is); // read first byte OutputStream os = socket.getOutputStream(); os.write(RESPONSE.getBytes()); byte[] buf = new byte[64 * 1024]; while (remaining > 0) { int amount = (int)Math.min(remaining, buf.length); os.write(buf, 0, amount); remaining -= amount; } System.out.println("Server: finished writing"); os.close(); } catch (IOException e) { long sent = CONTENT_LEN - remaining; System.out.println("Sent " + sent); e.printStackTrace(); } } }