2626import java .io .IOException ;
2727import java .net .*;
2828import java .util .*;
29+ import java .util .concurrent .ConcurrentHashMap ;
2930import java .util .concurrent .ExecutorService ;
3031import java .util .concurrent .Executors ;
3132import java .util .concurrent .ThreadFactory ;
33+ import java .util .concurrent .atomic .AtomicLong ;
3234import java .util .concurrent .atomic .AtomicReference ;
33- import java .util .function .Consumer ;
3435import javax .net .ServerSocketFactory ;
3536import javax .net .ssl .SSLContext ;
3637import javax .net .ssl .SSLParameters ;
3738import javax .net .ssl .SSLServerSocket ;
38- import javax .net .ssl .SSLServerSocketFactory ;
39- import javax .net .ssl .SNIServerName ;
4039import jdk .internal .net .http .frame .ErrorFrame ;
4140
4241/**
4746 * obtained from the supplied ExecutorService.
4847 */
4948public class Http2TestServer implements AutoCloseable {
49+ static final AtomicLong IDS = new AtomicLong ();
50+ final long id = IDS .incrementAndGet ();
5051 final ServerSocket server ;
5152 final boolean supportsHTTP11 ;
5253 volatile boolean secure ;
5354 final ExecutorService exec ;
54- volatile boolean stopping = false ;
55+ private volatile boolean stopping = false ;
5556 final Map <String ,Http2Handler > handlers ;
5657 final SSLContext sslContext ;
5758 final String serverName ;
58- final HashMap < InetSocketAddress , Http2TestServerConnection > connections ;
59+ final Set < Http2TestServerConnection > connections ;
5960 final Properties properties ;
61+ final String name ;
6062
6163 private static ThreadFactory defaultThreadFac =
6264 (Runnable r ) -> {
@@ -177,6 +179,7 @@ public Http2TestServer(InetAddress localAddr,
177179 boolean supportsHTTP11 )
178180 throws Exception
179181 {
182+ this .name = "TestServer(%d)" .formatted (id );
180183 this .serverName = serverName ;
181184 this .supportsHTTP11 = supportsHTTP11 ;
182185 if (secure ) {
@@ -193,7 +196,7 @@ public Http2TestServer(InetAddress localAddr,
193196 this .exec = exec == null ? getDefaultExecutor () : exec ;
194197 this .handlers = Collections .synchronizedMap (new HashMap <>());
195198 this .properties = properties == null ? new Properties () : properties ;
196- this .connections = new HashMap <> ();
199+ this .connections = ConcurrentHashMap . newKeySet ();
197200 }
198201
199202 /**
@@ -232,7 +235,7 @@ Http2Handler getHandlerFor(String path) {
232235 Http2Handler handler = href .get ();
233236 if (handler == null )
234237 throw new RuntimeException ("No handler found for path " + path );
235- System .err .println (" Using handler for: " + bestMatch .get ());
238+ System .err .println (name + ": Using handler for: " + bestMatch .get ());
236239 return handler ;
237240 }
238241
@@ -246,8 +249,8 @@ final ServerSocket initPlaintext(int port, int backlog) throws Exception {
246249 public synchronized void stop () {
247250 // TODO: clean shutdown GoAway
248251 stopping = true ;
249- System .err .printf ("Server stopping %d connections\n " , connections .size ());
250- for (Http2TestServerConnection connection : connections . values () ) {
252+ System .err .printf ("%s: stopping %d connections\n " , name , connections .size ());
253+ for (Http2TestServerConnection connection : connections ) {
251254 connection .close (ErrorFrame .NO_ERROR );
252255 }
253256 try {
@@ -284,11 +287,56 @@ public String serverName() {
284287
285288 private synchronized void putConnection (InetSocketAddress addr , Http2TestServerConnection c ) {
286289 if (!stopping )
287- connections .put ( addr , c );
290+ connections .add ( c );
288291 }
289292
290293 private synchronized void removeConnection (InetSocketAddress addr , Http2TestServerConnection c ) {
291- connections .remove (addr , c );
294+ connections .remove (c );
295+ }
296+
297+ record AcceptedConnection (Http2TestServer server ,
298+ Socket socket ) {
299+ void startConnection () {
300+ String name = server .name ;
301+ Http2TestServerConnection c = null ;
302+ InetSocketAddress addr = null ;
303+ try {
304+ addr = (InetSocketAddress ) socket .getRemoteSocketAddress ();
305+ System .err .println (name + ": creating connection" );
306+ c = server .createConnection (server , socket , server .exchangeSupplier );
307+ server .putConnection (addr , c );
308+ System .err .println (name + ": starting connection" );
309+ c .run ();
310+ System .err .println (name + ": connection started" );
311+ } catch (Throwable e ) {
312+ boolean stopping = server .stopping ;
313+ if (!stopping ) {
314+ System .err .println (name + ": unexpected exception: " + e );
315+ e .printStackTrace ();
316+ }
317+ // we should not reach here, but if we do
318+ // the connection might not have been closed
319+ // and if so then the client might wait
320+ // forever.
321+ if (c != null ) {
322+ server .removeConnection (addr , c );
323+ }
324+ try {
325+ if (c != null ) c .close (ErrorFrame .PROTOCOL_ERROR );
326+ } catch (Exception x ) {
327+ if (!stopping )
328+ System .err .println (name + ": failed to close connection: " + e );
329+ } finally {
330+ try {
331+ socket .close ();
332+ } catch (IOException x ) {
333+ if (!stopping )
334+ System .err .println (name + ": failed to close socket: " + e );
335+ }
336+ }
337+ System .err .println (name + ": failed to start connection: " + e );
338+ }
339+ }
292340 }
293341
294342 /**
@@ -298,38 +346,37 @@ public void start() {
298346 exec .submit (() -> {
299347 try {
300348 while (!stopping ) {
349+ System .err .println (name + ": accepting connections" );
301350 Socket socket = server .accept ();
302- Http2TestServerConnection c = null ;
303- InetSocketAddress addr = null ;
351+ System .err .println (name + ": connection accepted" );
304352 try {
305- addr = (InetSocketAddress ) socket .getRemoteSocketAddress ();
306- c = createConnection (this , socket , exchangeSupplier );
307- putConnection (addr , c );
308- c .run ();
353+ var accepted = new AcceptedConnection (this , socket );
354+ exec .submit (accepted ::startConnection );
309355 } catch (Throwable e ) {
356+ if (!stopping ) {
357+ System .err .println (name + ": unexpected exception: " + e );
358+ e .printStackTrace ();
359+ }
310360 // we should not reach here, but if we do
311361 // the connection might not have been closed
312362 // and if so then the client might wait
313363 // forever.
314- if (c != null ) {
315- removeConnection (addr , c );
316- c .close (ErrorFrame .PROTOCOL_ERROR );
317- } else {
318- socket .close ();
319- }
320- System .err .println ("TestServer: start exception: " + e );
364+ System .err .println (name + ": start exception: " + e );
321365 }
366+ System .err .println (name + ": stopping is: " + stopping );
322367 }
323368 } catch (SecurityException se ) {
324- System .err .println ("TestServer : terminating, caught " + se );
369+ System .err .println (name + " : terminating, caught " + se );
325370 se .printStackTrace ();
326371 stopping = true ;
327372 try { server .close (); } catch (IOException ioe ) { /* ignore */ }
328373 } catch (Throwable e ) {
329374 if (!stopping ) {
330- System .err .println ("TestServer : terminating, caught " + e );
375+ System .err .println (name + " : terminating, caught " + e );
331376 e .printStackTrace ();
332377 }
378+ } finally {
379+ System .err .println (name + ": finished" );
333380 }
334381 });
335382 }
@@ -343,6 +390,7 @@ protected Http2TestServerConnection createConnection(Http2TestServer http2TestSe
343390
344391 @ Override
345392 public void close () throws Exception {
393+ System .err .println (name + ": closing" );
346394 stop ();
347395 }
348396}
0 commit comments