Skip to content

Instantly share code, notes, and snippets.

@skanga
Created December 8, 2017 19:53
Show Gist options
  • Save skanga/d5737a4339fea498b8e67b6fd3842820 to your computer and use it in GitHub Desktop.
Save skanga/d5737a4339fea498b8e67b6fd3842820 to your computer and use it in GitHub Desktop.
Multi threaded HTTP server in Java that will only serve 1 single file for ANY http request
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
// Serve only a single specific file for ANY http request
public class SingleFileHTTPServer
{
private static final String serverName = "SingleFileHTTPServer";
private static final String serverVer = "1.0";
private static final Logger logger = Logger.getLogger (serverName);
private static final int numThreads = 2;
private final byte[] httpHeader;
private final int httpPort;
private final Path filePath;
public SingleFileHTTPServer (String fileName, int httpPort)
{
String mimeType = URLConnection.getFileNameMap ().getContentTypeFor (fileName);
filePath = Paths.get (fileName);
this.httpPort = httpPort;
String header = "HTTP/1.0 200 OK\r\n"
+ "Server: " + serverName + " " + serverVer + "\r\n"
+ "Content-length: " + new File (fileName).length () + "\r\n"
+ "Content-type: " + mimeType + "\r\n\r\n";
this.httpHeader = header.getBytes (Charset.forName ("US-ASCII"));
}
public void start ()
{
ExecutorService threadPool = Executors.newFixedThreadPool (numThreads);
try (ServerSocket serverSocket = new ServerSocket (this.httpPort))
{
logger.info ("Accepting connections on port " + serverSocket.getLocalPort ());
while (true)
{
try
{
Socket clientSocket = serverSocket.accept ();
threadPool.submit (new HTTPHandler (clientSocket));
}
catch (IOException ex)
{
logger.log (Level.WARNING, "Exception accepting connection", ex);
}
catch (RuntimeException ex)
{
logger.log (Level.SEVERE, "Unexpected error", ex);
}
}
}
catch (IOException ex)
{
logger.log (Level.SEVERE, "Could not start server", ex);
}
}
private class HTTPHandler implements Callable <Void>
{
private final Socket clientSocket;
HTTPHandler (Socket clientSocket)
{
this.clientSocket = clientSocket;
}
@Override
public Void call () throws IOException
{
try
{
OutputStream outStream = new BufferedOutputStream (clientSocket.getOutputStream ());
InputStream inStream = new BufferedInputStream (clientSocket.getInputStream ());
// read the first line only; that's all we need
StringBuilder httpRequest = new StringBuilder (80);
while (true)
{
int currChar = inStream.read ();
if (currChar == '\r' || currChar == '\n' || currChar == -1) break;
httpRequest.append ((char) currChar);
}
// If this is HTTP/1.0 or later send a MIME header
if (httpRequest.toString ().indexOf ("HTTP/") != -1)
{
outStream.write (httpHeader);
}
Files.copy (filePath, outStream);
outStream.flush ();
}
catch (IOException ex)
{
logger.log (Level.WARNING, "Error writing to client", ex);
}
finally
{
clientSocket.close ();
}
return null;
}
}
public static void main (String[] args)
{
// set the port to listen on
int port;
try
{
port = Integer.parseInt (args[1]);
if (port < 1 || port > 65535) port = 80;
}
catch (RuntimeException ex)
{
port = 80;
}
try
{
SingleFileHTTPServer server = new SingleFileHTTPServer (args[0], port);
server.start ();
}
catch (ArrayIndexOutOfBoundsException ex)
{
System.out.println ("Usage: java SingleFileHTTPServer filename port");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment