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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.incubator.http; 27 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.net.URI; 31 import jdk.incubator.http.ResponseSubscribers.MultiSubscriberImpl; 32 import static jdk.incubator.http.internal.common.Utils.unchecked; 33 import static jdk.incubator.http.internal.common.Utils.charsetFrom; 34 import java.nio.ByteBuffer; 35 import java.nio.charset.Charset; 36 import java.nio.channels.FileChannel; 37 import java.nio.file.OpenOption; 38 import java.nio.file.Path; 39 import java.nio.file.Paths; 40 import java.nio.file.StandardOpenOption; 41 import java.security.AccessControlContext; 42 import java.util.Arrays; 43 import java.util.List; 44 import java.util.Objects; 45 import java.util.Optional; 46 import java.util.concurrent.CompletableFuture; 47 import java.util.concurrent.CompletionStage; 48 import java.util.concurrent.Flow; 49 import java.util.function.Consumer; 50 import java.util.function.Function; 51 import javax.net.ssl.SSLParameters; 52 53 /** 54 * Represents a response to a {@link HttpRequest}. 55 * {@Incubating} 56 * 57 * <p> A {@code HttpResponse} is available when the response status code and 58 * headers have been received, and typically after the response body has also 59 * been received. This depends on the response body handler provided when 60 * sending the request. In all cases, the response body handler is invoked 61 * before the body is read. This gives applications an opportunity to decide 62 * how to handle the body. 63 * 64 * <p> Methods are provided in this class for accessing the response headers, 65 * and response body. 66 * 67 * <p><b>Response handlers and subscribers</b> 68 * 69 * <p> Response bodies are handled at two levels. Application code supplies a 70 * response handler ({@link BodyHandler}) which may examine the response status 71 * code and headers, and which then returns a {@link BodySubscriber} to actually 72 * read (or discard) the body and convert it into some useful Java object type. 73 * The handler can return one of the pre-defined subscriber types, or a custom 74 * subscriber, or if the body is to be discarded it can call {@link 75 * BodySubscriber#discard(Object) discard} and return a subscriber which 76 * discards the response body. Static implementations of both handlers and 77 * subscribers are provided in {@linkplain BodyHandler BodyHandler} and 78 * {@linkplain BodySubscriber BodySubscriber} respectively. In all cases, the 79 * handler functions provided are convenience implementations which ignore the 80 * supplied status code and headers and return the relevant pre-defined {@code 81 * BodySubscriber}. 82 * 83 * <p> See {@link BodyHandler} for example usage. 84 * 85 * @param <T> the response body type 86 * @since 9 87 */ 88 public abstract class HttpResponse<T> { 89 90 /** 91 * Creates an HttpResponse. 92 */ 93 protected HttpResponse() { } 94 95 /** 96 * Returns the status code for this response. 97 * 98 * @return the response code 99 */ 100 public abstract int statusCode(); 101 102 /** 103 * Returns the {@link HttpRequest} corresponding to this response. 104 * 105 * <p> This may not be the original request provided by the caller, 106 * for example, if that request was redirected. 107 * 108 * @see #previousResponse() 109 * 110 * @return the request 111 */ 112 public abstract HttpRequest request(); 113 114 /** 115 * Returns an {@code Optional} containing the previous intermediate response 116 * if one was received. An intermediate response is one that is received 117 * as a result of redirection or authentication. If no previous response 118 * was received then an empty {@code Optional} is returned. 119 * 120 * @return an Optional containing the HttpResponse, if any. 121 */ 122 public abstract Optional<HttpResponse<T>> previousResponse(); 123 124 /** 125 * Returns the received response headers. 126 * 127 * @return the response headers 128 */ 129 public abstract HttpHeaders headers(); 130 131 /** 132 * Returns the body. Depending on the type of {@code T}, the returned body 133 * may represent the body after it was read (such as {@code byte[]}, or 134 * {@code String}, or {@code Path}) or it may represent an object with 135 * which the body is read, such as an {@link java.io.InputStream}. 136 * 137 * <p> If this {@code HttpResponse} was returned from an invocation of 138 * {@link #previousResponse()} then this method returns {@code null} 139 * 140 * @return the body 141 */ 142 public abstract T body(); 143 144 /** 145 * Returns the {@link javax.net.ssl.SSLParameters} in effect for this 146 * response. Returns {@code null} if this is not a HTTPS response. 147 * 148 * @return the SSLParameters associated with the response 149 */ 150 public abstract SSLParameters sslParameters(); 151 152 /** 153 * Returns the {@code URI} that the response was received from. This may be 154 * different from the request {@code URI} if redirection occurred. 155 * 156 * @return the URI of the response 157 */ 158 public abstract URI uri(); 159 160 /** 161 * Returns the HTTP protocol version that was used for this response. 162 * 163 * @return HTTP protocol version 164 */ 165 public abstract HttpClient.Version version(); 166 167 168 private static String pathForSecurityCheck(Path path) { 169 return path.toFile().getPath(); 170 } 171 172 /** A body handler that is further restricted by a given ACC. */ 173 interface UntrustedBodyHandler<T> extends BodyHandler<T> { 174 void setAccessControlContext(AccessControlContext acc); 175 } 176 177 /** 178 * A Path body handler. 179 * 180 * Note: Exists mainly too allow setting of the senders ACC post creation of 181 * the handler. 182 */ 183 static class PathBodyHandler implements UntrustedBodyHandler<Path> { 184 private final Path file; 185 private final OpenOption[]openOptions; 186 private volatile AccessControlContext acc; 187 188 PathBodyHandler(Path file, OpenOption... openOptions) { 189 this.file = file; 190 this.openOptions = openOptions; 191 } 192 193 @Override 194 public void setAccessControlContext(AccessControlContext acc) { 195 this.acc = acc; 196 } 197 198 @Override 199 public BodySubscriber<Path> apply(int statusCode, HttpHeaders headers) { 200 ResponseSubscribers.PathSubscriber bs = (ResponseSubscribers.PathSubscriber) 201 BodySubscriber.asFileImpl(file, openOptions); 202 bs.setAccessControlContext(acc); 203 return bs; 204 } 205 } 206 207 // Similar to Path body handler, but for file download. Supports setting ACC. 208 static class FileDownloadBodyHandler implements UntrustedBodyHandler<Path> { 209 private final Path directory; 210 private final OpenOption[]openOptions; 211 private volatile AccessControlContext acc; 212 213 FileDownloadBodyHandler(Path directory, OpenOption... openOptions) { 214 this.directory = directory; 215 this.openOptions = openOptions; 216 } 217 218 @Override 219 public void setAccessControlContext(AccessControlContext acc) { 220 this.acc = acc; 221 } 222 223 @Override 224 public BodySubscriber<Path> apply(int statusCode, HttpHeaders headers) { 225 String dispoHeader = headers.firstValue("Content-Disposition") 226 .orElseThrow(() -> unchecked(new IOException("No Content-Disposition"))); 227 if (!dispoHeader.startsWith("attachment;")) { 228 throw unchecked(new IOException("Unknown Content-Disposition type")); 229 } 230 int n = dispoHeader.indexOf("filename="); 231 if (n == -1) { 232 throw unchecked(new IOException("Bad Content-Disposition type")); 233 } 234 int lastsemi = dispoHeader.lastIndexOf(';'); 235 String disposition; 236 if (lastsemi < n) { 237 disposition = dispoHeader.substring(n + 9); 238 } else { 239 disposition = dispoHeader.substring(n + 9, lastsemi); 240 } 241 Path file = Paths.get(directory.toString(), disposition); 242 243 ResponseSubscribers.PathSubscriber bs = (ResponseSubscribers.PathSubscriber) 244 BodySubscriber.asFileImpl(file, openOptions); 245 bs.setAccessControlContext(acc); 246 return bs; 247 } 248 } 249 250 /** 251 * A handler for response bodies. 252 * {@Incubating} 253 * 254 * <p> This is a function that takes two parameters: the response status code, 255 * and the response headers, and which returns a {@linkplain BodySubscriber}. 256 * The function is always called just before the response body is read. Its 257 * implementation may examine the status code or headers and must decide, 258 * whether to accept the response body or discard it, and if accepting it, 259 * exactly how to handle it. 260 * 261 * <p> Some pre-defined implementations which do not utilize the status code 262 * or headers (meaning the body is always accepted) are defined: 263 * <ul><li>{@link #asByteArray() }</li> 264 * <li>{@link #asByteArrayConsumer(java.util.function.Consumer) 265 * asByteArrayConsumer(Consumer)}</li> 266 * <li>{@link #asString(java.nio.charset.Charset) asString(Charset)}</li> 267 * <li>{@link #asFile(Path, OpenOption...) 268 * asFile(Path,OpenOption...)}</li> 269 * <li>{@link #asFileDownload(java.nio.file.Path,OpenOption...) 270 * asFileDownload(Path,OpenOption...)}</li> 271 * <li>{@link #asInputStream() asInputStream()}</li> 272 * <li>{@link #discard(Object) }</li> 273 * <li>{@link #buffering(BodyHandler, int) 274 * buffering(BodyHandler,int)}</li> 275 * </ul> 276 * 277 * <p> These implementations return the equivalent {@link BodySubscriber}. 278 * Alternatively, the handler can be used to examine the status code 279 * or headers and return different body subscribers as appropriate. 280 * 281 * <p><b>Examples of handler usage</b> 282 * 283 * <p> The first example uses one of the predefined handler functions which 284 * ignores the response headers and status, and always process the response 285 * body in the same way. 286 * <pre> 287 * {@code 288 * HttpResponse<Path> resp = HttpRequest 289 * .create(URI.create("http://www.foo.com")) 290 * .GET() 291 * .response(BodyHandler.asFile(Paths.get("/tmp/f"))); 292 * } 293 * </pre> 294 * Note, that even though these pre-defined handlers ignore the status code 295 * and headers, this information is still accessible from the 296 * {@code HttpResponse} when it is returned. 297 * 298 * <p> In the second example, the function returns a different subscriber 299 * depending on the status code. 300 * <pre> 301 * {@code 302 * HttpResponse<Path> resp1 = HttpRequest 303 * .create(URI.create("http://www.foo.com")) 304 * .GET() 305 * .response( 306 * (status, headers) -> status == 200 307 * ? BodySubscriber.asFile(Paths.get("/tmp/f")) 308 * : BodySubscriber.discard(Paths.get("/NULL"))); 309 * } 310 * </pre> 311 * 312 * @param <T> the response body type 313 */ 314 @FunctionalInterface 315 public interface BodyHandler<T> { 316 317 /** 318 * Returns a {@link BodySubscriber BodySubscriber} considering the given 319 * response status code and headers. This method is always called before 320 * the body is read and its implementation can decide to keep the body 321 * and store it somewhere, or else discard it by returning the {@code 322 * BodySubscriber} returned from {@link BodySubscriber#discard(Object) 323 * discard}. 324 * 325 * @param statusCode the HTTP status code received 326 * @param responseHeaders the response headers received 327 * @return a body subscriber 328 */ 329 public BodySubscriber<T> apply(int statusCode, HttpHeaders responseHeaders); 330 331 /** 332 * Returns a response body handler which discards the response body and 333 * uses the given value as a replacement for it. 334 * 335 * @param <U> the response body type 336 * @param value the value of U to return as the body, may be {@code null} 337 * @return a response body handler 338 */ 339 public static <U> BodyHandler<U> discard(U value) { 340 return (status, headers) -> BodySubscriber.discard(value); 341 } 342 343 /** 344 * Returns a {@code BodyHandler<String>} that returns a 345 * {@link BodySubscriber BodySubscriber}{@code <String>} obtained from 346 * {@link BodySubscriber#asString(Charset) BodySubscriber.asString(Charset)}. 347 * If a charset is provided, the body is decoded using it. If charset is 348 * {@code null} then the handler tries to determine the character set 349 * from the {@code Content-encoding} header. If that charset is not 350 * supported then {@link java.nio.charset.StandardCharsets#UTF_8 UTF_8} 351 * is used. 352 * 353 * @param charset The name of the charset to interpret the body as. If 354 * {@code null} then the charset is determined from the 355 * <i>Content-encoding</i> header. 356 * @return a response body handler 357 */ 358 public static BodyHandler<String> asString(Charset charset) { 359 return (status, headers) -> { 360 if (charset != null) { 361 return BodySubscriber.asString(charset); 362 } 363 return BodySubscriber.asString(charsetFrom(headers)); 364 }; 365 } 366 367 /** 368 * Returns a {@code BodyHandler<Path>} that returns a 369 * {@link BodySubscriber BodySubscriber}{@code <Path>} obtained from 370 * {@link BodySubscriber#asFile(Path, OpenOption...) 371 * BodySubscriber.asFile(Path,OpenOption...)}. 372 * 373 * <p> When the {@code HttpResponse} object is returned, the body has 374 * been completely written to the file, and {@link #body()} returns a 375 * reference to its {@link Path}. 376 * 377 * @param file the filename to store the body in 378 * @param openOptions any options to use when opening/creating the file 379 * @return a response body handler 380 * @throws SecurityException If a security manager has been installed 381 * and it denies {@link SecurityManager#checkWrite(String) 382 * write access} to the file. The {@link 383 * SecurityManager#checkDelete(String) checkDelete} method is 384 * invoked to check delete access if the file is opened with 385 * the {@code DELETE_ON_CLOSE} option. 386 */ 387 public static BodyHandler<Path> asFile(Path file, OpenOption... openOptions) { 388 Objects.requireNonNull(file); 389 SecurityManager sm = System.getSecurityManager(); 390 if (sm != null) { 391 String fn = pathForSecurityCheck(file); 392 sm.checkWrite(fn); 393 List<OpenOption> opts = Arrays.asList(openOptions); 394 if (opts.contains(StandardOpenOption.DELETE_ON_CLOSE)) 395 sm.checkDelete(fn); 396 if (opts.contains(StandardOpenOption.READ)) 397 sm.checkRead(fn); 398 } 399 return new PathBodyHandler(file, openOptions); 400 } 401 402 /** 403 * Returns a {@code BodyHandler<Path>} that returns a 404 * {@link BodySubscriber BodySubscriber}{@code <Path>} obtained from 405 * {@link BodySubscriber#asFile(Path) BodySubscriber.asFile(Path)}. 406 * 407 * <p> When the {@code HttpResponse} object is returned, the body has 408 * been completely written to the file, and {@link #body()} returns a 409 * reference to its {@link Path}. 410 * 411 * @param file the file to store the body in 412 * @return a response body handler 413 * @throws SecurityException if a security manager has been installed 414 * and it denies {@link SecurityManager#checkWrite(String) 415 * write access} to the file 416 */ 417 public static BodyHandler<Path> asFile(Path file) { 418 return BodyHandler.asFile(file, StandardOpenOption.CREATE, 419 StandardOpenOption.WRITE); 420 } 421 422 /** 423 * Returns a {@code BodyHandler<Path>} that returns a 424 * {@link BodySubscriber BodySubscriber}<{@link Path}> 425 * where the download directory is specified, but the filename is 426 * obtained from the {@code Content-Disposition} response header. The 427 * {@code Content-Disposition} header must specify the <i>attachment</i> 428 * type and must also contain a <i>filename</i> parameter. If the 429 * filename specifies multiple path components only the final component 430 * is used as the filename (with the given directory name). 431 * 432 * <p> When the {@code HttpResponse} object is returned, the body has 433 * been completely written to the file and {@link #body()} returns a 434 * {@code Path} object for the file. The returned {@code Path} is the 435 * combination of the supplied directory name and the file name supplied 436 * by the server. If the destination directory does not exist or cannot 437 * be written to, then the response will fail with an {@link IOException}. 438 * 439 * @param directory the directory to store the file in 440 * @param openOptions open options 441 * @return a response body handler 442 * @throws SecurityException If a security manager has been installed 443 * and it denies {@link SecurityManager#checkWrite(String) 444 * write access} to the file. The {@link 445 * SecurityManager#checkDelete(String) checkDelete} method is 446 * invoked to check delete access if the file is opened with 447 * the {@code DELETE_ON_CLOSE} option. 448 */ 449 //####: check if the dir exists and is writable?? 450 public static BodyHandler<Path> asFileDownload(Path directory, 451 OpenOption... openOptions) { 452 Objects.requireNonNull(directory); 453 SecurityManager sm = System.getSecurityManager(); 454 if (sm != null) { 455 String fn = pathForSecurityCheck(directory); 456 sm.checkWrite(fn); 457 List<OpenOption> opts = Arrays.asList(openOptions); 458 if (opts.contains(StandardOpenOption.DELETE_ON_CLOSE)) 459 sm.checkDelete(fn); 460 if (opts.contains(StandardOpenOption.READ)) 461 sm.checkRead(fn); 462 } 463 return new FileDownloadBodyHandler(directory, openOptions); 464 } 465 466 /** 467 * Returns a {@code BodyHandler<InputStream>} that returns a 468 * {@link BodySubscriber BodySubscriber}{@code <InputStream>} obtained 469 * from {@link BodySubscriber#asInputStream() BodySubscriber.asInputStream}. 470 * 471 * <p> When the {@code HttpResponse} object is returned, the response 472 * headers will have been completely read, but the body may not have 473 * been fully received yet. The {@link #body()} method returns an 474 * {@link InputStream} from which the body can be read as it is received. 475 * 476 * @apiNote See {@link BodySubscriber#asInputStream()} for more information. 477 * 478 * @return a response body handler 479 */ 480 public static BodyHandler<InputStream> asInputStream() { 481 return (status, headers) -> BodySubscriber.asInputStream(); 482 } 483 484 /** 485 * Returns a {@code BodyHandler<Void>} that returns a 486 * {@link BodySubscriber BodySubscriber}{@code <Void>} obtained from 487 * {@link BodySubscriber#asByteArrayConsumer(Consumer) 488 * BodySubscriber.asByteArrayConsumer(Consumer)}. 489 * 490 * <p> When the {@code HttpResponse} object is returned, the body has 491 * been completely written to the consumer. 492 * 493 * @param consumer a Consumer to accept the response body 494 * @return a response body handler 495 */ 496 public static BodyHandler<Void> asByteArrayConsumer(Consumer<Optional<byte[]>> consumer) { 497 return (status, headers) -> BodySubscriber.asByteArrayConsumer(consumer); 498 } 499 500 /** 501 * Returns a {@code BodyHandler<byte[]>} that returns a 502 * {@link BodySubscriber BodySubscriber}<{@code byte[]}> obtained 503 * from {@link BodySubscriber#asByteArray() BodySubscriber.asByteArray()}. 504 * 505 * <p> When the {@code HttpResponse} object is returned, the body has 506 * been completely written to the byte array. 507 * 508 * @return a response body handler 509 */ 510 public static BodyHandler<byte[]> asByteArray() { 511 return (status, headers) -> BodySubscriber.asByteArray(); 512 } 513 514 /** 515 * Returns a {@code BodyHandler<String>} that returns a 516 * {@link BodySubscriber BodySubscriber}{@code <String>} obtained from 517 * {@link BodySubscriber#asString(java.nio.charset.Charset) 518 * BodySubscriber.asString(Charset)}. The body is 519 * decoded using the character set specified in 520 * the {@code Content-encoding} response header. If there is no such 521 * header, or the character set is not supported, then 522 * {@link java.nio.charset.StandardCharsets#UTF_8 UTF_8} is used. 523 * 524 * <p> When the {@code HttpResponse} object is returned, the body has 525 * been completely written to the string. 526 * 527 * @return a response body handler 528 */ 529 public static BodyHandler<String> asString() { 530 return (status, headers) -> BodySubscriber.asString(charsetFrom(headers)); 531 } 532 533 /** 534 * Returns a {@code BodyHandler} which, when invoked, returns a {@linkplain 535 * BodySubscriber#buffering(BodySubscriber,int) buffering BodySubscriber} 536 * that buffers data before delivering it to the downstream subscriber. 537 * These {@code BodySubscriber} instances are created by calling 538 * {@linkplain BodySubscriber#buffering(BodySubscriber,int) 539 * BodySubscriber.buffering} with a subscriber obtained from the given 540 * downstream handler and the {@code bufferSize} parameter. 541 * 542 * @param downstreamHandler the downstream handler 543 * @param bufferSize the buffer size parameter passed to {@linkplain 544 * BodySubscriber#buffering(BodySubscriber,int) BodySubscriber.buffering} 545 * @return a body handler 546 * @throws IllegalArgumentException if {@code bufferSize <= 0} 547 */ 548 public static <T> BodyHandler<T> buffering(BodyHandler<T> downstreamHandler, 549 int bufferSize) { 550 if (bufferSize <= 0) 551 throw new IllegalArgumentException("must be greater than 0"); 552 return (status, headers) -> BodySubscriber 553 .buffering(downstreamHandler.apply(status, headers), 554 bufferSize); 555 } 556 } 557 558 /** 559 * A subscriber for response bodies. 560 * {@Incubating} 561 * 562 * <p> The object acts as a {@link Flow.Subscriber}<{@link List}<{@link 563 * ByteBuffer}>> to the HTTP client implementation, which publishes 564 * unmodifiable lists of ByteBuffers containing the response body. The Flow 565 * of data, as well as the order of ByteBuffers in the Flow lists, is a 566 * strictly ordered representation of the response body. Both the Lists and 567 * the ByteBuffers, once passed to the subscriber, are no longer used by the 568 * HTTP client. The subscriber converts the incoming buffers of data to some 569 * user-defined object type {@code T}. 570 * 571 * <p> The {@link #getBody()} method returns a {@link CompletionStage}{@code 572 * <T>} that provides the response body object. The {@code CompletionStage} 573 * must be obtainable at any time. When it completes depends on the nature 574 * of type {@code T}. In many cases, when {@code T} represents the entire 575 * body after being read then it completes after the body has been read. If 576 * {@code T} is a streaming type such as {@link java.io.InputStream} then it 577 * completes before the body has been read, because the calling code uses it 578 * to consume the data. 579 * 580 * @apiNote To ensure that all resources associated with the 581 * corresponding exchange are properly released, an implementation 582 * of {@code BodySubscriber} must ensure to {@linkplain 583 * Flow.Subscription#request request} more data until {@link 584 * #onComplete() onComplete} or {@link #onError(Throwable) onError} 585 * are signalled, or {@linkplain Flow.Subscription#request cancel} its 586 * {@linkplain #onSubscribe(Flow.Subscription) subscription} 587 * if unable or unwilling to do so. 588 * Calling {@code cancel} before exhausting the data may cause 589 * the underlying HTTP connection to be closed and prevent it 590 * from being reused for subsequent operations. 591 * 592 * @param <T> the response body type 593 */ 594 public interface BodySubscriber<T> 595 extends Flow.Subscriber<List<ByteBuffer>> { 596 597 /** 598 * Returns a {@code CompletionStage} which when completed will return 599 * the response body object. 600 * 601 * @return a CompletionStage for the response body 602 */ 603 public CompletionStage<T> getBody(); 604 605 /** 606 * Returns a body subscriber which stores the response body as a {@code 607 * String} converted using the given {@code Charset}. 608 * 609 * <p> The {@link HttpResponse} using this subscriber is available after 610 * the entire response has been read. 611 * 612 * @param charset the character set to convert the String with 613 * @return a body subscriber 614 */ 615 public static BodySubscriber<String> asString(Charset charset) { 616 return new ResponseSubscribers.ByteArraySubscriber<>( 617 bytes -> new String(bytes, charset) 618 ); 619 } 620 621 /** 622 * Returns a {@code BodySubscriber} which stores the response body as a 623 * byte array. 624 * 625 * <p> The {@link HttpResponse} using this subscriber is available after 626 * the entire response has been read. 627 * 628 * @return a body subscriber 629 */ 630 public static BodySubscriber<byte[]> asByteArray() { 631 return new ResponseSubscribers.ByteArraySubscriber<>( 632 Function.identity() // no conversion 633 ); 634 } 635 636 // no security check 637 private static BodySubscriber<Path> asFileImpl(Path file, OpenOption... openOptions) { 638 return new ResponseSubscribers.PathSubscriber(file, openOptions); 639 } 640 641 /** 642 * Returns a {@code BodySubscriber} which stores the response body in a 643 * file opened with the given options and name. The file will be opened 644 * with the given options using {@link FileChannel#open(Path,OpenOption...) 645 * FileChannel.open} just before the body is read. Any exception thrown 646 * will be returned or thrown from {@link HttpClient#send(HttpRequest, 647 * BodyHandler) HttpClient::send} or {@link HttpClient#sendAsync(HttpRequest, 648 * BodyHandler) HttpClient::sendAsync} as appropriate. 649 * 650 * <p> The {@link HttpResponse} using this subscriber is available after 651 * the entire response has been read. 652 * 653 * @param file the file to store the body in 654 * @param openOptions the list of options to open the file with 655 * @return a body subscriber 656 * @throws SecurityException If a security manager has been installed 657 * and it denies {@link SecurityManager#checkWrite(String) 658 * write access} to the file. The {@link 659 * SecurityManager#checkDelete(String) checkDelete} method is 660 * invoked to check delete access if the file is opened with the 661 * {@code DELETE_ON_CLOSE} option. 662 */ 663 public static BodySubscriber<Path> asFile(Path file, OpenOption... openOptions) { 664 Objects.requireNonNull(file); 665 SecurityManager sm = System.getSecurityManager(); 666 if (sm != null) { 667 String fn = pathForSecurityCheck(file); 668 sm.checkWrite(fn); 669 List<OpenOption> opts = Arrays.asList(openOptions); 670 if (opts.contains(StandardOpenOption.DELETE_ON_CLOSE)) 671 sm.checkDelete(fn); 672 if (opts.contains(StandardOpenOption.READ)) 673 sm.checkRead(fn); 674 } 675 return asFileImpl(file, openOptions); 676 } 677 678 /** 679 * Returns a {@code BodySubscriber} which stores the response body in a 680 * file opened with the given name. Has the same effect as calling 681 * {@link #asFile(Path, OpenOption...) asFile} with the standard open 682 * options {@code CREATE} and {@code WRITE} 683 * 684 * <p> The {@link HttpResponse} using this subscriber is available after 685 * the entire response has been read. 686 * 687 * @param file the file to store the body in 688 * @return a body subscriber 689 * @throws SecurityException if a security manager has been installed 690 * and it denies {@link SecurityManager#checkWrite(String) 691 * write access} to the file 692 */ 693 public static BodySubscriber<Path> asFile(Path file) { 694 return asFile(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE); 695 } 696 697 /** 698 * Returns a {@code BodySubscriber} which provides the incoming body 699 * data to the provided Consumer of {@code Optional<byte[]>}. Each 700 * call to {@link Consumer#accept(java.lang.Object) Consumer.accept()} 701 * will contain a non empty {@code Optional}, except for the final 702 * invocation after all body data has been read, when the {@code 703 * Optional} will be empty. 704 * 705 * <p> The {@link HttpResponse} using this subscriber is available after 706 * the entire response has been read. 707 * 708 * @param consumer a Consumer of byte arrays 709 * @return a BodySubscriber 710 */ 711 public static BodySubscriber<Void> asByteArrayConsumer(Consumer<Optional<byte[]>> consumer) { 712 return new ResponseSubscribers.ConsumerSubscriber(consumer); 713 } 714 715 /** 716 * Returns a {@code BodySubscriber} which streams the response body as 717 * an {@link InputStream}. 718 * 719 * <p> The {@link HttpResponse} using this subscriber is available 720 * immediately after the response headers have been read, without 721 * requiring to wait for the entire body to be processed. The response 722 * body can then be read directly from the {@link InputStream}. 723 * 724 * @apiNote To ensure that all resources associated with the 725 * corresponding exchange are properly released the caller must 726 * ensure to either read all bytes until EOF is reached, or call 727 * {@link InputStream#close} if it is unable or unwilling to do so. 728 * Calling {@code close} before exhausting the stream may cause 729 * the underlying HTTP connection to be closed and prevent it 730 * from being reused for subsequent operations. 731 * 732 * @return a body subscriber that streams the response body as an 733 * {@link InputStream}. 734 */ 735 public static BodySubscriber<InputStream> asInputStream() { 736 return new ResponseSubscribers.HttpResponseInputStream(); 737 } 738 739 /** 740 * Returns a response subscriber which discards the response body. The 741 * supplied value is the value that will be returned from 742 * {@link HttpResponse#body()}. 743 * 744 * @param <U> The type of the response body 745 * @param value the value to return from HttpResponse.body(), may be {@code null} 746 * @return a {@code BodySubscriber} 747 */ 748 public static <U> BodySubscriber<U> discard(U value) { 749 return new ResponseSubscribers.NullSubscriber<>(Optional.ofNullable(value)); 750 } 751 752 /** 753 * Returns a {@code BodySubscriber} which buffers data before delivering 754 * it to the given downstream subscriber. The subscriber guarantees to 755 * deliver {@code buffersize} bytes of data to each invocation of the 756 * downstream's {@linkplain #onNext(Object) onNext} method, except for 757 * the final invocation, just before {@linkplain #onComplete() onComplete} 758 * is invoked. The final invocation of {@code onNext} may contain fewer 759 * than {@code buffersize} bytes. 760 * 761 * <p> The returned subscriber delegates its {@link #getBody()} method 762 * to the downstream subscriber. 763 * 764 * @param downstream the downstream subscriber 765 * @param bufferSize the buffer size 766 * @return a buffering body subscriber 767 * @throws IllegalArgumentException if {@code bufferSize <= 0} 768 */ 769 public static <T> BodySubscriber<T> buffering(BodySubscriber<T> downstream, 770 int bufferSize) { 771 if (bufferSize <= 0) 772 throw new IllegalArgumentException("must be greater than 0"); 773 return new BufferingSubscriber<T>(downstream, bufferSize); 774 } 775 } 776 777 /** 778 * A response subscriber for a HTTP/2 multi response. 779 * {@Incubating} 780 * 781 * <p> A multi response comprises a main response, and zero or more additional 782 * responses. Each additional response is sent by the server in response to 783 * requests (PUSH_PROMISEs) that the server also generates. Additional responses are 784 * typically resources that the server expects the client will need which 785 * are related to the initial request. 786 * <p> 787 * Note. Instead of implementing this interface, applications should consider 788 * first using the mechanism (built on this interface) provided by 789 * {@link MultiSubscriber#asMap(java.util.function.Function, boolean) 790 * MultiSubscriber.asMap()} which is a slightly simplified, but also 791 * general purpose interface. 792 * <p> 793 * The server generated requests are also known as <i>push promises</i>. 794 * The server is permitted to send any number of these requests up to the 795 * point where the main response is fully received. Therefore, after 796 * completion of the main response, the final number of additional 797 * responses is known. Additional responses may be canceled, but given that 798 * the server does not wait for any acknowledgment before sending the 799 * response, this must be done quickly to avoid unnecessary data transmission. 800 * 801 * <p> {@code MultiSubscriber}s are parameterized with a type {@code U} which 802 * represents some meaningful aggregate of the responses received. This 803 * would typically be a collection of response or response body objects. 804 * 805 * @param <U> a type representing the aggregated results 806 * @param <T> a type representing all of the response bodies 807 * 808 * @since 9 809 */ 810 public interface MultiSubscriber<U,T> { 811 /** 812 * Called for the main request from the user. This {@link HttpRequest} 813 * parameter is the request that was supplied to {@link 814 * HttpClient#sendAsync(HttpRequest, MultiSubscriber)}. The 815 * implementation must return an {@link BodyHandler} for the response 816 * body. 817 * 818 * @param request the request 819 * 820 * @return an optional body handler 821 */ 822 BodyHandler<T> onRequest(HttpRequest request); 823 824 /** 825 * Called for each push promise that is received. The {@link HttpRequest} 826 * parameter represents the PUSH_PROMISE. The implementation must return 827 * an {@code Optional} of {@link BodyHandler} for the response body. 828 * Different handlers (of the same type) can be returned for different 829 * pushes within the same multi send. If no handler (an empty {@code 830 * Optional}) is returned, then the push will be canceled. If required, 831 * the {@code CompletableFuture<Void>} supplied to the {@code 832 * onFinalPushPromise} parameter of {@link 833 * #completion(CompletableFuture, CompletableFuture)} can be used to 834 * determine when the final PUSH_PROMISE is received. 835 * 836 * @param pushPromise the push promise 837 * 838 * @return an optional body handler 839 */ 840 Optional<BodyHandler<T>> onPushPromise(HttpRequest pushPromise); 841 842 /** 843 * Called for each response received. For each request either one of 844 * onResponse() or onError() is guaranteed to be called, but not both. 845 * 846 * <p> Note: The reason for switching to this callback interface rather 847 * than using CompletableFutures supplied to onRequest() is that there 848 * is a subtle interaction between those CFs and the CF returned from 849 * completion() (or when onComplete() was called formerly). The completion() 850 * CF will not complete until after all of the work done by the onResponse() 851 * calls is done. Whereas if you just create CF's dependent on a supplied 852 * CF (to onRequest()) then the implementation has no visibility of the 853 * dependent CFs and can't guarantee to call onComplete() (or complete 854 * the completion() CF) after the dependent CFs complete. 855 * 856 * @param response the response received 857 */ 858 void onResponse(HttpResponse<T> response); 859 860 /** 861 * Called if an error occurs receiving a response. For each request 862 * either one of onResponse() or onError() is guaranteed to be called, 863 * but not both. 864 * 865 * @param request the main request or subsequent push promise 866 * @param t the Throwable that caused the error 867 */ 868 void onError(HttpRequest request, Throwable t); 869 870 /** 871 * Returns a {@link java.util.concurrent.CompletableFuture}{@code <U>} 872 * which completes when the aggregate result object itself is available. 873 * It is expected that the returned {@code CompletableFuture} will depend 874 * on one of the given {@code CompletableFuture<Void}s which themselves 875 * complete after all individual responses associated with the multi 876 * response have completed, or after all push promises have been received. 877 * This method is called after {@link #onRequest(HttpRequest)} but 878 * before any other methods. 879 * 880 * @implNote Implementations might follow the pattern shown below 881 * <pre> 882 * {@code 883 * CompletableFuture<U> completion( 884 * CompletableFuture<Void> onComplete, 885 * CompletableFuture<Void> onFinalPushPromise) 886 * { 887 * return onComplete.thenApply((v) -> { 888 * U u = ... instantiate and populate a U instance 889 * return u; 890 * }); 891 * } 892 * } 893 * </pre> 894 * 895 * @param onComplete a CompletableFuture which completes after all 896 * responses have been received relating to this multi request. 897 * 898 * @param onFinalPushPromise CompletableFuture which completes after all 899 * push promises have been received. 900 * 901 * @return the aggregate CF response object 902 */ 903 CompletableFuture<U> completion(CompletableFuture<Void> onComplete, 904 CompletableFuture<Void> onFinalPushPromise); 905 906 /** 907 * Returns a general purpose handler for multi responses. The aggregated 908 * result object produced by this handler is a 909 * {@code Map<HttpRequest,CompletableFuture<HttpResponse<V>>>}. Each 910 * request (both the original user generated request and each server 911 * generated push promise) is returned as a key of the map. The value 912 * corresponding to each key is a 913 * {@code CompletableFuture<HttpResponse<V>>}. 914 * 915 * <p> There are two ways to use these handlers, depending on the value 916 * of the <i>completion</I> parameter. If completion is true, then the 917 * aggregated result will be available after all responses have 918 * themselves completed. If <i>completion</i> is false, then the 919 * aggregated result will be available immediately after the last push 920 * promise was received. In the former case, this implies that all the 921 * CompletableFutures in the map values will have completed. In the 922 * latter case, they may or may not have completed yet. 923 * 924 * <p> The simplest way to use these handlers is to set completion to 925 * {@code true}, and then all (results) values in the Map will be 926 * accessible without blocking. 927 * <p> 928 * See {@link #asMap(java.util.function.Function, boolean)} 929 * for a code sample of using this interface. 930 * 931 * <p> See {@link #asMap(Function, boolean)} for a code sample of using 932 * this interface. 933 * 934 * @param <V> the body type used for all responses 935 * @param reqHandler a function invoked for the user's request and each 936 * push promise 937 * @param completion {@code true} if the aggregate CompletableFuture 938 * completes after all responses have been received, 939 * or {@code false} after all push promises received 940 * 941 * @return a MultiSubscriber 942 */ 943 public static <V> MultiSubscriber<MultiMapResult<V>,V> asMap( 944 Function<HttpRequest, Optional<HttpResponse.BodyHandler<V>>> reqHandler, 945 boolean completion) { 946 return new MultiSubscriberImpl<V>(reqHandler.andThen(optv -> optv.get()), 947 reqHandler, 948 completion); 949 } 950 951 /** 952 * Returns a general purpose handler for multi responses. This is a 953 * convenience method which invokes {@link #asMap(Function,boolean) 954 * asMap(Function, true)} meaning that the aggregate result 955 * object completes after all responses have been received. 956 * 957 * <p><b>Example usage:</b> 958 * <br> 959 * <pre> 960 * {@code 961 * HttpRequest request = HttpRequest.newBuilder() 962 * .uri(URI.create("https://www.foo.com/")) 963 * .GET() 964 * .build(); 965 * 966 * HttpClient client = HttpClient.newHttpClient(); 967 * 968 * Map<HttpRequest,CompletableFuture<HttpResponse<String>>> results = client 969 * .sendAsync(request, MultiSubscriber.asMap( 970 * (req) -> Optional.of(HttpResponse.BodyHandler.asString()))) 971 * .join(); 972 * }</pre> 973 * 974 * <p> The lambda in this example is the simplest possible implementation, 975 * where neither the incoming requests are examined, nor the response 976 * headers, and every push that the server sends is accepted. When the 977 * join() call returns, all {@code HttpResponse}s and their associated 978 * body objects are available. 979 * 980 * @param <V> the body type used for all responses 981 * @param reqHandler a function invoked for each push promise and the 982 * main request 983 * @return a MultiSubscriber 984 */ 985 public static <V> MultiSubscriber<MultiMapResult<V>,V> asMap( 986 Function<HttpRequest, Optional<HttpResponse.BodyHandler<V>>> reqHandler) { 987 988 return asMap(reqHandler, true); 989 } 990 991 } 992 }