1 /*
2 * Copyright (c) 2015, 2018, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
29 import java.util.concurrent.ThreadFactory;
30 import java.util.concurrent.atomic.AtomicReference;
31 import java.util.function.Consumer;
32 import javax.net.ServerSocketFactory;
33 import javax.net.ssl.SSLContext;
34 import javax.net.ssl.SSLParameters;
35 import javax.net.ssl.SSLServerSocket;
36 import javax.net.ssl.SSLServerSocketFactory;
37 import javax.net.ssl.SNIServerName;
38 import jdk.internal.net.http.frame.ErrorFrame;
39
40 /**
41 * Waits for incoming TCP connections from a client and establishes
42 * a HTTP2 connection. Two threads are created per connection. One for reading
43 * and one for writing. Incoming requests are dispatched to the supplied
44 * Http2Handler on additional threads. All threads
45 * obtained from the supplied ExecutorService.
46 */
47 public class Http2TestServer implements AutoCloseable {
48 final ServerSocket server;
49 volatile boolean secure;
50 final ExecutorService exec;
51 volatile boolean stopping = false;
52 final Map<String,Http2Handler> handlers;
53 final SSLContext sslContext;
54 final String serverName;
55 final HashMap<InetSocketAddress,Http2TestServerConnection> connections;
56 final Properties properties;
57
58 private static ThreadFactory defaultThreadFac =
59 (Runnable r) -> {
60 Thread t = new Thread(r);
61 t.setName("Test-server-pool");
62 return t;
63 };
64
65
66 private static ExecutorService getDefaultExecutor() {
67 return Executors.newCachedThreadPool(defaultThreadFac);
68 }
94 this(serverName, secure, 0, null, 50, null, context);
95 }
96
97 public Http2TestServer(boolean secure,
98 int port,
99 ExecutorService exec,
100 SSLContext context) throws Exception {
101 this(null, secure, port, exec, 50, null, context);
102 }
103
104 public Http2TestServer(String serverName,
105 boolean secure,
106 int port,
107 ExecutorService exec,
108 SSLContext context)
109 throws Exception
110 {
111 this(serverName, secure, port, exec, 50, null, context);
112 }
113
114 /**
115 * Create a Http2Server listening on the given port. Currently needs
116 * to know in advance whether incoming connections are plain TCP "h2c"
117 * or TLS "h2"/
118 *
119 * @param serverName SNI servername
120 * @param secure https or http
121 * @param port listen port
122 * @param exec executor service (cached thread pool is used if null)
123 * @param backlog the server socket backlog
124 * @param properties additional configuration properties
125 * @param context the SSLContext used when secure is true
126 */
127 public Http2TestServer(String serverName,
128 boolean secure,
129 int port,
130 ExecutorService exec,
131 int backlog,
132 Properties properties,
133 SSLContext context)
134 throws Exception
135 {
136 this.serverName = serverName;
137 if (secure) {
138 if (context != null)
139 this.sslContext = context;
140 else
141 this.sslContext = SSLContext.getDefault();
142 server = initSecure(port, backlog);
143 } else {
144 this.sslContext = context;
145 server = initPlaintext(port, backlog);
146 }
147 this.secure = secure;
148 this.exec = exec == null ? getDefaultExecutor() : exec;
149 this.handlers = Collections.synchronizedMap(new HashMap<>());
150 this.properties = properties;
151 this.connections = new HashMap<>();
152 }
153
154 /**
155 * Adds the given handler for the given path
156 */
203 stopping = true;
204 System.err.printf("Server stopping %d connections\n", connections.size());
205 for (Http2TestServerConnection connection : connections.values()) {
206 connection.close(ErrorFrame.NO_ERROR);
207 }
208 try {
209 server.close();
210 } catch (IOException e) {}
211 exec.shutdownNow();
212 }
213
214
215 final ServerSocket initSecure(int port, int backlog) throws Exception {
216 ServerSocketFactory fac;
217 SSLParameters sslp = null;
218 fac = sslContext.getServerSocketFactory();
219 sslp = sslContext.getSupportedSSLParameters();
220 SSLServerSocket se = (SSLServerSocket) fac.createServerSocket();
221 se.setReuseAddress(false);
222 se.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), backlog);
223 sslp.setApplicationProtocols(new String[]{"h2"});
224 sslp.setEndpointIdentificationAlgorithm("HTTPS");
225 se.setSSLParameters(sslp);
226 se.setEnabledCipherSuites(se.getSupportedCipherSuites());
227 se.setEnabledProtocols(se.getSupportedProtocols());
228 // other initialisation here
229 return se;
230 }
231
232 public String serverName() {
233 return serverName;
234 }
235
236 private synchronized void putConnection(InetSocketAddress addr, Http2TestServerConnection c) {
237 if (!stopping)
238 connections.put(addr, c);
239 }
240
241 private synchronized void removeConnection(InetSocketAddress addr, Http2TestServerConnection c) {
242 connections.remove(addr, c);
243 }
|
1 /*
2 * Copyright (c) 2015, 2020, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
29 import java.util.concurrent.ThreadFactory;
30 import java.util.concurrent.atomic.AtomicReference;
31 import java.util.function.Consumer;
32 import javax.net.ServerSocketFactory;
33 import javax.net.ssl.SSLContext;
34 import javax.net.ssl.SSLParameters;
35 import javax.net.ssl.SSLServerSocket;
36 import javax.net.ssl.SSLServerSocketFactory;
37 import javax.net.ssl.SNIServerName;
38 import jdk.internal.net.http.frame.ErrorFrame;
39
40 /**
41 * Waits for incoming TCP connections from a client and establishes
42 * a HTTP2 connection. Two threads are created per connection. One for reading
43 * and one for writing. Incoming requests are dispatched to the supplied
44 * Http2Handler on additional threads. All threads
45 * obtained from the supplied ExecutorService.
46 */
47 public class Http2TestServer implements AutoCloseable {
48 final ServerSocket server;
49 final boolean supportsHTTP11;
50 volatile boolean secure;
51 final ExecutorService exec;
52 volatile boolean stopping = false;
53 final Map<String,Http2Handler> handlers;
54 final SSLContext sslContext;
55 final String serverName;
56 final HashMap<InetSocketAddress,Http2TestServerConnection> connections;
57 final Properties properties;
58
59 private static ThreadFactory defaultThreadFac =
60 (Runnable r) -> {
61 Thread t = new Thread(r);
62 t.setName("Test-server-pool");
63 return t;
64 };
65
66
67 private static ExecutorService getDefaultExecutor() {
68 return Executors.newCachedThreadPool(defaultThreadFac);
69 }
95 this(serverName, secure, 0, null, 50, null, context);
96 }
97
98 public Http2TestServer(boolean secure,
99 int port,
100 ExecutorService exec,
101 SSLContext context) throws Exception {
102 this(null, secure, port, exec, 50, null, context);
103 }
104
105 public Http2TestServer(String serverName,
106 boolean secure,
107 int port,
108 ExecutorService exec,
109 SSLContext context)
110 throws Exception
111 {
112 this(serverName, secure, port, exec, 50, null, context);
113 }
114
115 public Http2TestServer(String serverName,
116 boolean secure,
117 int port,
118 ExecutorService exec,
119 int backlog,
120 Properties properties,
121 SSLContext context)
122 throws Exception
123 {
124 this(serverName, secure, port, exec, backlog, properties, context, false);
125 }
126
127 /**
128 * Create a Http2Server listening on the given port. Currently needs
129 * to know in advance whether incoming connections are plain TCP "h2c"
130 * or TLS "h2"/
131 *
132 * @param serverName SNI servername
133 * @param secure https or http
134 * @param port listen port
135 * @param exec executor service (cached thread pool is used if null)
136 * @param backlog the server socket backlog
137 * @param properties additional configuration properties
138 * @param context the SSLContext used when secure is true
139 */
140 public Http2TestServer(String serverName,
141 boolean secure,
142 int port,
143 ExecutorService exec,
144 int backlog,
145 Properties properties,
146 SSLContext context,
147 boolean supportsHTTP11)
148 throws Exception
149 {
150 this.serverName = serverName;
151 this.supportsHTTP11 = supportsHTTP11;
152 if (secure) {
153 if (context != null)
154 this.sslContext = context;
155 else
156 this.sslContext = SSLContext.getDefault();
157 server = initSecure(port, backlog);
158 } else {
159 this.sslContext = context;
160 server = initPlaintext(port, backlog);
161 }
162 this.secure = secure;
163 this.exec = exec == null ? getDefaultExecutor() : exec;
164 this.handlers = Collections.synchronizedMap(new HashMap<>());
165 this.properties = properties;
166 this.connections = new HashMap<>();
167 }
168
169 /**
170 * Adds the given handler for the given path
171 */
218 stopping = true;
219 System.err.printf("Server stopping %d connections\n", connections.size());
220 for (Http2TestServerConnection connection : connections.values()) {
221 connection.close(ErrorFrame.NO_ERROR);
222 }
223 try {
224 server.close();
225 } catch (IOException e) {}
226 exec.shutdownNow();
227 }
228
229
230 final ServerSocket initSecure(int port, int backlog) throws Exception {
231 ServerSocketFactory fac;
232 SSLParameters sslp = null;
233 fac = sslContext.getServerSocketFactory();
234 sslp = sslContext.getSupportedSSLParameters();
235 SSLServerSocket se = (SSLServerSocket) fac.createServerSocket();
236 se.setReuseAddress(false);
237 se.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), backlog);
238 if (supportsHTTP11) {
239 sslp.setApplicationProtocols(new String[]{"h2", "http/1.1"});
240 } else {
241 sslp.setApplicationProtocols(new String[]{"h2"});
242 }
243 sslp.setEndpointIdentificationAlgorithm("HTTPS");
244 se.setSSLParameters(sslp);
245 se.setEnabledCipherSuites(se.getSupportedCipherSuites());
246 se.setEnabledProtocols(se.getSupportedProtocols());
247 // other initialisation here
248 return se;
249 }
250
251 public String serverName() {
252 return serverName;
253 }
254
255 private synchronized void putConnection(InetSocketAddress addr, Http2TestServerConnection c) {
256 if (!stopping)
257 connections.put(addr, c);
258 }
259
260 private synchronized void removeConnection(InetSocketAddress addr, Http2TestServerConnection c) {
261 connections.remove(addr, c);
262 }
|