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 }