1 /* 2 * Copyright (c) 2015, 2016, 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 java.net.http; 27 28 import java.io.Closeable; 29 import java.io.IOException; 30 import java.net.InetSocketAddress; 31 import java.nio.ByteBuffer; 32 import java.nio.channels.SocketChannel; 33 import java.util.concurrent.CompletableFuture; 34 import javax.net.ssl.SSLParameters; 35 36 /** 37 * Wraps socket channel layer and takes care of SSL also. 38 * 39 * Subtypes are: 40 * PlainHttpConnection: regular direct TCP connection to server 41 * PlainProxyConnection: plain text proxy connection 42 * PlainTunnelingConnection: opens plain text (CONNECT) tunnel to server 43 * SSLConnection: TLS channel direct to server 44 * SSLTunnelConnection: TLS channel via (CONNECT) proxy tunnel 45 */ 46 abstract class HttpConnection implements BufferHandler, Closeable { 47 48 protected final static ByteBuffer emptyBuf = Utils.EMPTY_BYTEBUFFER; 49 50 enum Mode { 51 BLOCKING, 52 NON_BLOCKING, 53 ASYNC 54 } 55 56 protected Mode mode; 57 58 // address we are connected to. Could be a server or a proxy 59 final InetSocketAddress address; 60 final HttpClientImpl client; 61 protected volatile ByteBuffer buffer; 62 63 HttpConnection(InetSocketAddress address, HttpClientImpl client) { 64 this.address = address; 65 this.client = client; 66 this.buffer = emptyBuf; 67 } 68 69 /** 70 * Public API to this class. addr is the ultimate destination. Any proxies 71 * etc are figured out from the request. Returns an instance of one of the 72 * following 73 * PlainHttpConnection 74 * PlainTunnelingConnection 75 * SSLConnection 76 * SSLTunnelConnection 77 * 78 * When object returned, connect() or connectAsync() must be called, which 79 * when it returns/completes, the connection is usable for requests. 80 */ 81 public static HttpConnection getConnection(InetSocketAddress addr, 82 HttpRequestImpl request) { 83 return getConnectionImpl(addr, request, null); 84 } 85 86 /** 87 * Called specifically to get an async connection for HTTP/2 over SSL. 88 * 89 * @param addr 90 * @param request 91 * @param http2 92 * @return 93 */ 94 public static HttpConnection getConnection(InetSocketAddress addr, 95 HttpRequestImpl request, Http2Connection http2) { 96 97 return getConnectionImpl(addr, request, http2); 98 } 99 100 public abstract void connect() throws IOException, InterruptedException; 101 102 public abstract CompletableFuture<Void> connectAsync(); 103 104 /** 105 * Returns whether this connection is connected to its destination 106 */ 107 abstract boolean connected(); 108 109 abstract boolean isSecure(); 110 111 abstract boolean isProxied(); 112 113 /** 114 * Completes when the first byte of the response is available to be read. 115 */ 116 abstract CompletableFuture<Void> whenReceivingResponse(); 117 118 // must be called before reading any data off connection 119 // at beginning of response. 120 ByteBuffer getRemaining() { 121 ByteBuffer b = buffer; 122 buffer = emptyBuf; 123 return b; 124 } 125 126 final boolean isOpen() { 127 return channel().isOpen(); 128 } 129 130 /* Returns either a plain HTTP connection or a plain tunnelling connection 131 * for proxied websockets */ 132 private static HttpConnection getPlainConnection(InetSocketAddress addr, 133 InetSocketAddress proxy, 134 HttpRequestImpl request) { 135 HttpClientImpl client = request.client(); 136 137 if (request.isWebSocket() && proxy != null) { 138 return new PlainTunnelingConnection(addr, 139 proxy, 140 client, 141 request.getAccessControlContext()); 142 } else { 143 if (proxy == null) { 144 return new PlainHttpConnection(addr, client); 145 } else { 146 return new PlainProxyConnection(proxy, client); 147 } 148 } 149 } 150 151 private static HttpConnection getSSLConnection(InetSocketAddress addr, 152 InetSocketAddress proxy, HttpRequestImpl request, 153 String[] alpn, Http2Connection http2) { 154 HttpClientImpl client = request.client(); 155 if (proxy != null) { 156 return new SSLTunnelConnection(addr, 157 client, 158 proxy, 159 request.getAccessControlContext()); 160 } else if (http2 == null) { 161 return new SSLConnection(addr, client, alpn); 162 } else { 163 return new AsyncSSLConnection(addr, client, alpn); 164 } 165 } 166 167 /** 168 * Main factory method. Gets a HttpConnection, either cached or new if 169 * none available. 170 */ 171 private static HttpConnection getConnectionImpl(InetSocketAddress addr, 172 HttpRequestImpl request, Http2Connection http2) { 173 174 HttpConnection c; 175 HttpClientImpl client = request.client(); 176 InetSocketAddress proxy = request.proxy(); 177 boolean secure = request.secure(); 178 ConnectionPool pool = client.connectionPool(); 179 String[] alpn = null; 180 181 if (secure && request.requestHttp2()) { 182 alpn = new String[1]; 183 alpn[0] = "h2"; 184 } 185 186 if (!secure) { 187 c = pool.getConnection(false, addr, proxy); 188 if (c != null) { 189 return c; 190 } else { 191 return getPlainConnection(addr, proxy, request); 192 } 193 } else { 194 c = pool.getConnection(true, addr, proxy); 195 if (c != null) { 196 return c; 197 } else { 198 return getSSLConnection(addr, proxy, request, alpn, http2); 199 } 200 } 201 } 202 203 void returnToCache(HttpHeaders hdrs) { 204 if (hdrs == null) { 205 // the connection was closed by server 206 close(); 207 return; 208 } 209 if (!isOpen()) { 210 return; 211 } 212 ConnectionPool pool = client.connectionPool(); 213 boolean keepAlive = hdrs.firstValue("Connection") 214 .map((s) -> !s.equalsIgnoreCase("close")) 215 .orElse(true); 216 217 if (keepAlive) { 218 pool.returnToPool(this); 219 } else { 220 close(); 221 } 222 } 223 224 /** 225 * Also check that the number of bytes written is what was expected. This 226 * could be different if the buffer is user-supplied and its internal 227 * pointers were manipulated in a race condition. 228 */ 229 final void checkWrite(long expected, ByteBuffer buffer) throws IOException { 230 long written = write(buffer); 231 if (written != expected) { 232 throw new IOException("incorrect number of bytes written"); 233 } 234 } 235 236 final void checkWrite(long expected, 237 ByteBuffer[] buffers, 238 int start, 239 int length) 240 throws IOException 241 { 242 long written = write(buffers, start, length); 243 if (written != expected) { 244 throw new IOException("incorrect number of bytes written"); 245 } 246 } 247 248 abstract SocketChannel channel(); 249 250 final InetSocketAddress address() { 251 return address; 252 } 253 254 synchronized void configureMode(Mode mode) throws IOException { 255 this.mode = mode; 256 if (mode == Mode.BLOCKING) 257 channel().configureBlocking(true); 258 else 259 channel().configureBlocking(false); 260 } 261 262 abstract ConnectionPool.CacheKey cacheKey(); 263 264 // overridden in SSL only 265 SSLParameters sslParameters() { 266 return null; 267 } 268 269 // Methods to be implemented for Plain TCP and SSL 270 271 abstract long write(ByteBuffer[] buffers, int start, int number) 272 throws IOException; 273 274 abstract long write(ByteBuffer buffer) throws IOException; 275 276 /** 277 * Closes this connection, by returning the socket to its connection pool. 278 */ 279 @Override 280 public abstract void close(); 281 282 /** 283 * Returns a ByteBuffer with data, or null if EOF. 284 */ 285 final ByteBuffer read() throws IOException { 286 return read(-1); 287 } 288 289 /** 290 * Puts position to limit and limit to capacity so we can resume reading 291 * into this buffer, but if required > 0 then limit may be reduced so that 292 * no more than required bytes are read next time. 293 */ 294 static void resumeChannelRead(ByteBuffer buf, int required) { 295 int limit = buf.limit(); 296 buf.position(limit); 297 int capacity = buf.capacity() - limit; 298 if (required > 0 && required < capacity) { 299 buf.limit(limit + required); 300 } else { 301 buf.limit(buf.capacity()); 302 } 303 } 304 305 /** 306 * Blocks ands return requested amount. 307 */ 308 final ByteBuffer read(int length) throws IOException { 309 if (length <= 0) { 310 buffer = readImpl(length); 311 return buffer; 312 } 313 buffer = readImpl(length); 314 int required = length - buffer.remaining(); 315 while (buffer.remaining() < length) { 316 resumeChannelRead(buffer, required); 317 int n = readImpl(buffer); 318 required -= n; 319 } 320 return buffer; 321 } 322 323 final int read(ByteBuffer buffer) throws IOException { 324 int n = readImpl(buffer); 325 return n; 326 } 327 328 /** Reads up to length bytes. */ 329 protected abstract ByteBuffer readImpl(int length) throws IOException; 330 331 /** Reads as much as possible into given buffer and returns amount read. */ 332 protected abstract int readImpl(ByteBuffer buffer) throws IOException; 333 334 @Override 335 public String toString() { 336 return "HttpConnection: " + channel().toString(); 337 } 338 339 @Override 340 public final ByteBuffer getBuffer(int n) { 341 return client.getBuffer(n); 342 } 343 344 @Override 345 public final void returnBuffer(ByteBuffer buffer) { 346 client.returnBuffer(buffer); 347 } 348 349 @Override 350 public final void setMinBufferSize(int n) { 351 client.setMinBufferSize(n); 352 } 353 }