From 1bf9658ccd33b9ab666a6ffc5c1a8c13c6f87fdd Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 14 Feb 2023 14:42:01 +0100 Subject: NanoHTTPD: Remove AsyncExecutor, move socket listen to constructor --- src/main/java/fi/iki/elonen/NanoHTTPD.java | 107 ++++++++--------------------- 1 file changed, 28 insertions(+), 79 deletions(-) diff --git a/src/main/java/fi/iki/elonen/NanoHTTPD.java b/src/main/java/fi/iki/elonen/NanoHTTPD.java index 1c1abc6..610e15f 100644 --- a/src/main/java/fi/iki/elonen/NanoHTTPD.java +++ b/src/main/java/fi/iki/elonen/NanoHTTPD.java @@ -35,7 +35,6 @@ package fi.iki.elonen; import java.io.BufferedReader; import java.io.ByteArrayInputStream; -import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -69,6 +68,7 @@ import java.util.concurrent.TimeUnit; import org.apache.commons.io.output.ByteArrayOutputStream; import org.openslx.util.PrioThreadFactory; +import org.openslx.util.Util; /** * A simple, tiny, nicely embeddable HTTP server in Java @@ -144,61 +144,47 @@ public abstract class NanoHTTPD implements Runnable * re-processing. */ private static final String QUERY_STRING_PARAMETER = "NanoHttpd.QUERY_STRING"; - private final String hostname; - private final int myPort; - private ServerSocket myServerSocket; + private final ServerSocket myServerSocket; private Set openConnections = new HashSet(); /** * Pluggable strategy for asynchronously executing requests. */ - private AsyncRunner asyncRunner; + private final ExecutorService asyncRunner; protected int maxRequestSize = 0; /** * Constructs an HTTP server on given port. */ - public NanoHTTPD( int port ) + public NanoHTTPD( int port ) throws IOException { this( null, port ); } - /** - * Constructs an HTTP server on given hostname and port. - */ - public NanoHTTPD( String hostname, int port ) + public NanoHTTPD( String hostname, int port ) throws IOException { - this.hostname = hostname; - this.myPort = port; - setAsyncRunner( new DefaultAsyncRunner() ); + this( hostname, port, new ThreadPoolExecutor( 2, 24, 1, TimeUnit.MINUTES, + new ArrayBlockingQueue( 16 ), new PrioThreadFactory( "httpd", Thread.NORM_PRIORITY ) ) ); } - protected static final void safeClose( Closeable closeable ) + /** + * Constructs an HTTP server on given hostname and port. + */ + public NanoHTTPD( String hostname, int port, ExecutorService executor ) throws IOException { - if ( closeable != null ) { - try { - closeable.close(); - } catch ( IOException e ) { - } - } + this.asyncRunner = executor; + myServerSocket = new ServerSocket(); + myServerSocket.setReuseAddress( true ); + myServerSocket.bind( ( hostname != null ) ? new InetSocketAddress( hostname, port ) + : new InetSocketAddress( port ) ); } /** * Start the server. - * - * @throws IOException if the socket is in use. */ @Override public void run() { - try { - myServerSocket = new ServerSocket(); - myServerSocket.setReuseAddress( true ); - myServerSocket.bind( ( hostname != null ) ? new InetSocketAddress( hostname, myPort ) - : new InetSocketAddress( myPort ) ); - } catch ( Exception e ) { - throw new RuntimeException( e ); - } do { try { @@ -206,7 +192,7 @@ public abstract class NanoHTTPD implements Runnable registerConnection( finalAccept ); finalAccept.setSoTimeout( SOCKET_READ_TIMEOUT ); final InputStream inputStream = finalAccept.getInputStream(); - asyncRunner.exec( new Runnable() { + asyncRunner.execute( new Runnable() { @Override public void run() { @@ -218,6 +204,11 @@ public abstract class NanoHTTPD implements Runnable while ( !finalAccept.isClosed() && !finalAccept.isInputShutdown() ) { session.execute(); } + } catch ( RejectedExecutionException e ) { + try { + outputStream.write( "HTTP/1.1 503 Overloaded\r\nConnection: Close\r\n\r\n".getBytes() ); + } catch ( Exception e2 ) { + } } catch ( Exception e ) { // When the socket is closed by the client, we throw our own SocketException // to break the "keep alive" loop above. @@ -226,9 +217,7 @@ public abstract class NanoHTTPD implements Runnable e.printStackTrace(); } } finally { - safeClose( outputStream ); - safeClose( inputStream ); - safeClose( finalAccept ); + Util.safeClose( outputStream, inputStream, finalAccept ); unRegisterConnection( finalAccept ); } } @@ -250,7 +239,7 @@ public abstract class NanoHTTPD implements Runnable public void stop() { try { - safeClose( myServerSocket ); + Util.safeClose( myServerSocket ); closeAllConnections(); } catch ( Exception e ) { e.printStackTrace(); @@ -284,7 +273,7 @@ public abstract class NanoHTTPD implements Runnable public synchronized void closeAllConnections() { for ( Socket socket : openConnections ) { - safeClose( socket ); + Util.safeClose( socket ); } } @@ -431,16 +420,6 @@ public abstract class NanoHTTPD implements Runnable // // ------------------------------------------------------------------------------- // - /** - * Pluggable strategy for asynchronously executing requests. - * - * @param asyncRunner new strategy for handling threads. - */ - public void setAsyncRunner( AsyncRunner asyncRunner ) - { - this.asyncRunner = asyncRunner; - } - /** * HTTP Request methods, with the ability to decode a String * back to its enum value. @@ -460,38 +439,8 @@ public abstract class NanoHTTPD implements Runnable } } - /** - * Pluggable strategy for asynchronously executing requests. - */ - public interface AsyncRunner - { - void exec( Runnable code ); - } - // ------------------------------------------------------------------------------- // - /** - * Default threading strategy for NanoHTTPD. - *

- *

- * Uses a thread pool. - *

- */ - public static class DefaultAsyncRunner implements AsyncRunner - { - private ExecutorService pool = new ThreadPoolExecutor( 2, 24, 1, TimeUnit.MINUTES, - new ArrayBlockingQueue( 16 ), new PrioThreadFactory( "httpd", Thread.NORM_PRIORITY ) ); - - @Override - public void exec( Runnable code ) - { - try { - pool.execute( code ); - } catch ( RejectedExecutionException e ) { - } - } - } - /** * HTTP response. Return one of these from serve(). */ @@ -638,7 +587,7 @@ public abstract class NanoHTTPD implements Runnable if ( sb.length() != 0 ) { outputStream.write( sb.toString().getBytes( StandardCharsets.UTF_8 ) ); } - safeClose( data ); + Util.safeClose( data ); } protected int sendContentLengthHeaderIfNotAlreadyPresent( StringBuilder sb, @@ -981,11 +930,11 @@ public abstract class NanoHTTPD implements Runnable Response r = new Response( Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage() ); r.send( outputStream ); - safeClose( outputStream ); + Util.safeClose( outputStream ); } catch ( ResponseException re ) { Response r = new Response( re.getStatus(), MIME_PLAINTEXT, re.getMessage() ); r.send( outputStream ); - safeClose( outputStream ); + Util.safeClose( outputStream ); } } -- cgit v1.2.3-55-g7522