/* * 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. * * 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. */ /* * @test * @bug 8087112 * @modules jdk.incubator.httpclient * java.logging * jdk.httpserver * @library /lib/testlibrary/ /test/lib * @compile ../../../com/sun/net/httpserver/LogFilter.java * @compile ../../../com/sun/net/httpserver/EchoHandler.java * @compile ../../../com/sun/net/httpserver/FileServerHandler.java * @build jdk.test.lib.Platform * @build jdk.test.lib.util.FileUtils * @build LightWeightHttpServer * @build jdk.testlibrary.SimpleSSLContext * @run testng/othervm RequestBodyTest */ import java.io.*; import java.net.URI; import jdk.incubator.http.HttpClient; import jdk.incubator.http.HttpRequest; import jdk.incubator.http.HttpResponse; import jdk.incubator.http.HttpResponse.BodyHandler; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.function.Supplier; import javax.net.ssl.SSLContext; import jdk.test.lib.util.FileUtils; import static java.lang.System.out; import static java.nio.charset.StandardCharsets.*; import static java.nio.file.StandardOpenOption.*; import static jdk.incubator.http.HttpRequest.BodyPublisher.*; import static jdk.incubator.http.HttpResponse.BodyHandler.*; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.*; public class RequestBodyTest { static final String fileroot = System.getProperty("test.src", ".") + "/docs"; static final String midSizedFilename = "/files/notsobigfile.txt"; static final String smallFilename = "/files/smallfile.txt"; final ConcurrentHashMap failures = new ConcurrentHashMap<>(); HttpClient client; String httpURI; String httpsURI; enum RequestBody { BYTE_ARRAY, BYTE_ARRAY_OFFSET, BYTE_ARRAYS, FILE, INPUTSTREAM, STRING, STRING_WITH_CHARSET } enum ResponseBody { BYTE_ARRAY, BYTE_ARRAY_CONSUMER, DISCARD, FILE, FILE_WITH_OPTION, STRING, STRING_WITH_CHARSET, } @BeforeTest public void setup() throws Exception { LightWeightHttpServer.initServer(); httpURI = LightWeightHttpServer.httproot + "echo/foo"; httpsURI = LightWeightHttpServer.httpsroot + "echo/foo"; SSLContext ctx = LightWeightHttpServer.ctx; client = HttpClient.newBuilder() .sslContext(ctx) .version(HttpClient.Version.HTTP_1_1) .followRedirects(HttpClient.Redirect.ALWAYS) .build(); } @AfterTest public void teardown() throws Exception { try { LightWeightHttpServer.stop(); } finally { System.out.println("RequestBodyTest: " + failures.size() + " failures"); int i = 0; for (String key: failures.keySet()) { System.out.println("test" + key + " failed: " + failures.get(key)); failures.get(key).printStackTrace(System.out); if (i++ > 3) { System.out.println("..... other failures not printed ...."); break; } } } } @DataProvider public Object[][] exchanges() throws Exception { List values = new ArrayList<>(); for (boolean async : new boolean[] { false, true }) for (String uri : new String[] { httpURI, httpsURI }) for (String file : new String[] { smallFilename, midSizedFilename }) for (RequestBody requestBodyType : RequestBody.values()) for (ResponseBody responseBodyType : ResponseBody.values()) for (boolean bufferResponseBody : new boolean[] { false, true }) values.add(new Object[] {uri, requestBodyType, responseBodyType, file, async, bufferResponseBody}); return values.stream().toArray(Object[][]::new); } @Test(dataProvider = "exchanges") void exchange(String target, RequestBody requestBodyType, ResponseBody responseBodyType, String file, boolean async, boolean bufferResponseBody) throws Exception { try { Path filePath = Paths.get(fileroot + file); URI uri = new URI(target); HttpRequest request = createRequest(uri, requestBodyType, filePath); checkResponse(client, request, requestBodyType, responseBodyType, filePath, async, bufferResponseBody); } catch (Exception | Error x) { Object[] params = new Object[] { target, requestBodyType, responseBodyType, file, "async=" + async, "buffer=" + bufferResponseBody }; failures.put(java.util.Arrays.toString(params), x); throw x; } } static final int DEFAULT_OFFSET = 10; static final int DEFAULT_LENGTH_FACTOR = 4/5; HttpRequest createRequest(URI uri, RequestBody requestBodyType, Path file) throws IOException { HttpRequest.Builder rb = HttpRequest.newBuilder(uri); String filename = file.toFile().getAbsolutePath(); byte[] fileAsBytes = getFileBytes(filename); String fileAsString = new String(fileAsBytes, UTF_8); switch (requestBodyType) { case BYTE_ARRAY: rb.POST(fromByteArray(fileAsBytes)); break; case BYTE_ARRAY_OFFSET: rb.POST(fromByteArray(fileAsBytes, DEFAULT_OFFSET, fileAsBytes.length * DEFAULT_LENGTH_FACTOR)); break; case BYTE_ARRAYS: Iterable iterable = Arrays.asList(fileAsBytes); rb.POST(fromByteArrays(iterable)); break; case FILE: rb.POST(fromFile(file)); break; case INPUTSTREAM: rb.POST(fromInputStream(fileInputStreamSupplier(file))); break; case STRING: rb.POST(fromString(fileAsString)); break; case STRING_WITH_CHARSET: rb.POST(fromString(new String(fileAsBytes), Charset.defaultCharset())); break; default: throw new AssertionError("Unknown request body:" + requestBodyType); } return rb.build(); } void checkResponse(HttpClient client, HttpRequest request, RequestBody requestBodyType, ResponseBody responseBodyType, Path file, boolean async, boolean bufferResponseBody) throws InterruptedException, IOException { String filename = file.toFile().getAbsolutePath(); byte[] fileAsBytes = getFileBytes(filename); if (requestBodyType == RequestBody.BYTE_ARRAY_OFFSET) { // Truncate the expected response body, if only a portion was sent int length = DEFAULT_OFFSET + (fileAsBytes.length * DEFAULT_LENGTH_FACTOR); fileAsBytes = Arrays.copyOfRange(fileAsBytes, DEFAULT_OFFSET, length); } String fileAsString = new String(fileAsBytes, UTF_8); Path tempFile = Paths.get("RequestBodyTest.tmp"); FileUtils.deleteFileIfExistsWithRetry(tempFile); switch (responseBodyType) { case BYTE_ARRAY: BodyHandler bh = asByteArray(); if (bufferResponseBody) bh = buffering(bh, 50); HttpResponse bar = getResponse(client, request, bh, async); assertEquals(bar.statusCode(), 200); assertEquals(bar.body(), fileAsBytes); break; case BYTE_ARRAY_CONSUMER: ByteArrayOutputStream baos = new ByteArrayOutputStream(); Consumer> consumer = o -> consumerBytes(o, baos); BodyHandler bh1 = asByteArrayConsumer(consumer); if (bufferResponseBody) bh1 = buffering(bh1, 49); HttpResponse v = getResponse(client, request, bh1, async); byte[] ba = baos.toByteArray(); assertEquals(v.statusCode(), 200); assertEquals(ba, fileAsBytes); break; case DISCARD: Object o = new Object(); BodyHandler bh2 = discard(o); if (bufferResponseBody) bh2 = buffering(bh2, 51); HttpResponse or = getResponse(client, request, bh2, async); assertEquals(or.statusCode(), 200); assertSame(or.body(), o); break; case FILE: BodyHandler bh3 = asFile(tempFile); if (bufferResponseBody) bh3 = buffering(bh3, 48); HttpResponse fr = getResponse(client, request, bh3, async); assertEquals(fr.statusCode(), 200); assertEquals(Files.size(tempFile), fileAsString.length()); assertEquals(Files.readAllBytes(tempFile), fileAsBytes); break; case FILE_WITH_OPTION: BodyHandler bh4 = asFile(tempFile, CREATE_NEW, WRITE); if (bufferResponseBody) bh4 = buffering(bh4, 52); fr = getResponse(client, request, bh4, async); assertEquals(fr.statusCode(), 200); assertEquals(Files.size(tempFile), fileAsString.length()); assertEquals(Files.readAllBytes(tempFile), fileAsBytes); break; case STRING: BodyHandler bh5 = asString(); if(bufferResponseBody) bh5 = buffering(bh5, 47); HttpResponse sr = getResponse(client, request, bh5, async); assertEquals(sr.statusCode(), 200); assertEquals(sr.body(), fileAsString); break; case STRING_WITH_CHARSET: BodyHandler bh6 = asString(StandardCharsets.UTF_8); if (bufferResponseBody) bh6 = buffering(bh6, 53); HttpResponse r = getResponse(client, request, bh6, async); assertEquals(r.statusCode(), 200); assertEquals(r.body(), fileAsString); break; default: throw new AssertionError("Unknown response body:" + responseBodyType); } } static HttpResponse getResponse(HttpClient client, HttpRequest request, HttpResponse.BodyHandler handler, boolean async) throws InterruptedException, IOException { if (!async) return client.send(request, handler); else return client.sendAsync(request, handler).join(); } static byte[] getFileBytes(String path) throws IOException { try (FileInputStream fis = new FileInputStream(path); BufferedInputStream bis = new BufferedInputStream(fis); ByteArrayOutputStream baos = new ByteArrayOutputStream()) { bis.transferTo(baos); return baos.toByteArray(); } } static Supplier fileInputStreamSupplier(Path f) { return new Supplier<>() { Path file = f; @Override public FileInputStream get() { try { return new FileInputStream(file.toFile()); } catch (FileNotFoundException x) { throw new UncheckedIOException(x); } } }; } static void consumerBytes(Optional bytes, ByteArrayOutputStream baos) { try { if (bytes.isPresent()) baos.write(bytes.get()); } catch (IOException x) { throw new UncheckedIOException(x); } } // --- /* Main entry point for standalone testing of the main functional test. */ public static void main(String... args) throws Exception { RequestBodyTest t = new RequestBodyTest(); t.setup(); int count = 0; try { for (Object[] objs : t.exchanges()) { count++; out.printf("********* iteration: %d %s %s %s %s %s %s *********%n", count, objs[0], objs[1], objs[2], objs[3], objs[4], objs[5]); t.exchange((String) objs[0], (RequestBody) objs[1], (ResponseBody) objs[2], (String) objs[3], (boolean) objs[4], (boolean) objs[5]); } } finally { t.teardown(); } } }