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.
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 */
23
24 import java.io.IOException;
25 import java.net.*;
26 import java.util.*;
27 import java.util.concurrent.ExecutorService;
28 import java.util.concurrent.Executors;
29 import java.util.concurrent.ThreadFactory;
30 import java.util.concurrent.atomic.AtomicReference;
31 import javax.net.ServerSocketFactory;
32 import javax.net.ssl.SSLContext;
33 import javax.net.ssl.SSLParameters;
34 import javax.net.ssl.SSLServerSocket;
35 import javax.net.ssl.SSLServerSocketFactory;
36 import javax.net.ssl.SNIServerName;
37
38 /**
39 * Waits for incoming TCP connections from a client and establishes
40 * a HTTP2 connection. Two threads are created per connection. One for reading
41 * and one for writing. Incoming requests are dispatched to the supplied
42 * Http2Handler on additional threads. All threads
43 * obtained from the supplied ExecutorService.
44 */
45 public class Http2TestServer implements AutoCloseable {
46 final ServerSocket server;
47 volatile boolean secure;
48 final ExecutorService exec;
49 volatile boolean stopping = false;
50 final Map<String,Http2Handler> handlers;
114 this.serverName = serverName;
115 if (secure) {
116 server = initSecure(port);
117 } else {
118 server = initPlaintext(port);
119 }
120 this.secure = secure;
121 this.exec = exec == null ? getDefaultExecutor() : exec;
122 this.handlers = Collections.synchronizedMap(new HashMap<>());
123 this.sslContext = context;
124 this.connections = new HashMap<>();
125 }
126
127 /**
128 * Adds the given handler for the given path
129 */
130 public void addHandler(Http2Handler handler, String path) {
131 handlers.put(path, handler);
132 }
133
134 Http2Handler getHandlerFor(String path) {
135 if (path == null || path.equals(""))
136 path = "/";
137
138 final String fpath = path;
139 AtomicReference<String> bestMatch = new AtomicReference<>("");
140 AtomicReference<Http2Handler> href = new AtomicReference<>();
141
142 handlers.forEach((key, value) -> {
143 if (fpath.startsWith(key) && key.length() > bestMatch.get().length()) {
144 bestMatch.set(key);
145 href.set(value);
146 }
147 });
148 Http2Handler handler = href.get();
149 if (handler == null)
150 throw new RuntimeException("No handler found for path " + path);
151 System.err.println("Using handler for: " + bestMatch.get());
152 return handler;
153 }
182 se.setSSLParameters(sslp);
183 se.setEnabledCipherSuites(se.getSupportedCipherSuites());
184 se.setEnabledProtocols(se.getSupportedProtocols());
185 // other initialisation here
186 return se;
187 }
188
189 public String serverName() {
190 return serverName;
191 }
192
193 /**
194 * Starts a thread which waits for incoming connections.
195 */
196 public void start() {
197 exec.submit(() -> {
198 try {
199 while (!stopping) {
200 Socket socket = server.accept();
201 InetSocketAddress addr = (InetSocketAddress) socket.getRemoteSocketAddress();
202 Http2TestServerConnection c = new Http2TestServerConnection(this, socket);
203 connections.put(addr, c);
204 try {
205 c.run();
206 } catch(Throwable e) {
207 // we should not reach here, but if we do
208 // the connection might not have been closed
209 // and if so then the client might wait
210 // forever.
211 connections.remove(addr, c);
212 c.close();
213 throw e;
214 }
215 }
216 } catch (Throwable e) {
217 if (!stopping) {
218 System.err.println("TestServer: start exception: " + e);
219 e.printStackTrace();
220 }
221 }
222 });
|
1 /*
2 * Copyright (c) 2015, 2017, 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 */
23
24 import java.io.IOException;
25 import java.net.*;
26 import java.util.*;
27 import java.util.concurrent.ExecutorService;
28 import java.util.concurrent.Executors;
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
39 /**
40 * Waits for incoming TCP connections from a client and establishes
41 * a HTTP2 connection. Two threads are created per connection. One for reading
42 * and one for writing. Incoming requests are dispatched to the supplied
43 * Http2Handler on additional threads. All threads
44 * obtained from the supplied ExecutorService.
45 */
46 public class Http2TestServer implements AutoCloseable {
47 final ServerSocket server;
48 volatile boolean secure;
49 final ExecutorService exec;
50 volatile boolean stopping = false;
51 final Map<String,Http2Handler> handlers;
115 this.serverName = serverName;
116 if (secure) {
117 server = initSecure(port);
118 } else {
119 server = initPlaintext(port);
120 }
121 this.secure = secure;
122 this.exec = exec == null ? getDefaultExecutor() : exec;
123 this.handlers = Collections.synchronizedMap(new HashMap<>());
124 this.sslContext = context;
125 this.connections = new HashMap<>();
126 }
127
128 /**
129 * Adds the given handler for the given path
130 */
131 public void addHandler(Http2Handler handler, String path) {
132 handlers.put(path, handler);
133 }
134
135 volatile Http2TestExchangeSupplier exchangeSupplier = Http2TestExchangeSupplier.ofDefault();
136
137 /**
138 * Sets an explicit exchange handler to be used for all future connections.
139 * Useful for testing scenarios where non-standard or specific server
140 * behaviour is required, either direct control over the frames sent, "bad"
141 * behaviour, or something else.
142 */
143 public void setExchangeSupplier(Http2TestExchangeSupplier exchangeSupplier) {
144 this.exchangeSupplier = exchangeSupplier;
145 }
146
147 Http2Handler getHandlerFor(String path) {
148 if (path == null || path.equals(""))
149 path = "/";
150
151 final String fpath = path;
152 AtomicReference<String> bestMatch = new AtomicReference<>("");
153 AtomicReference<Http2Handler> href = new AtomicReference<>();
154
155 handlers.forEach((key, value) -> {
156 if (fpath.startsWith(key) && key.length() > bestMatch.get().length()) {
157 bestMatch.set(key);
158 href.set(value);
159 }
160 });
161 Http2Handler handler = href.get();
162 if (handler == null)
163 throw new RuntimeException("No handler found for path " + path);
164 System.err.println("Using handler for: " + bestMatch.get());
165 return handler;
166 }
195 se.setSSLParameters(sslp);
196 se.setEnabledCipherSuites(se.getSupportedCipherSuites());
197 se.setEnabledProtocols(se.getSupportedProtocols());
198 // other initialisation here
199 return se;
200 }
201
202 public String serverName() {
203 return serverName;
204 }
205
206 /**
207 * Starts a thread which waits for incoming connections.
208 */
209 public void start() {
210 exec.submit(() -> {
211 try {
212 while (!stopping) {
213 Socket socket = server.accept();
214 InetSocketAddress addr = (InetSocketAddress) socket.getRemoteSocketAddress();
215 Http2TestServerConnection c =
216 new Http2TestServerConnection(this, socket, exchangeSupplier);
217 connections.put(addr, c);
218 try {
219 c.run();
220 } catch(Throwable e) {
221 // we should not reach here, but if we do
222 // the connection might not have been closed
223 // and if so then the client might wait
224 // forever.
225 connections.remove(addr, c);
226 c.close();
227 throw e;
228 }
229 }
230 } catch (Throwable e) {
231 if (!stopping) {
232 System.err.println("TestServer: start exception: " + e);
233 e.printStackTrace();
234 }
235 }
236 });
|