< prev index next >

src/java.httpclient/share/classes/java/net/http/HttpConnection.java

Print this page




   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.FileOutputStream;
  27 import java.io.IOException;
  28 import java.io.PrintStream;
  29 import java.net.InetSocketAddress;
  30 import java.nio.ByteBuffer;
  31 import java.nio.channels.SocketChannel;
  32 import java.util.concurrent.CompletableFuture;
  33 import javax.net.ssl.SSLParameters;
  34 
  35 /**
  36  * Wraps socket channel layer and takes care of SSL also.
  37  *
  38  * Subtypes are:
  39  *      PlainHttpConnection: regular direct TCP connection to server
  40  *      PlainProxyConnection: plain text proxy connection
  41  *      PlainTunnelingConnection: opens plain text (CONNECT) tunnel to server
  42  *      SSLConnection: TLS channel direct to server
  43  *      SSLTunnelConnection: TLS channel via (CONNECT) proxy tunnel
  44  */
  45 abstract class HttpConnection implements BufferHandler {










  46 
  47     // address we are connected to. Could be a server or a proxy
  48     final InetSocketAddress address;
  49     final HttpClientImpl client;
  50     protected volatile ByteBuffer buffer;
  51 
  52     HttpConnection(InetSocketAddress address, HttpClientImpl client) {
  53         this.address = address;
  54         this.client = client;

  55     }
  56 
  57     /**
  58      * Public API to this class. addr is the ultimate destination. Any proxies
  59      * etc are figured out from the request. Returns an instance of one of the
  60      * following
  61      *      PlainHttpConnection
  62      *      PlainTunnelingConnection
  63      *      SSLConnection
  64      *      SSLTunnelConnection
  65      *
  66      * When object returned, connect() or connectAsync() must be called, which
  67      * when it returns/completes, the connection is usable for requests.
  68      */
  69     public static HttpConnection getConnection(InetSocketAddress addr,
  70                                                HttpRequestImpl request) {
  71         return getConnectionImpl(addr, request);














  72     }
  73 
  74     public abstract void connect() throws IOException, InterruptedException;
  75 
  76     public abstract CompletableFuture<Void> connectAsync();
  77 
  78     /**
  79      * Returns whether this connection is connected to its destination
  80      */
  81     abstract boolean connected();
  82 
  83     abstract boolean isSecure();
  84 
  85     abstract boolean isProxied();
  86 
  87     /**
  88      * Completes when the first byte of the response is available to be read.
  89      */
  90     abstract CompletableFuture<Void> whenReceivingResponse();
  91 
  92     // must be called before reading any data off connection
  93     // at beginning of response.
  94     ByteBuffer getRemaining() {
  95         ByteBuffer b = buffer;
  96         buffer = null;
  97         return b;
  98     }
  99 
 100     final boolean isOpen() {
 101         return channel().isOpen();
 102     }
 103 
 104     /* Returns either a plain HTTP connection or a plain tunnelling connection
 105      * for proxied websockets */
 106     private static HttpConnection getPlainConnection(InetSocketAddress addr,
 107                                                      InetSocketAddress proxy,
 108                                                      HttpRequestImpl request) {
 109         HttpClientImpl client = request.client();
 110 
 111         if (request.isWebSocket() && proxy != null) {
 112             return new PlainTunnelingConnection(addr,
 113                                                 proxy,
 114                                                 client,
 115                                                 request.getAccessControlContext());
 116         } else {
 117             if (proxy == null) {
 118                 return new PlainHttpConnection(addr, client);
 119             } else {
 120                 return new PlainProxyConnection(proxy, client);
 121             }
 122         }
 123     }
 124 
 125     private static HttpConnection getSSLConnection(InetSocketAddress addr,
 126                                                    InetSocketAddress proxy,
 127                                                    HttpRequestImpl request,
 128                                                    String[] alpn) {
 129         HttpClientImpl client = request.client();
 130         if (proxy != null) {
 131             return new SSLTunnelConnection(addr,
 132                                            client,
 133                                            proxy,
 134                                            request.getAccessControlContext());
 135         } else {
 136             return new SSLConnection(addr, client, alpn);


 137         }
 138     }
 139 
 140     /**
 141      * Main factory method.   Gets a HttpConnection, either cached or new if
 142      * none available.
 143      */
 144     private static HttpConnection getConnectionImpl(InetSocketAddress addr,
 145                                                     HttpRequestImpl request) {

 146         HttpConnection c;
 147         HttpClientImpl client = request.client();
 148         InetSocketAddress proxy = request.proxy();
 149         boolean secure = request.secure();
 150         ConnectionPool pool = client.connectionPool();
 151         String[] alpn =  null;
 152 
 153         if (secure && request.requestHttp2()) {
 154             alpn = new String[1];
 155             alpn[0] = "h2";
 156         }
 157 
 158         if (!secure) {
 159             c = pool.getConnection(false, addr, proxy);
 160             if (c != null) {
 161                 return c;
 162             } else {
 163                 return getPlainConnection(addr, proxy, request);
 164             }
 165         } else {
 166             c = pool.getConnection(true, addr, proxy);
 167             if (c != null) {
 168                 return c;
 169             } else {
 170                 return getSSLConnection(addr, proxy, request, alpn);
 171             }
 172         }
 173     }
 174 
 175     void returnToCache(HttpHeaders hdrs) {
 176         if (hdrs == null) {
 177             // the connection was closed by server
 178             close();
 179             return;
 180         }
 181         if (!isOpen()) {
 182             return;
 183         }
 184         ConnectionPool pool = client.connectionPool();
 185         boolean keepAlive = hdrs.firstValue("Connection")
 186                 .map((s) -> !s.equalsIgnoreCase("close"))
 187                 .orElse(true);
 188 
 189         if (keepAlive) {
 190             pool.returnToPool(this);


 206     }
 207 
 208     final void checkWrite(long expected,
 209                           ByteBuffer[] buffers,
 210                           int start,
 211                           int length)
 212         throws IOException
 213     {
 214         long written = write(buffers, start, length);
 215         if (written != expected) {
 216             throw new IOException("incorrect number of bytes written");
 217         }
 218     }
 219 
 220     abstract SocketChannel channel();
 221 
 222     final InetSocketAddress address() {
 223         return address;
 224     }
 225 
 226     void configureBlocking(boolean mode) throws IOException {
 227         channel().configureBlocking(mode);




 228     }
 229 
 230     abstract ConnectionPool.CacheKey cacheKey();
 231 
 232     /*
 233     static PrintStream ps;
 234 
 235     static {
 236         try {
 237             String propval = Utils.getNetProperty("java.net.httpclient.showData");
 238             if (propval != null && propval.equalsIgnoreCase("true")) {
 239                 ps = new PrintStream(new FileOutputStream("/tmp/httplog.txt"), false);
 240             }
 241         } catch (IOException e) {
 242             e.printStackTrace();
 243         }
 244     }
 245 
 246     synchronized final void debugPrint(String s, ByteBuffer b) {
 247         ByteBuffer[] bufs = new ByteBuffer[1];
 248         bufs[0] = b;
 249         debugPrint(s, bufs, 0, 1);
 250     }
 251 
 252     synchronized final void debugPrint(String s,
 253                                        ByteBuffer[] bufs,
 254                                        int start,
 255                                        int number) {
 256         if (ps == null) {
 257             return;
 258         }
 259 
 260         ps.printf("\n%s:\n", s);
 261 
 262         for (int i=start; i<start+number; i++) {
 263             ByteBuffer b = bufs[i].duplicate();
 264             while (b.hasRemaining()) {
 265                 int c = b.get();
 266                 if (c == 10) {
 267                     ps.printf("LF \n");
 268                 } else if (c == 13) {
 269                     ps.printf(" CR ");
 270                 } else if (c == 0x20) {
 271                     ps.printf("_");
 272                 } else if (c > 0x20 && c <= 0x7F) {
 273                     ps.printf("%c", (char)c);
 274                 } else {
 275                     ps.printf("0x%02x ", c);
 276                 }
 277             }
 278         }
 279         ps.printf("\n---------------------\n");
 280     }
 281 
 282     */
 283 
 284     // overridden in SSL only
 285     SSLParameters sslParameters() {
 286         return null;
 287     }
 288 
 289     // Methods to be implemented for Plain TCP and SSL
 290 
 291     abstract long write(ByteBuffer[] buffers, int start, int number)
 292         throws IOException;
 293 
 294     abstract long write(ByteBuffer buffer) throws IOException;
 295 
 296     /**
 297      * Closes this connection, by returning the socket to its connection pool.
 298      */
 299     abstract void close();

 300 
 301     /**
 302      * Returns a ByteBuffer with data, or null if EOF.
 303      */
 304     final ByteBuffer read() throws IOException {
 305         return read(-1);
 306     }
 307 
 308     /**
 309      * Puts position to limit and limit to capacity so we can resume reading
 310      * into this buffer, but if required > 0 then limit may be reduced so that
 311      * no more than required bytes are read next time.
 312      */
 313     static void resumeChannelRead(ByteBuffer buf, int required) {
 314         int limit = buf.limit();
 315         buf.position(limit);
 316         int capacity = buf.capacity() - limit;
 317         if (required > 0 && required < capacity) {
 318             buf.limit(limit + required);
 319         } else {


 339         return buffer;
 340     }
 341 
 342     final int read(ByteBuffer buffer) throws IOException {
 343         int n = readImpl(buffer);
 344         return n;
 345     }
 346 
 347     /** Reads up to length bytes. */
 348     protected abstract ByteBuffer readImpl(int length) throws IOException;
 349 
 350     /** Reads as much as possible into given buffer and returns amount read. */
 351     protected abstract int readImpl(ByteBuffer buffer) throws IOException;
 352 
 353     @Override
 354     public String toString() {
 355         return "HttpConnection: " + channel().toString();
 356     }
 357 
 358     @Override
 359     public final ByteBuffer getBuffer() {
 360         return client.getBuffer();
 361     }
 362 
 363     @Override
 364     public final void returnBuffer(ByteBuffer buffer) {
 365         client.returnBuffer(buffer);





 366     }
 367 }


   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);


 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 {


 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 >