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