1 /*
   2  * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  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.internal.net.http;
  27 
  28 import java.io.IOException;
  29 import java.net.URI;
  30 import java.nio.ByteBuffer;
  31 import java.util.Optional;
  32 import java.util.concurrent.CompletableFuture;
  33 import java.util.function.Supplier;
  34 import javax.net.ssl.SSLSession;
  35 import java.net.http.HttpClient;
  36 import java.net.http.HttpHeaders;
  37 import java.net.http.HttpRequest;
  38 import java.net.http.HttpResponse;
  39 import jdk.internal.net.http.websocket.RawChannel;
  40 
  41 /**
  42  * The implementation class for HttpResponse
  43  */
  44 class HttpResponseImpl<T> implements HttpResponse<T>, RawChannel.Provider {
  45 
  46     final int responseCode;
  47     final Exchange<T> exchange;
  48     final HttpRequest initialRequest;
  49     final Optional<HttpResponse<T>> previousResponse;
  50     final HttpHeaders headers;
  51     final Optional<SSLSession> sslSession;
  52     final URI uri;
  53     final HttpClient.Version version;
  54     RawChannel rawchan;
  55     final HttpConnection connection;
  56     final Stream<T> stream;
  57     final T body;
  58 
  59     public HttpResponseImpl(HttpRequest initialRequest,
  60                             Response response,
  61                             HttpResponse<T> previousResponse,
  62                             T body,
  63                             Exchange<T> exch) {
  64         this.responseCode = response.statusCode();
  65         this.exchange = exch;
  66         this.initialRequest = initialRequest;
  67         this.previousResponse = Optional.ofNullable(previousResponse);
  68         this.headers = response.headers();
  69         //this.trailers = trailers;
  70         this.sslSession = Optional.ofNullable(response.getSSLSession());
  71         this.uri = response.request().uri();
  72         this.version = response.version();
  73         this.connection = connection(exch);
  74         this.stream = null;
  75         this.body = body;
  76     }
  77 
  78     private HttpConnection connection(Exchange<?> exch) {
  79         if (exch == null || exch.exchImpl == null) {
  80             assert responseCode == 407;
  81             return null; // case of Proxy 407
  82         }
  83         return exch.exchImpl.connection();
  84     }
  85 
  86     private ExchangeImpl<?> exchangeImpl() {
  87         return exchange != null ? exchange.exchImpl : stream;
  88     }
  89 
  90     @Override
  91     public int statusCode() {
  92         return responseCode;
  93     }
  94 
  95     @Override
  96     public HttpRequest request() {
  97         return initialRequest;
  98     }
  99 
 100     @Override
 101     public Optional<HttpResponse<T>> previousResponse() {
 102         return previousResponse;
 103     }
 104 
 105     @Override
 106     public HttpHeaders headers() {
 107         return headers;
 108     }
 109 
 110     @Override
 111     public T body() {
 112         return body;
 113     }
 114 
 115     @Override
 116     public Optional<SSLSession> sslSession() {
 117         return sslSession;
 118     }
 119 
 120     @Override
 121     public URI uri() {
 122         return uri;
 123     }
 124 
 125     @Override
 126     public HttpClient.Version version() {
 127         return version;
 128     }
 129     // keepalive flag determines whether connection is closed or kept alive
 130     // by reading/skipping data
 131 
 132     /**
 133      * Returns a RawChannel that may be used for WebSocket protocol.
 134      * @implNote This implementation does not support RawChannel over
 135      *           HTTP/2 connections.
 136      * @return a RawChannel that may be used for WebSocket protocol.
 137      * @throws UnsupportedOperationException if getting a RawChannel over
 138      *         this connection is not supported.
 139      * @throws IOException if an I/O exception occurs while retrieving
 140      *         the channel.
 141      */
 142     @Override
 143     public synchronized RawChannel rawChannel() throws IOException {
 144         if (rawchan == null) {
 145             ExchangeImpl<?> exchImpl = exchangeImpl();
 146             if (!(exchImpl instanceof Http1Exchange)) {
 147                 // RawChannel is only used for WebSocket - and WebSocket
 148                 // is not supported over HTTP/2 yet, so we should not come
 149                 // here. Getting a RawChannel over HTTP/2 might be supported
 150                 // in the future, but it would entail retrieving any left over
 151                 // bytes that might have been read but not consumed by the
 152                 // HTTP/2 connection.
 153                 throw new UnsupportedOperationException("RawChannel is not supported over HTTP/2");
 154             }
 155             // Http1Exchange may have some remaining bytes in its
 156             // internal buffer.
 157             Supplier<ByteBuffer> initial = ((Http1Exchange<?>)exchImpl)::drainLeftOverBytes;
 158             rawchan = new RawChannelTube(connection, initial);
 159         }
 160         return rawchan;
 161     }
 162 
 163     @Override
 164     public String toString() {
 165         StringBuilder sb = new StringBuilder();
 166         String method = request().method();
 167         URI uri = request().uri();
 168         String uristring = uri == null ? "" : uri.toString();
 169         sb.append('(')
 170           .append(method)
 171           .append(" ")
 172           .append(uristring)
 173           .append(") ")
 174           .append(statusCode());
 175         return sb.toString();
 176     }
 177 }