< prev index next >
src/java.httpclient/share/classes/java/net/http/Http2ClientImpl.java
Print this page
@@ -1,7 +1,7 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
@@ -21,13 +21,144 @@
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
*/
package java.net.http;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import static java.net.http.SettingsFrame.INITIAL_WINDOW_SIZE;
+import static java.net.http.SettingsFrame.ENABLE_PUSH;
+import static java.net.http.SettingsFrame.HEADER_TABLE_SIZE;
+import static java.net.http.SettingsFrame.MAX_CONCURRENT_STREAMS;
+import static java.net.http.SettingsFrame.MAX_FRAME_SIZE;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Http2 specific aspects of HttpClientImpl
+ */
class Http2ClientImpl {
- Http2ClientImpl(HttpClientImpl t) {}
- String getSettingsString() {return "";}
- void debugPrint() {}
- Http2Connection getConnectionFor(HttpRequestImpl r) {
+
+ HttpClientImpl client;
+
+ Http2ClientImpl(HttpClientImpl client) {
+ this.client = client;
+ }
+
+ /* Map key is "scheme:host:port" */
+ final Map<String,Http2Connection> connections =
+ Collections.synchronizedMap(new HashMap<>());
+
+ final Set<String> opening = Collections.synchronizedSet(new HashSet<>());
+
+ synchronized boolean haveConnectionFor(URI uri, InetSocketAddress proxy) {
+ return connections.containsKey(Http2Connection.keyFor(uri,proxy));
+ }
+
+ /*
+ * Only one connection per destination is created. Blocks when opening
+ * connection, or when waiting for connection to be opened.
+ * First thread opens the connection and notifies the others when done.
+ *
+ * If the request is secure (https) then we open the connection here.
+ * If not, then the more complicated upgrade from 1.1 to 2 happens (not here)
+ * In latter case, when the Http2Connection is connected, putConnection() must
+ * be called to store it.
+ */
+ Http2Connection getConnectionFor(HttpRequestImpl req)
+ throws IOException, InterruptedException
+ {
+ URI uri = req.uri();
+ InetSocketAddress proxy = req.proxy();
+ String key = Http2Connection.keyFor(uri, proxy);
+ Http2Connection connection;
+ boolean createHere; // true if this thread is going to open connection
+ synchronized (opening) {
+ connection = connections.get(key);
+ if (connection != null) {
+ return connection;
+ }
+
+ if (!req.secure()) {
return null;
}
+
+ if (!opening.contains(key)) {
+ opening.add(key);
+ createHere = true;
+ } else {
+ createHere = false;
+ opening.wait();
+ }
+ }
+ if (createHere) {
+ connection = new Http2Connection(req);
+ synchronized(opening) {
+ connections.put(key, connection);
+ opening.remove(key);
+ opening.notifyAll();
+ }
+ }
+ return connection;
+ }
+
+ /*
+ * TODO: If there isn't a connection to the same destination, then
+ * store it. If there is already a connection, then close it
+ */
+ synchronized void putConnection(Http2Connection c) {
+ String key = c.key();
+ connections.put(key, c);
+ }
+
+ synchronized void deleteConnection(Http2Connection c) {
+ String key = c.key();
+ connections.remove(key);
+ }
+
+ /** Returns the client settings as a base64 (url) encoded string */
+ String getSettingsString() {
+ SettingsFrame sf = getClientSettings();
+ ByteBufferGenerator bg = new ByteBufferGenerator(client);
+ sf.writeOutgoing(bg);
+ byte[] settings = bg.asByteArray(9); // without the header
+ Base64.Encoder encoder = Base64.getUrlEncoder()
+ .withoutPadding();
+ return encoder.encodeToString(settings);
+ }
+
+ private static final int K = 1024;
+
+ SettingsFrame getClientSettings() {
+ SettingsFrame frame = new SettingsFrame();
+ frame.setParameter(HEADER_TABLE_SIZE, Utils.getIntegerNetProperty(
+ "sun.net.httpclient.hpack.maxheadertablesize", 16 * K));
+ frame.setParameter(ENABLE_PUSH, Utils.getIntegerNetProperty(
+ "sun.net.httpclient.enablepush", 1));
+ frame.setParameter(MAX_CONCURRENT_STREAMS, Utils.getIntegerNetProperty(
+ "sun.net.httpclient.maxstreams", 16));
+ frame.setParameter(INITIAL_WINDOW_SIZE, Utils.getIntegerNetProperty(
+ "sun.net.httpclient.windowsize", 32 * K));
+ frame.setParameter(MAX_FRAME_SIZE, Utils.getIntegerNetProperty(
+ "sun.net.httpclient.maxframesize", 16 * K));
+ frame.setLength();
+ return frame;
+ }
+
+ // these default settings only used until first Settings frame received
+ // from server.
+
+ SettingsFrame getServerSettings() {
+ SettingsFrame frame = new SettingsFrame();
+ frame.setParameter(HEADER_TABLE_SIZE, 4 * K);
+ frame.setParameter(ENABLE_PUSH, 0);
+ frame.setParameter(MAX_CONCURRENT_STREAMS, 8);
+ frame.setParameter(INITIAL_WINDOW_SIZE, 64 * K - 1);
+ frame.setParameter(MAX_FRAME_SIZE, 8 * K);
+ return frame;
+ }
}
< prev index next >