jdk/src/java.httpclient/share/classes/java/net/http/Http2ClientImpl.java
changeset 42483 3850c235c3fb
parent 42482 15297dde0d55
parent 42479 a80dbf731cbe
child 42489 a9e4de33da2e
equal deleted inserted replaced
42482:15297dde0d55 42483:3850c235c3fb
     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.IOException;
       
    29 import java.net.InetSocketAddress;
       
    30 import java.net.URI;
       
    31 import static java.net.http.SettingsFrame.INITIAL_WINDOW_SIZE;
       
    32 import static java.net.http.SettingsFrame.ENABLE_PUSH;
       
    33 import static java.net.http.SettingsFrame.HEADER_TABLE_SIZE;
       
    34 import static java.net.http.SettingsFrame.MAX_CONCURRENT_STREAMS;
       
    35 import static java.net.http.SettingsFrame.MAX_FRAME_SIZE;
       
    36 import java.util.Base64;
       
    37 import java.util.Collections;
       
    38 import java.util.HashMap;
       
    39 import java.util.HashSet;
       
    40 import java.util.Map;
       
    41 import java.util.Set;
       
    42 
       
    43 /**
       
    44  *  Http2 specific aspects of HttpClientImpl
       
    45  */
       
    46 class Http2ClientImpl {
       
    47 
       
    48     final private HttpClientImpl client;
       
    49 
       
    50     Http2ClientImpl(HttpClientImpl client) {
       
    51         this.client = client;
       
    52     }
       
    53 
       
    54     /* Map key is "scheme:host:port" */
       
    55     final private Map<String,Http2Connection> connections =
       
    56             Collections.synchronizedMap(new HashMap<>());
       
    57 
       
    58     final private Set<String> opening = Collections.synchronizedSet(new HashSet<>());
       
    59 
       
    60     synchronized boolean haveConnectionFor(URI uri, InetSocketAddress proxy) {
       
    61         return connections.containsKey(Http2Connection.keyFor(uri,proxy));
       
    62     }
       
    63 
       
    64     /**
       
    65      * If a https request then blocks and waits until a connection is opened.
       
    66      * Returns null if the request is 'http' as a different (upgrade)
       
    67      * mechanism is used.
       
    68      *
       
    69      * Only one connection per destination is created. Blocks when opening
       
    70      * connection, or when waiting for connection to be opened.
       
    71      * First thread opens the connection and notifies the others when done.
       
    72      *
       
    73      * If the request is secure (https) then we open the connection here.
       
    74      * If not, then the more complicated upgrade from 1.1 to 2 happens (not here)
       
    75      * In latter case, when the Http2Connection is connected, putConnection() must
       
    76      * be called to store it.
       
    77      */
       
    78     Http2Connection getConnectionFor(HttpRequestImpl req)
       
    79             throws IOException, InterruptedException {
       
    80         URI uri = req.uri();
       
    81         InetSocketAddress proxy = req.proxy();
       
    82         String key = Http2Connection.keyFor(uri, proxy);
       
    83         Http2Connection connection;
       
    84         synchronized (opening) {
       
    85             while ((connection = connections.get(key)) == null) {
       
    86                 if (!req.secure()) {
       
    87                     return null;
       
    88                 }
       
    89                 if (!opening.contains(key)) {
       
    90                     opening.add(key);
       
    91                     break;
       
    92                 } else {
       
    93                     opening.wait();
       
    94                 }
       
    95             }
       
    96         }
       
    97         if (connection != null) {
       
    98             return connection;
       
    99         }
       
   100         // we are opening the connection here blocking until it is done.
       
   101         connection = new Http2Connection(req);
       
   102         synchronized (opening) {
       
   103             connections.put(key, connection);
       
   104             opening.remove(key);
       
   105             opening.notifyAll();
       
   106         }
       
   107         return connection;
       
   108     }
       
   109 
       
   110 
       
   111     /*
       
   112      * TODO: If there isn't a connection to the same destination, then
       
   113      * store it. If there is already a connection, then close it
       
   114      */
       
   115     synchronized void putConnection(Http2Connection c) {
       
   116         String key = c.key();
       
   117         connections.put(key, c);
       
   118     }
       
   119 
       
   120     synchronized void deleteConnection(Http2Connection c) {
       
   121         String key = c.key();
       
   122         connections.remove(key);
       
   123     }
       
   124 
       
   125     HttpClientImpl client() {
       
   126         return client;
       
   127     }
       
   128 
       
   129     /** Returns the client settings as a base64 (url) encoded string */
       
   130     String getSettingsString() {
       
   131         SettingsFrame sf = getClientSettings();
       
   132         ByteBufferGenerator bg = new ByteBufferGenerator(client);
       
   133         sf.writeOutgoing(bg);
       
   134         byte[] settings = bg.asByteArray(9); // without the header
       
   135         Base64.Encoder encoder = Base64.getUrlEncoder()
       
   136                                        .withoutPadding();
       
   137         return encoder.encodeToString(settings);
       
   138     }
       
   139 
       
   140     private static final int K = 1024;
       
   141 
       
   142     SettingsFrame getClientSettings() {
       
   143         SettingsFrame frame = new SettingsFrame();
       
   144         frame.setParameter(HEADER_TABLE_SIZE, Utils.getIntegerNetProperty(
       
   145             "java.net.httpclient.hpack.maxheadertablesize", 16 * K));
       
   146         frame.setParameter(ENABLE_PUSH, Utils.getIntegerNetProperty(
       
   147             "java.net.httpclient.enablepush", 1));
       
   148         frame.setParameter(MAX_CONCURRENT_STREAMS, Utils.getIntegerNetProperty(
       
   149             "java.net.httpclient.maxstreams", 16));
       
   150         frame.setParameter(INITIAL_WINDOW_SIZE, Utils.getIntegerNetProperty(
       
   151             "java.net.httpclient.windowsize", 32 * K));
       
   152         frame.setParameter(MAX_FRAME_SIZE, Utils.getIntegerNetProperty(
       
   153             "java.net.httpclient.maxframesize", 16 * K));
       
   154         frame.computeLength();
       
   155         return frame;
       
   156     }
       
   157 }