1 /* 2 * Copyright (c) 2018, 2020, 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 import java.io.BufferedReader; 25 import java.io.ByteArrayOutputStream; 26 import java.io.IOException; 27 import java.io.PrintStream; 28 import java.io.StringReader; 29 import java.io.UncheckedIOException; 30 import java.math.BigInteger; 31 import java.net.InetAddress; 32 import java.net.InetSocketAddress; 33 import java.net.URI; 34 import java.net.http.HttpClient; 35 import java.net.http.HttpClient.Builder; 36 import java.net.http.HttpRequest; 37 import java.net.http.HttpRequest.BodyPublishers; 38 import java.net.http.HttpResponse; 39 import java.net.http.HttpResponse.BodyHandlers; 40 import java.net.http.HttpResponse.BodySubscribers; 41 import java.nio.charset.Charset; 42 import java.nio.charset.StandardCharsets; 43 import java.util.ArrayList; 44 import java.util.List; 45 import java.util.concurrent.CompletableFuture; 46 import java.util.concurrent.CopyOnWriteArrayList; 47 import java.util.concurrent.ExecutorService; 48 import java.util.concurrent.Executors; 49 import java.util.concurrent.Flow; 50 import java.util.concurrent.ThreadFactory; 51 import java.util.concurrent.atomic.AtomicInteger; 52 import java.util.function.Function; 53 import java.util.function.Supplier; 54 import java.util.stream.Collectors; 55 import java.util.stream.Stream; 56 import javax.net.ssl.SSLContext; 57 import com.sun.net.httpserver.HttpServer; 58 import com.sun.net.httpserver.HttpsConfigurator; 59 import com.sun.net.httpserver.HttpsServer; 60 import jdk.test.lib.net.SimpleSSLContext; 61 import org.testng.annotations.AfterTest; 62 import org.testng.annotations.BeforeTest; 63 import org.testng.annotations.DataProvider; 64 import org.testng.annotations.Test; 65 66 import static java.nio.charset.StandardCharsets.UTF_16; 67 import static java.nio.charset.StandardCharsets.UTF_8; 68 import static java.net.http.HttpRequest.BodyPublishers.ofString; 69 import static org.testng.Assert.assertEquals; 70 import static org.testng.Assert.assertNotNull; 71 import static org.testng.Assert.assertThrows; 72 import static org.testng.Assert.assertTrue; 73 74 /* 75 * @test 76 * @summary Basic tests for line adapter subscribers as created by 77 * the BodyHandlers returned by BodyHandler::fromLineSubscriber 78 * and BodyHandler::asLines 79 * @bug 8256459 80 * @modules java.base/sun.net.www.http 81 * java.net.http/jdk.internal.net.http.common 82 * java.net.http/jdk.internal.net.http.frame 83 * java.net.http/jdk.internal.net.http.hpack 84 * java.logging 85 * jdk.httpserver 86 * @library /test/lib http2/server 87 * @build Http2TestServer LineBodyHandlerTest HttpServerAdapters 88 * @build jdk.test.lib.net.SimpleSSLContext 89 * @run testng/othervm LineBodyHandlerTest 90 */ 91 92 public class LineBodyHandlerTest implements HttpServerAdapters { 93 94 SSLContext sslContext; 95 HttpTestServer httpTestServer; // HTTP/1.1 [ 4 servers ] 96 HttpTestServer httpsTestServer; // HTTPS/1.1 97 HttpTestServer http2TestServer; // HTTP/2 ( h2c ) 98 HttpTestServer https2TestServer; // HTTP/2 ( h2 ) 99 String httpURI; 100 String httpsURI; 101 String http2URI; 102 String https2URI; 103 104 @DataProvider(name = "uris") variants()105 public Object[][] variants() { 106 return new Object[][]{ 107 { httpURI }, 108 { httpsURI }, 109 { http2URI }, 110 { https2URI }, 111 }; 112 } 113 114 static final Class<NullPointerException> NPE = NullPointerException.class; 115 static final Class<IllegalArgumentException> IAE = IllegalArgumentException.class; 116 117 @Test testNull()118 public void testNull() { 119 assertThrows(NPE, () -> BodyHandlers.fromLineSubscriber(null)); 120 assertNotNull(BodyHandlers.fromLineSubscriber(new StringSubscriber())); 121 assertThrows(NPE, () -> BodyHandlers.fromLineSubscriber(null, Function.identity(), "\n")); 122 assertThrows(NPE, () -> BodyHandlers.fromLineSubscriber(new StringSubscriber(), null, "\n")); 123 assertNotNull(BodyHandlers.fromLineSubscriber(new StringSubscriber(), Function.identity(), null)); 124 assertThrows(NPE, () -> BodyHandlers.fromLineSubscriber(null, null, "\n")); 125 assertThrows(NPE, () -> BodyHandlers.fromLineSubscriber(null, Function.identity(), null)); 126 assertThrows(NPE, () -> BodyHandlers.fromLineSubscriber(new StringSubscriber(), null, null)); 127 128 assertThrows(NPE, () -> BodySubscribers.fromLineSubscriber(null)); 129 assertThrows(NPE, () -> BodySubscribers.fromLineSubscriber(null, Function.identity(), 130 Charset.defaultCharset(), System.lineSeparator())); 131 assertThrows(NPE, () -> BodySubscribers.fromLineSubscriber(new StringSubscriber(), null, 132 Charset.defaultCharset(), System.lineSeparator())); 133 assertThrows(NPE, () -> BodySubscribers.fromLineSubscriber(new StringSubscriber(), Function.identity(), 134 null, System.lineSeparator())); 135 assertNotNull(BodySubscribers.fromLineSubscriber(new StringSubscriber(), Function.identity(), 136 Charset.defaultCharset(), null)); 137 assertThrows(NPE, () -> BodySubscribers.fromLineSubscriber(null, null, 138 Charset.defaultCharset(), System.lineSeparator())); 139 assertThrows(NPE, () -> BodySubscribers.fromLineSubscriber(null, Function.identity(), 140 null, System.lineSeparator())); 141 assertThrows(NPE, () -> BodySubscribers.fromLineSubscriber(null, Function.identity(), 142 Charset.defaultCharset(), null)); 143 assertThrows(NPE, () -> BodySubscribers.fromLineSubscriber(new StringSubscriber(), null, 144 null, System.lineSeparator())); 145 assertThrows(NPE, () -> BodySubscribers.fromLineSubscriber(new StringSubscriber(), null, 146 Charset.defaultCharset(), null)); 147 assertThrows(NPE, () -> BodySubscribers.fromLineSubscriber(new StringSubscriber(), Function.identity(), 148 null, null)); 149 assertThrows(NPE, () -> BodySubscribers.fromLineSubscriber(new StringSubscriber(), null, null, null)); 150 assertThrows(NPE, () -> BodySubscribers.fromLineSubscriber(null, Function.identity(), 151 null, null)); 152 assertThrows(NPE, () -> BodySubscribers.fromLineSubscriber(null, null, 153 Charset.defaultCharset(), null)); 154 assertThrows(NPE, () -> BodySubscribers.fromLineSubscriber(null, null, 155 null, System.lineSeparator())); 156 assertThrows(NPE, () -> BodySubscribers.fromLineSubscriber(null, null, null, null)); 157 } 158 159 @Test testIAE()160 public void testIAE() { 161 assertThrows(IAE, () -> BodyHandlers.fromLineSubscriber(new StringSubscriber(), Function.identity(),"")); 162 assertThrows(IAE, () -> BodyHandlers.fromLineSubscriber(new CharSequenceSubscriber(), Function.identity(),"")); 163 assertThrows(IAE, () -> BodyHandlers.fromLineSubscriber(new ObjectSubscriber(), Function.identity(), "")); 164 assertThrows(IAE, () -> BodySubscribers.fromLineSubscriber(new StringSubscriber(), Function.identity(), 165 StandardCharsets.UTF_8, "")); 166 assertThrows(IAE, () -> BodySubscribers.fromLineSubscriber(new CharSequenceSubscriber(), Function.identity(), 167 StandardCharsets.UTF_16, "")); 168 assertThrows(IAE, () -> BodySubscribers.fromLineSubscriber(new ObjectSubscriber(), Function.identity(), 169 StandardCharsets.US_ASCII, "")); 170 } 171 lines(String text, String eol)172 private static final List<String> lines(String text, String eol) { 173 if (eol == null) { 174 return new BufferedReader(new StringReader(text)).lines().collect(Collectors.toList()); 175 } else { 176 String replaced = text.replace(eol, "|"); 177 int i=0; 178 while(replaced.endsWith("||")) { 179 replaced = replaced.substring(0,replaced.length()-1); 180 i++; 181 } 182 List<String> res = List.of(replaced.split("\\|")); 183 if (i > 0) { 184 res = new ArrayList<>(res); 185 for (int j=0; j<i; j++) res.add(""); 186 } 187 return res; 188 } 189 } 190 newClient()191 HttpClient newClient() { 192 return HttpClient.newBuilder() 193 .sslContext(sslContext) 194 .proxy(Builder.NO_PROXY) 195 .build(); 196 } 197 198 @Test(dataProvider = "uris") testStringWithFinisher(String url)199 void testStringWithFinisher(String url) { 200 String body = "May the luck of the Irish be with you!"; 201 HttpClient client = newClient(); 202 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 203 .POST(BodyPublishers.ofString(body)) 204 .build(); 205 206 StringSubscriber subscriber = new StringSubscriber(); 207 CompletableFuture<HttpResponse<String>> cf 208 = client.sendAsync(request, BodyHandlers.fromLineSubscriber( 209 subscriber, Supplier::get, "\n")); 210 assertNoObtrusion(cf); 211 HttpResponse<String> response = cf.join(); 212 String text = response.body(); 213 System.out.println(text); 214 assertEquals(response.statusCode(), 200); 215 assertEquals(text, body); 216 assertEquals(subscriber.list, lines(body, "\n")); 217 } 218 219 @Test(dataProvider = "uris") testAsStream(String url)220 void testAsStream(String url) { 221 String body = "May the luck of the Irish be with you!"; 222 HttpClient client = newClient(); 223 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 224 .POST(BodyPublishers.ofString(body)) 225 .build(); 226 227 CompletableFuture<HttpResponse<Stream<String>>> cf 228 = client.sendAsync(request, BodyHandlers.ofLines()); 229 assertNoObtrusion(cf); 230 HttpResponse<Stream<String>> response = cf.join(); 231 Stream<String> stream = response.body(); 232 List<String> list = stream.collect(Collectors.toList()); 233 String text = list.stream().collect(Collectors.joining("|")); 234 System.out.println(text); 235 assertEquals(response.statusCode(), 200); 236 assertEquals(text, body); 237 assertEquals(list, List.of(body)); 238 assertEquals(list, lines(body, null)); 239 } 240 241 @Test(dataProvider = "uris") testStringWithFinisher2(String url)242 void testStringWithFinisher2(String url) { 243 String body = "May the luck\r\n\r\n of the Irish be with you!"; 244 HttpClient client = newClient(); 245 246 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 247 .POST(BodyPublishers.ofString(body)) 248 .build(); 249 250 StringSubscriber subscriber = new StringSubscriber(); 251 CompletableFuture<HttpResponse<Void>> cf 252 = client.sendAsync(request, 253 BodyHandlers.fromLineSubscriber(subscriber)); 254 assertNoObtrusion(cf); 255 HttpResponse<Void> response = cf.join(); 256 String text = subscriber.get(); 257 System.out.println(text); 258 assertEquals(response.statusCode(), 200); 259 assertEquals(text, body.replace("\r\n", "\n")); 260 assertEquals(subscriber.list, lines(body, null)); 261 } 262 263 @Test(dataProvider = "uris") testAsStreamWithCRLF(String url)264 void testAsStreamWithCRLF(String url) { 265 String body = "May the luck\r\n\r\n of the Irish be with you!"; 266 HttpClient client = newClient(); 267 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 268 .POST(BodyPublishers.ofString(body)) 269 .build(); 270 271 CompletableFuture<HttpResponse<Stream<String>>> cf 272 = client.sendAsync(request, BodyHandlers.ofLines()); 273 assertNoObtrusion(cf); 274 HttpResponse<Stream<String>> response = cf.join(); 275 Stream<String> stream = response.body(); 276 List<String> list = stream.collect(Collectors.toList()); 277 String text = list.stream().collect(Collectors.joining("|")); 278 System.out.println(text); 279 assertEquals(response.statusCode(), 200); 280 assertEquals(text, "May the luck|| of the Irish be with you!"); 281 assertEquals(list, List.of("May the luck", 282 "", 283 " of the Irish be with you!")); 284 assertEquals(list, lines(body, null)); 285 } 286 287 @Test(dataProvider = "uris") testStringWithFinisherBlocking(String url)288 void testStringWithFinisherBlocking(String url) throws Exception { 289 String body = "May the luck of the Irish be with you!"; 290 HttpClient client = newClient(); 291 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 292 .POST(BodyPublishers.ofString(body)).build(); 293 294 StringSubscriber subscriber = new StringSubscriber(); 295 HttpResponse<String> response = client.send(request, 296 BodyHandlers.fromLineSubscriber(subscriber, Supplier::get, "\n")); 297 String text = response.body(); 298 System.out.println(text); 299 assertEquals(response.statusCode(), 200); 300 assertEquals(text, "May the luck of the Irish be with you!"); 301 assertEquals(subscriber.list, lines(body, "\n")); 302 } 303 304 @Test(dataProvider = "uris") testStringWithoutFinisherBlocking(String url)305 void testStringWithoutFinisherBlocking(String url) throws Exception { 306 String body = "May the luck of the Irish be with you!"; 307 HttpClient client = newClient(); 308 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 309 .POST(BodyPublishers.ofString(body)).build(); 310 311 StringSubscriber subscriber = new StringSubscriber(); 312 HttpResponse<Void> response = client.send(request, 313 BodyHandlers.fromLineSubscriber(subscriber)); 314 String text = subscriber.get(); 315 System.out.println(text); 316 assertEquals(response.statusCode(), 200); 317 assertEquals(text, "May the luck of the Irish be with you!"); 318 assertEquals(subscriber.list, lines(body, null)); 319 } 320 321 // Subscriber<Object> 322 323 @Test(dataProvider = "uris") testAsStreamWithMixedCRLF(String url)324 void testAsStreamWithMixedCRLF(String url) { 325 String body = "May\r\n the wind\r\n always be\rat your back.\r\r"; 326 HttpClient client = newClient(); 327 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 328 .POST(BodyPublishers.ofString(body)) 329 .build(); 330 331 CompletableFuture<HttpResponse<Stream<String>>> cf 332 = client.sendAsync(request, BodyHandlers.ofLines()); 333 assertNoObtrusion(cf); 334 HttpResponse<Stream<String>> response = cf.join(); 335 Stream<String> stream = response.body(); 336 List<String> list = stream.collect(Collectors.toList()); 337 String text = list.stream().collect(Collectors.joining("|")); 338 System.out.println(text); 339 assertEquals(response.statusCode(), 200); 340 assertTrue(text.length() != 0); // what else can be asserted! 341 assertEquals(text, "May| the wind| always be|at your back.|"); 342 assertEquals(list, List.of("May", 343 " the wind", 344 " always be", 345 "at your back.", 346 "")); 347 assertEquals(list, lines(body, null)); 348 } 349 350 @Test(dataProvider = "uris") testAsStreamWithMixedCRLF_UTF8(String url)351 void testAsStreamWithMixedCRLF_UTF8(String url) { 352 String body = "May\r\n the wind\r\n always be\rat your back.\r\r"; 353 HttpClient client = newClient(); 354 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 355 .header("Content-type", "text/text; charset=UTF-8") 356 .POST(BodyPublishers.ofString(body, UTF_8)).build(); 357 358 CompletableFuture<HttpResponse<Stream<String>>> cf 359 = client.sendAsync(request, BodyHandlers.ofLines()); 360 assertNoObtrusion(cf); 361 HttpResponse<Stream<String>> response = cf.join(); 362 Stream<String> stream = response.body(); 363 List<String> list = stream.collect(Collectors.toList()); 364 String text = list.stream().collect(Collectors.joining("|")); 365 System.out.println(text); 366 assertEquals(response.statusCode(), 200); 367 assertTrue(text.length() != 0); // what else can be asserted! 368 assertEquals(text, "May| the wind| always be|at your back.|"); 369 assertEquals(list, List.of("May", 370 " the wind", 371 " always be", 372 "at your back.", "")); 373 assertEquals(list, lines(body, null)); 374 } 375 376 @Test(dataProvider = "uris") testAsStreamWithMixedCRLF_UTF16(String url)377 void testAsStreamWithMixedCRLF_UTF16(String url) { 378 String body = "May\r\n the wind\r\n always be\rat your back.\r\r"; 379 HttpClient client = newClient(); 380 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 381 .header("Content-type", "text/text; charset=UTF-16") 382 .POST(BodyPublishers.ofString(body, UTF_16)).build(); 383 384 CompletableFuture<HttpResponse<Stream<String>>> cf 385 = client.sendAsync(request, BodyHandlers.ofLines()); 386 assertNoObtrusion(cf); 387 HttpResponse<Stream<String>> response = cf.join(); 388 Stream<String> stream = response.body(); 389 List<String> list = stream.collect(Collectors.toList()); 390 String text = list.stream().collect(Collectors.joining("|")); 391 System.out.println(text); 392 assertEquals(response.statusCode(), 200); 393 assertTrue(text.length() != 0); // what else can be asserted! 394 assertEquals(text, "May| the wind| always be|at your back.|"); 395 assertEquals(list, List.of("May", 396 " the wind", 397 " always be", 398 "at your back.", 399 "")); 400 assertEquals(list, lines(body, null)); 401 } 402 403 @Test(dataProvider = "uris") testObjectWithFinisher(String url)404 void testObjectWithFinisher(String url) { 405 String body = "May\r\n the wind\r\n always be\rat your back."; 406 HttpClient client = newClient(); 407 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 408 .POST(BodyPublishers.ofString(body)) 409 .build(); 410 411 ObjectSubscriber subscriber = new ObjectSubscriber(); 412 CompletableFuture<HttpResponse<String>> cf 413 = client.sendAsync(request, BodyHandlers.fromLineSubscriber( 414 subscriber, ObjectSubscriber::get, "\r\n")); 415 assertNoObtrusion(cf); 416 HttpResponse<String> response = cf.join(); 417 String text = response.body(); 418 System.out.println(text); 419 assertEquals(response.statusCode(), 200); 420 assertTrue(text.length() != 0); // what else can be asserted! 421 assertEquals(text, "May\n the wind\n always be\rat your back."); 422 assertEquals(subscriber.list, List.of("May", 423 " the wind", 424 " always be\rat your back.")); 425 assertEquals(subscriber.list, lines(body, "\r\n")); 426 } 427 428 @Test(dataProvider = "uris") testObjectWithFinisher_UTF16(String url)429 void testObjectWithFinisher_UTF16(String url) { 430 String body = "May\r\n the wind\r\n always be\rat your back.\r\r"; 431 HttpClient client = newClient(); 432 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 433 .header("Content-type", "text/text; charset=UTF-16") 434 .POST(BodyPublishers.ofString(body, UTF_16)).build(); 435 ObjectSubscriber subscriber = new ObjectSubscriber(); 436 CompletableFuture<HttpResponse<String>> cf 437 = client.sendAsync(request, BodyHandlers.fromLineSubscriber( 438 subscriber, ObjectSubscriber::get, null)); 439 assertNoObtrusion(cf); 440 HttpResponse<String> response = cf.join(); 441 String text = response.body(); 442 System.out.println(text); 443 assertEquals(response.statusCode(), 200); 444 assertTrue(text.length() != 0); // what else can be asserted! 445 assertEquals(text, "May\n the wind\n always be\nat your back.\n"); 446 assertEquals(subscriber.list, List.of("May", 447 " the wind", 448 " always be", 449 "at your back.", 450 "")); 451 assertEquals(subscriber.list, lines(body, null)); 452 } 453 454 @Test(dataProvider = "uris") testObjectWithoutFinisher(String url)455 void testObjectWithoutFinisher(String url) { 456 String body = "May\r\n the wind\r\n always be\rat your back."; 457 HttpClient client = newClient(); 458 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 459 .POST(BodyPublishers.ofString(body)) 460 .build(); 461 462 ObjectSubscriber subscriber = new ObjectSubscriber(); 463 CompletableFuture<HttpResponse<Void>> cf 464 = client.sendAsync(request, 465 BodyHandlers.fromLineSubscriber(subscriber)); 466 assertNoObtrusion(cf); 467 HttpResponse<Void> response = cf.join(); 468 String text = subscriber.get(); 469 System.out.println(text); 470 assertEquals(response.statusCode(), 200); 471 assertTrue(text.length() != 0); // what else can be asserted! 472 assertEquals(text, "May\n the wind\n always be\nat your back."); 473 assertEquals(subscriber.list, List.of("May", 474 " the wind", 475 " always be", 476 "at your back.")); 477 assertEquals(subscriber.list, lines(body, null)); 478 } 479 480 @Test(dataProvider = "uris") testObjectWithFinisherBlocking(String url)481 void testObjectWithFinisherBlocking(String url) throws Exception { 482 String body = "May\r\n the wind\r\n always be\nat your back."; 483 HttpClient client = newClient(); 484 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 485 .POST(BodyPublishers.ofString(body)) 486 .build(); 487 488 ObjectSubscriber subscriber = new ObjectSubscriber(); 489 HttpResponse<String> response = client.send(request, 490 BodyHandlers.fromLineSubscriber(subscriber, 491 ObjectSubscriber::get, 492 "\r\n")); 493 String text = response.body(); 494 System.out.println(text); 495 assertEquals(response.statusCode(), 200); 496 assertTrue(text.length() != 0); // what else can be asserted! 497 assertEquals(text, "May\n the wind\n always be\nat your back."); 498 assertEquals(subscriber.list, List.of("May", 499 " the wind", 500 " always be\nat your back.")); 501 assertEquals(subscriber.list, lines(body, "\r\n")); 502 } 503 504 @Test(dataProvider = "uris") testObjectWithoutFinisherBlocking(String url)505 void testObjectWithoutFinisherBlocking(String url) throws Exception { 506 String body = "May\r\n the wind\r\n always be\nat your back."; 507 HttpClient client = newClient(); 508 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 509 .POST(BodyPublishers.ofString(body)) 510 .build(); 511 512 ObjectSubscriber subscriber = new ObjectSubscriber(); 513 HttpResponse<Void> response = client.send(request, 514 BodyHandlers.fromLineSubscriber(subscriber)); 515 String text = subscriber.get(); 516 System.out.println(text); 517 assertEquals(response.statusCode(), 200); 518 assertTrue(text.length() != 0); // what else can be asserted! 519 assertEquals(text, "May\n the wind\n always be\nat your back."); 520 assertEquals(subscriber.list, List.of("May", 521 " the wind", 522 " always be", 523 "at your back.")); 524 assertEquals(subscriber.list, lines(body, null)); 525 } 526 527 static private final String LINE = "Bient\u00f4t nous plongerons dans les" + 528 " fr\u00f4\ud801\udc00des t\u00e9n\u00e8bres, "; 529 bigtext()530 static private final String bigtext() { 531 StringBuilder res = new StringBuilder((LINE.length() + 1) * 50); 532 for (int i = 0; i<50; i++) { 533 res.append(LINE); 534 if (i%2 == 0) res.append("\r\n"); 535 } 536 return res.toString(); 537 } 538 539 @Test(dataProvider = "uris") testBigTextFromLineSubscriber(String url)540 void testBigTextFromLineSubscriber(String url) { 541 HttpClient client = newClient(); 542 String bigtext = bigtext(); 543 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 544 .POST(BodyPublishers.ofString(bigtext)) 545 .build(); 546 547 StringSubscriber subscriber = new StringSubscriber(); 548 CompletableFuture<HttpResponse<String>> cf 549 = client.sendAsync(request, BodyHandlers.fromLineSubscriber( 550 subscriber, Supplier::get, "\r\n")); 551 assertNoObtrusion(cf); 552 HttpResponse<String> response = cf.join(); 553 String text = response.body(); 554 System.out.println(text); 555 assertEquals(response.statusCode(), 200); 556 assertEquals(text, bigtext.replace("\r\n", "\n")); 557 assertEquals(subscriber.list, lines(bigtext, "\r\n")); 558 } 559 560 @Test(dataProvider = "uris") testBigTextAsStream(String url)561 void testBigTextAsStream(String url) { 562 HttpClient client = newClient(); 563 String bigtext = bigtext(); 564 HttpRequest request = HttpRequest.newBuilder(URI.create(url)) 565 .POST(BodyPublishers.ofString(bigtext)) 566 .build(); 567 568 CompletableFuture<HttpResponse<Stream<String>>> cf 569 = client.sendAsync(request, BodyHandlers.ofLines()); 570 assertNoObtrusion(cf); 571 HttpResponse<Stream<String>> response = cf.join(); 572 Stream<String> stream = response.body(); 573 List<String> list = stream.collect(Collectors.toList()); 574 String text = list.stream().collect(Collectors.joining("|")); 575 System.out.println(text); 576 assertEquals(response.statusCode(), 200); 577 assertEquals(text, bigtext.replace("\r\n", "|")); 578 assertEquals(list, List.of(bigtext.split("\r\n"))); 579 assertEquals(list, lines(bigtext, null)); 580 } 581 582 /** An abstract Subscriber that converts all received data into a String. */ 583 static abstract class AbstractSubscriber implements Supplier<String> { 584 protected volatile Flow.Subscription subscription; 585 protected final StringBuilder baos = new StringBuilder(); 586 protected volatile String text; 587 protected volatile RuntimeException error; 588 protected final List<Object> list = new CopyOnWriteArrayList<>(); 589 onSubscribe(Flow.Subscription subscription)590 public void onSubscribe(Flow.Subscription subscription) { 591 this.subscription = subscription; 592 subscription.request(Long.MAX_VALUE); 593 } onError(Throwable throwable)594 public void onError(Throwable throwable) { 595 System.out.println(this + " onError: " + throwable); 596 error = new RuntimeException(throwable); 597 } onComplete()598 public void onComplete() { 599 System.out.println(this + " onComplete"); 600 text = baos.toString(); 601 } get()602 @Override public String get() { 603 if (error != null) throw error; 604 return text; 605 } 606 } 607 608 static class StringSubscriber extends AbstractSubscriber 609 implements Flow.Subscriber<String>, Supplier<String> 610 { onNext(String item)611 @Override public void onNext(String item) { 612 System.out.print(this + " onNext: \"" + item + "\""); 613 if (baos.length() != 0) baos.append('\n'); 614 baos.append(item); 615 list.add(item); 616 } 617 } 618 619 static class CharSequenceSubscriber extends AbstractSubscriber 620 implements Flow.Subscriber<CharSequence>, Supplier<String> 621 { onNext(CharSequence item)622 @Override public void onNext(CharSequence item) { 623 System.out.print(this + " onNext: " + item); 624 if (baos.length() != 0) baos.append('\n'); 625 baos.append(item); 626 list.add(item); 627 } 628 } 629 630 static class ObjectSubscriber extends AbstractSubscriber 631 implements Flow.Subscriber<Object>, Supplier<String> 632 { onNext(Object item)633 @Override public void onNext(Object item) { 634 System.out.print(this + " onNext: " + item); 635 if (baos.length() != 0) baos.append('\n'); 636 baos.append(item); 637 list.add(item); 638 } 639 } 640 641 uncheckedWrite(ByteArrayOutputStream baos, byte[] ba)642 static void uncheckedWrite(ByteArrayOutputStream baos, byte[] ba) { 643 try { 644 baos.write(ba); 645 } catch (IOException e) { 646 throw new UncheckedIOException(e); 647 } 648 } 649 executorFor(String serverThreadName)650 private static ExecutorService executorFor(String serverThreadName) { 651 ThreadFactory factory = new ThreadFactory() { 652 final AtomicInteger counter = new AtomicInteger(); 653 @Override 654 public Thread newThread(Runnable r) { 655 Thread thread = new Thread(r); 656 thread.setName(serverThreadName + "#" + counter.incrementAndGet()); 657 return thread; 658 } 659 }; 660 return Executors.newCachedThreadPool(factory); 661 } 662 663 @BeforeTest setup()664 public void setup() throws Exception { 665 sslContext = new SimpleSSLContext().get(); 666 if (sslContext == null) 667 throw new AssertionError("Unexpected null sslContext"); 668 669 InetSocketAddress sa = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); 670 httpTestServer = HttpTestServer.of(HttpServer.create(sa, 0), 671 executorFor("HTTP/1.1 Server Thread")); 672 httpTestServer.addHandler(new HttpTestEchoHandler(), "/http1/echo"); 673 httpURI = "http://" + httpTestServer.serverAuthority() + "/http1/echo"; 674 675 HttpsServer httpsServer = HttpsServer.create(sa, 0); 676 httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext)); 677 httpsTestServer = HttpTestServer.of(httpsServer, 678 executorFor("HTTPS/1.1 Server Thread")); 679 httpsTestServer.addHandler(new HttpTestEchoHandler(),"/https1/echo"); 680 httpsURI = "https://" + httpsTestServer.serverAuthority() + "/https1/echo"; 681 682 http2TestServer = HttpTestServer.of(new Http2TestServer("localhost", false, 0)); 683 http2TestServer.addHandler(new HttpTestEchoHandler(), "/http2/echo"); 684 http2URI = "http://" + http2TestServer.serverAuthority() + "/http2/echo"; 685 686 https2TestServer = HttpTestServer.of(new Http2TestServer("localhost", true, sslContext)); 687 https2TestServer.addHandler(new HttpTestEchoHandler(), "/https2/echo"); 688 https2URI = "https://" + https2TestServer.serverAuthority() + "/https2/echo"; 689 690 httpTestServer.start(); 691 httpsTestServer.start(); 692 http2TestServer.start(); 693 https2TestServer.start(); 694 } 695 696 @AfterTest teardown()697 public void teardown() throws Exception { 698 httpTestServer.stop(); 699 httpsTestServer.stop(); 700 http2TestServer.stop(); 701 https2TestServer.stop(); 702 } 703 printBytes(PrintStream out, String prefix, byte[] bytes)704 static void printBytes(PrintStream out, String prefix, byte[] bytes) { 705 int padding = 4 + 4 - (bytes.length % 4); 706 padding = padding > 4 ? padding - 4 : 4; 707 byte[] bigbytes = new byte[bytes.length + padding]; 708 System.arraycopy(bytes, 0, bigbytes, padding, bytes.length); 709 out.println(prefix + bytes.length + " " 710 + new BigInteger(bigbytes).toString(16)); 711 } 712 assertNoObtrusion(CompletableFuture<?> cf)713 private static void assertNoObtrusion(CompletableFuture<?> cf) { 714 assertThrows(UnsupportedOperationException.class, 715 () -> cf.obtrudeException(new RuntimeException())); 716 assertThrows(UnsupportedOperationException.class, 717 () -> cf.obtrudeValue(null)); 718 } 719 } 720