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 }