1 /* 2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test @bug 8087112 26 * @modules jdk.incubator.httpclient 27 * java.logging 28 * jdk.httpserver 29 * @library /lib/testlibrary/ /test/lib 30 * @compile ../../../com/sun/net/httpserver/LogFilter.java 31 * @compile ../../../com/sun/net/httpserver/FileServerHandler.java 32 * @build jdk.test.lib.util.FileUtils 33 * @build jdk.test.lib.Utils 34 * @build jdk.test.lib.Asserts 35 * @build jdk.test.lib.JDKToolFinder 36 * @build jdk.test.lib.JDKToolLauncher 37 * @build jdk.test.lib.Platform 38 * @build jdk.test.lib.process.* 39 * @build LightWeightHttpServer 40 * @build jdk.testlibrary.SimpleSSLContext 41 * @run testng/othervm RequestBodyTest 42 */ 43 44 import java.io.*; 45 import java.net.URI; 46 import jdk.incubator.http.HttpClient; 47 import jdk.incubator.http.HttpRequest; 48 import jdk.incubator.http.HttpResponse; 49 import java.nio.charset.Charset; 50 import java.nio.charset.StandardCharsets; 51 import java.nio.file.Files; 52 import java.nio.file.Path; 53 import java.nio.file.Paths; 54 import java.util.ArrayList; 55 import java.util.Arrays; 56 import java.util.List; 57 import java.util.Optional; 58 import java.util.concurrent.ExecutorService; 59 import java.util.concurrent.Executors; 60 import java.util.function.Supplier; 61 import javax.net.ssl.SSLContext; 62 import jdk.test.lib.util.FileUtils; 63 import static java.nio.charset.StandardCharsets.*; 64 import static java.nio.file.StandardOpenOption.*; 65 import static jdk.incubator.http.HttpRequest.BodyProcessor.*; 66 import static jdk.incubator.http.HttpResponse.BodyHandler.*; 67 68 import org.testng.annotations.AfterTest; 69 import org.testng.annotations.BeforeTest; 70 import org.testng.annotations.DataProvider; 71 import org.testng.annotations.Test; 72 import static org.testng.Assert.*; 73 74 public class RequestBodyTest { 75 76 static final String fileroot = System.getProperty("test.src") + "/docs"; 77 static final String midSizedFilename = "/files/notsobigfile.txt"; 78 static final String smallFilename = "/files/smallfile.txt"; 79 80 HttpClient client; 81 ExecutorService exec = Executors.newCachedThreadPool(); 82 String httpURI; 83 String httpsURI; 84 85 enum RequestBody { 86 BYTE_ARRAY, 87 BYTE_ARRAY_OFFSET, 88 BYTE_ARRAYS, 89 FILE, 90 INPUTSTREAM, 91 STRING, 92 STRING_WITH_CHARSET 93 } 94 95 enum ResponseBody { 96 BYTE_ARRAY, 97 BYTE_ARRAY_CONSUMER, 98 DISCARD, 99 FILE, 100 FILE_WITH_OPTION, 101 STRING, 102 STRING_WITH_CHARSET, 103 } 104 105 @BeforeTest 106 public void setup() throws Exception { 107 LightWeightHttpServer.initServer(); 108 httpURI = LightWeightHttpServer.httproot + "echo/foo"; 109 httpsURI = LightWeightHttpServer.httpsroot + "echo/foo"; 110 111 SSLContext ctx = LightWeightHttpServer.ctx; 112 client = HttpClient.newBuilder() 113 .sslContext(ctx) 114 .version(HttpClient.Version.HTTP_1_1) 115 .followRedirects(HttpClient.Redirect.ALWAYS) 116 .executor(exec) 117 .build(); 118 } 119 120 @AfterTest 121 public void teardown() throws Exception { 122 exec.shutdownNow(); 123 LightWeightHttpServer.stop(); 124 } 125 126 @DataProvider 127 public Object[][] exchanges() throws Exception { 128 List<Object[]> values = new ArrayList<>(); 129 130 for (boolean async : new boolean[] { false, true }) 131 for (String uri : new String[] { httpURI, httpsURI }) 132 for (String file : new String[] { smallFilename, midSizedFilename }) 133 for (RequestBody requestBodyType : RequestBody.values()) 134 for (ResponseBody responseBodyType : ResponseBody.values()) 135 values.add(new Object[] 136 {uri, requestBodyType, responseBodyType, file, async}); 137 138 return values.stream().toArray(Object[][]::new); 139 } 140 141 @Test(dataProvider = "exchanges") 142 void exchange(String target, 143 RequestBody requestBodyType, 144 ResponseBody responseBodyType, 145 String file, 146 boolean async) 147 throws Exception 148 { 149 Path filePath = Paths.get(fileroot + file); 150 URI uri = new URI(target); 151 152 HttpRequest request = createRequest(uri, requestBodyType, filePath); 153 154 checkResponse(client, request, requestBodyType, responseBodyType, filePath, async); 155 } 156 157 static final int DEFAULT_OFFSET = 10; 158 static final int DEFAULT_LENGTH = 1000; 159 160 HttpRequest createRequest(URI uri, 161 RequestBody requestBodyType, 162 Path file) 163 throws IOException 164 { 165 HttpRequest.Builder rb = HttpRequest.newBuilder(uri); 166 167 String filename = file.toFile().getAbsolutePath(); 168 byte[] fileAsBytes = getFileBytes(filename); 169 String fileAsString = new String(fileAsBytes, UTF_8); 170 171 switch (requestBodyType) { 172 case BYTE_ARRAY: 173 rb.POST(fromByteArray(fileAsBytes)); 174 break; 175 case BYTE_ARRAY_OFFSET: 176 rb.POST(fromByteArray(fileAsBytes, DEFAULT_OFFSET, DEFAULT_LENGTH)); 177 break; 178 case BYTE_ARRAYS: 179 Iterable<byte[]> iterable = Arrays.asList(fileAsBytes); 180 rb.POST(fromByteArrays(iterable)); 181 break; 182 case FILE: 183 rb.POST(fromFile(file)); 184 break; 185 case INPUTSTREAM: 186 rb.POST(fromInputStream(fileInputStreamSupplier(file))); 187 break; 188 case STRING: 189 rb.POST(fromString(fileAsString)); 190 break; 191 case STRING_WITH_CHARSET: 192 rb.POST(fromString(new String(fileAsBytes), Charset.defaultCharset())); 193 break; 194 default: 195 throw new AssertionError("Unknown request body:" + requestBodyType); 196 } 197 return rb.build(); 198 } 199 200 void checkResponse(HttpClient client, 201 HttpRequest request, 202 RequestBody requestBodyType, 203 ResponseBody responseBodyType, 204 Path file, 205 boolean async) 206 throws InterruptedException, IOException 207 { 208 String filename = file.toFile().getAbsolutePath(); 209 byte[] fileAsBytes = getFileBytes(filename); 210 if (requestBodyType == RequestBody.BYTE_ARRAY_OFFSET) { 211 // Truncate the expected response body, if only a portion was sent 212 fileAsBytes = Arrays.copyOfRange(fileAsBytes, 213 DEFAULT_OFFSET, 214 DEFAULT_OFFSET + DEFAULT_LENGTH); 215 } 216 String fileAsString = new String(fileAsBytes, UTF_8); 217 Path tempFile = Paths.get("RequestBodyTest.tmp"); 218 FileUtils.deleteFileIfExistsWithRetry(tempFile); 219 220 switch (responseBodyType) { 221 case BYTE_ARRAY: 222 HttpResponse<byte[]> bar = getResponse(client, request, asByteArray(), async); 223 assertEquals(bar.statusCode(), 200); 224 assertEquals(bar.body(), fileAsBytes); 225 break; 226 case BYTE_ARRAY_CONSUMER: 227 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 228 HttpResponse<Void> v = getResponse(client, request, 229 asByteArrayConsumer(o -> consumerBytes(o, baos) ), async); 230 byte[] ba = baos.toByteArray(); 231 assertEquals(v.statusCode(), 200); 232 assertEquals(ba, fileAsBytes); 233 break; 234 case DISCARD: 235 Object o = new Object(); 236 HttpResponse<Object> or = getResponse(client, request, discard(o), async); 237 assertEquals(or.statusCode(), 200); 238 assertSame(or.body(), o); 239 break; 240 case FILE: 241 HttpResponse<Path> fr = getResponse(client, request, asFile(tempFile), async); 242 assertEquals(fr.statusCode(), 200); 243 assertEquals(Files.size(tempFile), fileAsString.length()); 244 assertEquals(Files.readAllBytes(tempFile), fileAsBytes); 245 break; 246 case FILE_WITH_OPTION: 247 fr = getResponse(client, request, asFile(tempFile, CREATE_NEW, WRITE), async); 248 assertEquals(fr.statusCode(), 200); 249 assertEquals(Files.size(tempFile), fileAsString.length()); 250 assertEquals(Files.readAllBytes(tempFile), fileAsBytes); 251 break; 252 case STRING: 253 HttpResponse<String> sr = getResponse(client, request, asString(), async); 254 assertEquals(sr.statusCode(), 200); 255 assertEquals(sr.body(), fileAsString); 256 break; 257 case STRING_WITH_CHARSET: 258 HttpResponse<String> r = getResponse(client, request, asString(StandardCharsets.UTF_8), async); 259 assertEquals(r.statusCode(), 200); 260 assertEquals(r.body(), fileAsString); 261 break; 262 default: 263 throw new AssertionError("Unknown response body:" + responseBodyType); 264 } 265 } 266 267 static <T> HttpResponse<T> getResponse(HttpClient client, 268 HttpRequest request, 269 HttpResponse.BodyHandler<T> handler, 270 boolean async) 271 throws InterruptedException, IOException 272 { 273 if (!async) 274 return client.send(request, handler); 275 else 276 return client.sendAsync(request, handler).join(); 277 } 278 279 static byte[] getFileBytes(String path) throws IOException { 280 try (FileInputStream fis = new FileInputStream(path); 281 BufferedInputStream bis = new BufferedInputStream(fis); 282 ByteArrayOutputStream baos = new ByteArrayOutputStream()) { 283 bis.transferTo(baos); 284 return baos.toByteArray(); 285 } 286 } 287 288 static Supplier<FileInputStream> fileInputStreamSupplier(Path f) { 289 return new Supplier<>() { 290 Path file = f; 291 @Override 292 public FileInputStream get() { 293 try { 294 return new FileInputStream(file.toFile()); 295 } catch (FileNotFoundException x) { 296 throw new UncheckedIOException(x); 297 } 298 } 299 }; 300 } 301 302 static void consumerBytes(Optional<byte[]> bytes, ByteArrayOutputStream baos) { 303 try { 304 if (bytes.isPresent()) 305 baos.write(bytes.get()); 306 } catch (IOException x) { 307 throw new UncheckedIOException(x); 308 } 309 } 310 }