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