Path: blob/master/src/java.net.http/share/classes/jdk/internal/net/http/HttpResponseImpl.java
41171 views
/*1* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package jdk.internal.net.http;2627import java.io.IOException;28import java.net.URI;29import java.nio.ByteBuffer;30import java.util.Optional;31import java.util.concurrent.CompletableFuture;32import java.util.function.Supplier;33import javax.net.ssl.SSLSession;34import java.net.http.HttpClient;35import java.net.http.HttpHeaders;36import java.net.http.HttpRequest;37import java.net.http.HttpResponse;38import jdk.internal.net.http.websocket.RawChannel;3940/**41* The implementation class for HttpResponse42*/43class HttpResponseImpl<T> implements HttpResponse<T>, RawChannel.Provider {4445final int responseCode;46final HttpRequest initialRequest;47final Optional<HttpResponse<T>> previousResponse;48final HttpHeaders headers;49final Optional<SSLSession> sslSession;50final URI uri;51final HttpClient.Version version;52final RawChannelProvider rawChannelProvider;53final T body;5455public HttpResponseImpl(HttpRequest initialRequest,56Response response,57HttpResponse<T> previousResponse,58T body,59Exchange<T> exch) {60this.responseCode = response.statusCode();61this.initialRequest = initialRequest;62this.previousResponse = Optional.ofNullable(previousResponse);63this.headers = response.headers();64//this.trailers = trailers;65this.sslSession = Optional.ofNullable(response.getSSLSession());66this.uri = response.request().uri();67this.version = response.version();68this.rawChannelProvider = RawChannelProvider.create(response, exch);69this.body = body;70}7172@Override73public int statusCode() {74return responseCode;75}7677@Override78public HttpRequest request() {79return initialRequest;80}8182@Override83public Optional<HttpResponse<T>> previousResponse() {84return previousResponse;85}8687@Override88public HttpHeaders headers() {89return headers;90}9192@Override93public T body() {94return body;95}9697@Override98public Optional<SSLSession> sslSession() {99return sslSession;100}101102@Override103public URI uri() {104return uri;105}106107@Override108public HttpClient.Version version() {109return version;110}111// keepalive flag determines whether connection is closed or kept alive112// by reading/skipping data113114/**115* Returns a RawChannel that may be used for WebSocket protocol.116* @implNote This implementation does not support RawChannel over117* HTTP/2 connections.118* @return a RawChannel that may be used for WebSocket protocol.119* @throws UnsupportedOperationException if getting a RawChannel over120* this connection is not supported.121* @throws IOException if an I/O exception occurs while retrieving122* the channel.123*/124@Override125public synchronized RawChannel rawChannel() throws IOException {126if (rawChannelProvider == null) {127throw new UnsupportedOperationException(128"RawChannel is only supported for WebSocket creation");129}130return rawChannelProvider.rawChannel();131}132133/**134* Closes the RawChannel that may have been used for WebSocket protocol.135*136* @apiNote This method should be called to close the connection137* if an exception occurs during the websocket handshake, in cases where138* {@link #rawChannel() rawChannel().close()} would have been called.139* An unsuccessful handshake may prevent the creation of the RawChannel:140* if a RawChannel has already been created, this method wil close it.141* Otherwise, it will close the connection.142*143* @throws UnsupportedOperationException if getting a RawChannel over144* this connection is not supported.145* @throws IOException if an I/O exception occurs while closing146* the channel.147*/148@Override149public synchronized void closeRawChannel() throws IOException {150if (rawChannelProvider == null) {151throw new UnsupportedOperationException(152"RawChannel is only supported for WebSocket creation");153}154rawChannelProvider.closeRawChannel();155}156157@Override158public String toString() {159StringBuilder sb = new StringBuilder();160String method = request().method();161URI uri = request().uri();162String uristring = uri == null ? "" : uri.toString();163sb.append('(')164.append(method)165.append(" ")166.append(uristring)167.append(") ")168.append(statusCode());169return sb.toString();170}171172/**173* An auxiliary class used for RawChannel creation when creating a WebSocket.174* This avoids keeping around references to connection/exchange in the175* regular HttpResponse case. Only those responses corresponding to an176* initial WebSocket request have a RawChannelProvider.177*/178private static final class RawChannelProvider implements RawChannel.Provider {179private final HttpConnection connection;180private final Exchange<?> exchange;181private RawChannel rawchan;182RawChannelProvider(HttpConnection conn, Exchange<?> exch) {183connection = conn;184exchange = exch;185}186187static RawChannelProvider create(Response resp, Exchange<?> exch) {188if (resp.request().isWebSocket()) {189return new RawChannelProvider(connection(resp, exch), exch);190}191return null;192}193194@Override195public synchronized RawChannel rawChannel() {196if (rawchan == null) {197ExchangeImpl<?> exchImpl = exchangeImpl();198if (!(exchImpl instanceof Http1Exchange)) {199// RawChannel is only used for WebSocket - and WebSocket200// is not supported over HTTP/2 yet, so we should not come201// here. Getting a RawChannel over HTTP/2 might be supported202// in the future, but it would entail retrieving any left over203// bytes that might have been read but not consumed by the204// HTTP/2 connection.205throw new UnsupportedOperationException("RawChannel is not supported over HTTP/2");206}207// Http1Exchange may have some remaining bytes in its208// internal buffer.209Supplier<ByteBuffer> initial = ((Http1Exchange<?>) exchImpl)::drainLeftOverBytes;210rawchan = new RawChannelTube(connection, initial);211}212return rawchan;213}214215public synchronized void closeRawChannel() throws IOException {216// close the rawChannel, if created, or the217// connection, if not.218if (rawchan != null) rawchan.close();219else connection.close();220}221222private static HttpConnection connection(Response resp, Exchange<?> exch) {223if (exch == null || exch.exchImpl == null) {224assert resp.statusCode == 407;225return null; // case of Proxy 407226}227return exch.exchImpl.connection();228}229230private ExchangeImpl<?> exchangeImpl() {231return exchange != null ? exchange.exchImpl : null;232}233234}235}236237238