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