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