src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java
changeset 49944 4690a2871b44
parent 49765 ee6f7a61f3a5
child 50681 4254bed3c09d
child 56507 2294c51eae30
equal deleted inserted replaced
49943:8e1ed2a15845 49944:4690a2871b44
   119             Utils.getDebugLogger("Http2Connection"::toString, Utils.DEBUG);
   119             Utils.getDebugLogger("Http2Connection"::toString, Utils.DEBUG);
   120     private final Logger debugHpack =
   120     private final Logger debugHpack =
   121             Utils.getHpackLogger(this::dbgString, Utils.DEBUG_HPACK);
   121             Utils.getHpackLogger(this::dbgString, Utils.DEBUG_HPACK);
   122     static final ByteBuffer EMPTY_TRIGGER = ByteBuffer.allocate(0);
   122     static final ByteBuffer EMPTY_TRIGGER = ByteBuffer.allocate(0);
   123 
   123 
   124     private boolean singleStream; // used only for stream 1, then closed
   124     static private final int MAX_CLIENT_STREAM_ID = Integer.MAX_VALUE; // 2147483647
       
   125     static private final int MAX_SERVER_STREAM_ID = Integer.MAX_VALUE - 1; // 2147483646
       
   126 
       
   127     /**
       
   128      * Flag set when no more streams to be opened on this connection.
       
   129      * Two cases where it is used.
       
   130      *
       
   131      * 1. Two connections to the same server were opened concurrently, in which
       
   132      *    case one of them will be put in the cache, and the second will expire
       
   133      *    when all its opened streams (which usually should be a single client
       
   134      *    stream + possibly some additional push-promise server streams) complete.
       
   135      * 2. A cached connection reaches its maximum number of streams (~ 2^31-1)
       
   136      *    either server / or client allocated, in which case it will be taken
       
   137      *    out of the cache - allowing a new connection to replace it. It will
       
   138      *    expire when all its still open streams (which could be many) eventually
       
   139      *    complete.
       
   140      */
       
   141     private boolean finalStream;
   125 
   142 
   126     /*
   143     /*
   127      *  ByteBuffer pooling strategy for HTTP/2 protocol:
   144      * ByteBuffer pooling strategy for HTTP/2 protocol.
   128      *
   145      *
   129      * In general there are 4 points where ByteBuffers are used:
   146      * In general there are 4 points where ByteBuffers are used:
   130      *  - incoming/outgoing frames from/to ByteBuffers plus incoming/outgoing encrypted data
   147      *  - incoming/outgoing frames from/to ByteBuffers plus incoming/outgoing
   131      *    in case of SSL connection.
   148      *    encrypted data in case of SSL connection.
   132      *
   149      *
   133      * 1. Outgoing frames encoded to ByteBuffers.
   150      * 1. Outgoing frames encoded to ByteBuffers.
   134      *    Outgoing ByteBuffers are created with requited size and frequently small (except DataFrames, etc)
   151      *
   135      *    At this place no pools at all. All outgoing buffers should be collected by GC.
   152      *  Outgoing ByteBuffers are created with required size and frequently
       
   153      *  small (except DataFrames, etc). At this place no pools at all. All
       
   154      *  outgoing buffers should eventually be collected by GC.
   136      *
   155      *
   137      * 2. Incoming ByteBuffers (decoded to frames).
   156      * 2. Incoming ByteBuffers (decoded to frames).
   138      *    Here, total elimination of BB pool is not a good idea.
       
   139      *    We don't know how many bytes we will receive through network.
       
   140      * So here we allocate buffer of reasonable size. The following life of the BB:
       
   141      * - If all frames decoded from the BB are other than DataFrame and HeaderFrame (and HeaderFrame subclasses)
       
   142      *     BB is returned to pool,
       
   143      * - If we decoded DataFrame from the BB. In that case DataFrame refers to subbuffer obtained by slice() method.
       
   144      *     Such BB is never returned to pool and will be GCed.
       
   145      * - If we decoded HeadersFrame from the BB. Then header decoding is performed inside processFrame method and
       
   146      *     the buffer could be release to pool.
       
   147      *
   157      *
   148      * 3. SLL encrypted buffers. Here another pool was introduced and all net buffers are to/from the pool,
   158      *  Here, total elimination of BB pool is not a good idea.
   149      *    because of we can't predict size encrypted packets.
   159      *  We don't know how many bytes we will receive through network.
   150      *
   160      *
       
   161      *  A possible future improvement ( currently not implemented ):
       
   162      *  Allocate buffers of reasonable size. The following life of the BB:
       
   163      *   - If all frames decoded from the BB are other than DataFrame and
       
   164      *     HeaderFrame (and HeaderFrame subclasses) BB is returned to pool,
       
   165      *   - If a DataFrame is decoded from the BB. In that case DataFrame refers
       
   166      *     to sub-buffer obtained by slice(). Such a BB is never returned to the
       
   167      *     pool and will eventually be GC'ed.
       
   168      *   - If a HeadersFrame is decoded from the BB. Then header decoding is
       
   169      *     performed inside processFrame method and the buffer could be release
       
   170      *     back to pool.
       
   171      *
       
   172      * 3. SSL encrypted buffers ( received ).
       
   173      *
       
   174      *  The current implementation recycles encrypted buffers read from the
       
   175      *  channel. The pool of buffers has a maximum size of 3, SocketTube.MAX_BUFFERS,
       
   176      *  direct buffers which are shared by all connections on a given client.
       
   177      *  The pool is used by all SSL connections - whether HTTP/1.1 or HTTP/2,
       
   178      *  but only for SSL encrypted buffers that circulate between the SocketTube
       
   179      *  Publisher and the SSLFlowDelegate Reader. Limiting the pool to this
       
   180      *  particular segment allows the use of direct buffers, thus avoiding any
       
   181      *  additional copy in the NIO socket channel implementation. See
       
   182      *  HttpClientImpl.SSLDirectBufferSupplier, SocketTube.SSLDirectBufferSource,
       
   183      *  and SSLTube.recycler.
   151      */
   184      */
   152 
   185 
   153 
   186 
   154     // A small class that allows to control frames with respect to the state of
   187     // A small class that allows to control frames with respect to the state of
   155     // the connection preface. Any data received before the connection
   188     // the connection preface. Any data received before the connection
   218     final HttpConnection connection;
   251     final HttpConnection connection;
   219     private final Http2ClientImpl client2;
   252     private final Http2ClientImpl client2;
   220     private final Map<Integer,Stream<?>> streams = new ConcurrentHashMap<>();
   253     private final Map<Integer,Stream<?>> streams = new ConcurrentHashMap<>();
   221     private int nextstreamid;
   254     private int nextstreamid;
   222     private int nextPushStream = 2;
   255     private int nextPushStream = 2;
       
   256     // actual stream ids are not allocated until the Headers frame is ready
       
   257     // to be sent. The following two fields are updated as soon as a stream
       
   258     // is created and assigned to a connection. They are checked before
       
   259     // assigning a stream to a connection.
       
   260     private int lastReservedClientStreamid = 1;
       
   261     private int lastReservedServerStreamid = 0;
   223     private final Encoder hpackOut;
   262     private final Encoder hpackOut;
   224     private final Decoder hpackIn;
   263     private final Decoder hpackIn;
   225     final SettingsFrame clientSettings;
   264     final SettingsFrame clientSettings;
   226     private volatile SettingsFrame serverSettings;
   265     private volatile SettingsFrame serverSettings;
   227     private final String key; // for HttpClientImpl.connections map
   266     private final String key; // for HttpClientImpl.connections map
   363 
   402 
   364     final HttpClientImpl client() {
   403     final HttpClientImpl client() {
   365         return client2.client();
   404         return client2.client();
   366     }
   405     }
   367 
   406 
       
   407     // call these before assigning a request/stream to a connection
       
   408     // if false returned then a new Http2Connection is required
       
   409     // if true, the the stream may be assigned to this connection
       
   410     synchronized boolean reserveStream(boolean clientInitiated) {
       
   411         if (finalStream) {
       
   412             return false;
       
   413         }
       
   414         if (clientInitiated && (lastReservedClientStreamid + 2) >= MAX_CLIENT_STREAM_ID) {
       
   415             setFinalStream();
       
   416             client2.deleteConnection(this);
       
   417             return false;
       
   418         } else if (!clientInitiated && (lastReservedServerStreamid + 2) >= MAX_SERVER_STREAM_ID) {
       
   419             setFinalStream();
       
   420             client2.deleteConnection(this);
       
   421             return false;
       
   422         }
       
   423         if (clientInitiated)
       
   424             lastReservedClientStreamid+=2;
       
   425         else
       
   426             lastReservedServerStreamid+=2;
       
   427         return true;
       
   428     }
       
   429 
   368     /**
   430     /**
   369      * Throws an IOException if h2 was not negotiated
   431      * Throws an IOException if h2 was not negotiated
   370      */
   432      */
   371     private static CompletableFuture<?> checkSSLConfig(AbstractAsyncSSLConnection aconn) {
   433     private static CompletableFuture<?> checkSSLConfig(AbstractAsyncSSLConnection aconn) {
   372         assert aconn.isSecure();
   434         assert aconn.isSecure();
   412                     }
   474                     }
   413                 })
   475                 })
   414                 .thenCompose(checkAlpnCF);
   476                 .thenCompose(checkAlpnCF);
   415     }
   477     }
   416 
   478 
   417     synchronized boolean singleStream() {
   479     synchronized boolean finalStream() {
   418         return singleStream;
   480         return finalStream;
   419     }
   481     }
   420 
   482 
   421     synchronized void setSingleStream(boolean use) {
   483     /**
   422         singleStream = use;
   484      * Mark this connection so no more streams created on it and it will close when
       
   485      * all are complete.
       
   486      */
       
   487     synchronized void setFinalStream() {
       
   488         finalStream = true;
   423     }
   489     }
   424 
   490 
   425     static String keyFor(HttpConnection connection) {
   491     static String keyFor(HttpConnection connection) {
   426         boolean isProxy = connection.isProxied(); // tunnel or plain clear connection through proxy
   492         boolean isProxy = connection.isProxied(); // tunnel or plain clear connection through proxy
   427         boolean isSecure = connection.isSecure();
   493         boolean isSecure = connection.isSecure();
   691         HttpRequestImpl parentReq = parent.request;
   757         HttpRequestImpl parentReq = parent.request;
   692         int promisedStreamid = pp.getPromisedStream();
   758         int promisedStreamid = pp.getPromisedStream();
   693         if (promisedStreamid != nextPushStream) {
   759         if (promisedStreamid != nextPushStream) {
   694             resetStream(promisedStreamid, ResetFrame.PROTOCOL_ERROR);
   760             resetStream(promisedStreamid, ResetFrame.PROTOCOL_ERROR);
   695             return;
   761             return;
       
   762         } else if (!reserveStream(false)) {
       
   763             resetStream(promisedStreamid, ResetFrame.REFUSED_STREAM);
       
   764             return;
   696         } else {
   765         } else {
   697             nextPushStream += 2;
   766             nextPushStream += 2;
   698         }
   767         }
   699 
   768 
   700         HttpHeadersImpl headers = decoder.headers();
   769         HttpHeadersImpl headers = decoder.headers();
   750         if (s != null && !(s instanceof Stream.PushedStream)) {
   819         if (s != null && !(s instanceof Stream.PushedStream)) {
   751             // Since PushStreams have no request body, then they have no
   820             // Since PushStreams have no request body, then they have no
   752             // corresponding entry in the window controller.
   821             // corresponding entry in the window controller.
   753             windowController.removeStream(streamid);
   822             windowController.removeStream(streamid);
   754         }
   823         }
   755         if (singleStream() && streams.isEmpty()) {
   824         if (finalStream() && streams.isEmpty()) {
   756             // should be only 1 stream, but there might be more if server push
   825             // should be only 1 stream, but there might be more if server push
   757             close();
   826             close();
   758         }
   827         }
   759     }
   828     }
   760 
   829