| /* | |
| * Copyright (c) 2017, 2023, 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.InputStream; | |
| import java.io.InputStreamReader; | |
| import java.io.Reader; | |
| 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.net.http.HttpResponse.BodyHandlers; | |
| import java.nio.charset.Charset; | |
| import java.util.Locale; | |
| import java.util.Optional; | |
| import java.util.concurrent.CompletableFuture; | |
| import java.util.stream.Stream; | |
| import static java.lang.System.err; | |
| /* | |
| * @test | |
| * @bug 8187503 | |
| * @summary An example on how to read a response body with InputStream. | |
| * @run main/othervm/manual -Dtest.debug=true BodyProcessorInputStreamTest | |
| * @author daniel fuchs | |
| */ | |
| public class BodyProcessorInputStreamTest { | |
| public static boolean DEBUG = Boolean.getBoolean("test.debug"); | |
| /** | |
| * Examine the response headers to figure out the charset used to | |
| * encode the body content. | |
| * If the content type is not textual, returns an empty Optional. | |
| * Otherwise, returns the body content's charset, defaulting to | |
| * ISO-8859-1 if none is explicitly specified. | |
| * @param headers The response headers. | |
| * @return The charset to use for decoding the response body, if | |
| * the response body content is text/... | |
| */ | |
| public static Optional<Charset> getCharset(HttpHeaders headers) { | |
| Optional<String> contentType = headers.firstValue("Content-Type"); | |
| Optional<Charset> charset = Optional.empty(); | |
| if (contentType.isPresent()) { | |
| final String[] values = contentType.get().split(";"); | |
| if (values[0].startsWith("text/")) { | |
| charset = Optional.of(Stream.of(values) | |
| .map(x -> x.toLowerCase(Locale.ROOT)) | |
| .map(String::trim) | |
| .filter(x -> x.startsWith("charset=")) | |
| .map(x -> x.substring("charset=".length())) | |
| .findFirst() | |
| .orElse("ISO-8859-1")) | |
| .map(Charset::forName); | |
| } | |
| } | |
| return charset; | |
| } | |
| public static void main(String[] args) throws Exception { | |
| HttpClient client = HttpClient.newHttpClient(); | |
| HttpRequest request = HttpRequest | |
| .newBuilder(new URI("https://hg.openjdk.org/jdk9/sandbox/jdk/shortlog/http-client-branch/")) | |
| .GET() | |
| .build(); | |
| // This example shows how to return an InputStream that can be used to | |
| // start reading the response body before the response is fully received. | |
| // In comparison, the snipet below (which uses | |
| // HttpResponse.BodyHandlers.ofString()) obviously will not return before the | |
| // response body is fully read: | |
| // | |
| // System.out.println( | |
| // client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).get().body()); | |
| CompletableFuture<HttpResponse<InputStream>> handle = | |
| client.sendAsync(request, BodyHandlers.ofInputStream()); | |
| if (DEBUG) err.println("Request sent"); | |
| HttpResponse<InputStream> pending = handle.get(); | |
| // At this point, the response headers have been received, but the | |
| // response body may not have arrived yet. This comes from | |
| // the implementation of HttpResponseInputStream::getBody above, | |
| // which returns an already completed completion stage, without | |
| // waiting for any data. | |
| // We can therefore access the headers - and the body, which | |
| // is our live InputStream, without waiting... | |
| HttpHeaders responseHeaders = pending.headers(); | |
| // Get the charset declared in the response headers. | |
| // The optional will be empty if the content type is not | |
| // of type text/... | |
| Optional<Charset> charset = getCharset(responseHeaders); | |
| try (InputStream is = pending.body(); | |
| // We assume a textual content type. Construct an InputStream | |
| // Reader with the appropriate Charset. | |
| // charset.get() will throw NPE if the content is not textual. | |
| Reader r = new InputStreamReader(is, charset.get())) { | |
| char[] buff = new char[32]; | |
| int off=0, n=0; | |
| if (DEBUG) err.println("Start receiving response body"); | |
| if (DEBUG) err.println("Charset: " + charset.get()); | |
| // Start consuming the InputStream as the data arrives. | |
| // Will block until there is something to read... | |
| while ((n = r.read(buff, off, buff.length - off)) > 0) { | |
| assert (buff.length - off) > 0; | |
| assert n <= (buff.length - off); | |
| if (n == (buff.length - off)) { | |
| System.out.print(buff); | |
| off = 0; | |
| } else { | |
| off += n; | |
| } | |
| assert off < buff.length; | |
| } | |
| // last call to read may not have filled 'buff' completely. | |
| // flush out the remaining characters. | |
| assert off >= 0 && off < buff.length; | |
| for (int i=0; i < off; i++) { | |
| System.out.print(buff[i]); | |
| } | |
| // We're done! | |
| System.out.println("Done!"); | |
| } | |
| } | |
| } |