import java.io.*;
import java.net.*;
import java.util.*;

/**
 * HTTP 1.0 Server.
 *
 * Only implements HTTP GET requests and directory listings.
 *
 * @author Jose Sandoval - jose@josesandoval.com - January 25, 2003.
 * @version 2.0
 */
public class JWebServer {
    // List on port number
    private int portNumber;

    // Server identifier
    private static final String SERVER_ID = "Jose Sandoval HTTP Server/1.0";


    // Socket
    private ServerSocket listenSocket;

    /**
     * Main
     *
     * @param args String[]
     * @throws Exception
     */
    static public void main( String[] args ) throws Exception   {
	// Check for the correct number of arguments
	if (args.length != 1) {
	    System.out.println("Usage: java -jar web.jar <portNumber>");
	    System.exit(1);
	}

	// Get portNumber
	int portNumber = Integer.parseInt(args[0]);

	// Run server
	System.out.println("Starting " + SERVER_ID);
	new JWebServer(portNumber).runServer();
    }

    /** 
     * Constructor 
     */
    public JWebServer() {
	super();
    }

    /**
     * Constructor
     *
     * @param port int
     */
    public JWebServer(int port) {
	super();
	portNumber = port;
	init();
    }

    /** Init */
    private void init() {
	// Open server socket
        try {
	    listenSocket = new ServerSocket(portNumber);
        } catch (Exception e) {
	    e.printStackTrace();
        }
    }

    /**
      * Run server - Wait and handle request in separete thread
      */
    private void runServer() throws Exception {
	while (true) {
	    new HandleRequest(listenSocket.accept()).start();
	}
    }

    /**
    * Handle HTTP request in it's own thread.
    *
    * Only implements HTTP GET requests and directory listings.
    *
    * @author Jose Sandoval - jose@josesandoval.com - February 28, 2003.
    */
    class HandleRequest extends Thread {
	// Client
	Socket connectionSocket;
	
	// End Of Line
	private static final String EOL = "\r\n";


	public HandleRequest(Socket aSocket) {
	    super();
	    connectionSocket = aSocket;
	}

	public HandleRequest() {
	    super();
	}
    
	/**
	* Serve request in separate thread
	*/
	public void run() {
	    String requestMessageLine = null;
	    String fileName = null;
	    String requestMethod = null;
    
	    // Readers
	    BufferedReader inFromClient = null;
	    DataOutputStream outToClient = null;
    
	    // Request line
	    StringTokenizer tokenizedLine = null;
    
	    try {
		// Reader and Writer
		inFromClient = new BufferedReader( new InputStreamReader(connectionSocket.getInputStream()) );
		outToClient = new DataOutputStream( connectionSocket.getOutputStream() );
    
		// Get request line
		requestMessageLine = inFromClient.readLine();
		tokenizedLine = new StringTokenizer(requestMessageLine);
    
		// Serving
		consoleMessage(requestMessageLine);
    
		// Check that there are tokens
		if (tokenizedLine.countTokens() >= 2) {
		    // Get request method
		    requestMethod = tokenizedLine.nextToken();
		    
		    // We have at least 2 tokens and 2nd token shold be some file name
		    fileName = tokenizedLine.nextToken();
    
		    // We handle GET request only
		    if (requestMethod.equals("GET")) {
			// Do GET request
			doGetRequest(fileName, outToClient);
		    } else {
			// Unknown request method
			doBadRequest(outToClient);
		    }
		} else {
		    // No tokens, assume bad request
		    doBadRequest(outToClient);
		}
    
		// Request served, clean up
		inFromClient.close();
		outToClient.close();
		connectionSocket.close();
	    } catch (Exception e) {
		e.printStackTrace();
		throw new RuntimeException(e.getMessage());
	    }
	}

	/**
	* Replace occurance of pattern with replace in str.
	* @param str
	* @param pattern
	* @param replace
	* @return String
	*/
	public String myReplace(String str, String pattern, String replace) {
	    int s = 0;
	    int e = 0;
	    StringBuffer result = new StringBuffer();
	    while ((e = str.indexOf(pattern, s)) >= 0) {
		result.append(str.substring(s, e));
		result.append(replace);
		s = e + pattern.length();
	    }

	    result.append(str.substring(s));
	    return result.toString();
	}

	/**
	* Handle GET HTTP request.
	*
	* @param fileName String
	* @param out DataOutputStream
	* @throws Exception All exceptions are thrown
	*/
	private void doGetRequest(String fileName, DataOutputStream out) throws Exception {
	    // If it's a dir
	    if (fileName.endsWith("/")) {
		fileName = fileName + "index.html";
	    }

	    // Clean file name
	    if (fileName.startsWith("/")) {
		fileName = fileName.substring(1);
	    }

	    // Check if file exists and is not a directory
	    // We don't handle directory listings
	    File file = new File(fileName);
	    if ( file.isDirectory()) {
		doDirectoryListing(out, fileName, file.list());
	    } else if (file.exists() && !file.isDirectory()) {
		doFileExist(out, fileName);
	    } else {
		doFileNotFound(out);
	    }
	}

	/**
	* Get content type depending on file extention. Only HTML, GIF and JPG are handled.
	*
	* @param fileName String File name
	* @return String Content type
	* @throws Exception
	*/
	private String doGetContentType(String fileName) throws Exception {
	    String contentType = null;
    
	    // Check for file type requested
	    if (fileName.toLowerCase().endsWith(".html") || fileName.toLowerCase().endsWith(".htm")) {
		contentType = "text/html";
	    } else if (fileName.toLowerCase().endsWith(".gif")) {
		contentType = "image/gif";
	    } else if (fileName.toLowerCase().endsWith(".jpg")) {
		contentType = "image/jpeg";
	    } else {
		// Let user agent handle the file
		contentType = "unknown/unknown";
	    }
    
	    return contentType;
	}

	/**
	* Serve file if it exists
	*
	* @param out DataOutputStream 
	* @param fileName String 
	* @throws RuntimeException
	*/
	private void doFileExist(DataOutputStream out, String fileName) {
	    try {
		// Get file ready
		int numOfBytes = (int) new File(fileName).length();
		FileInputStream inFile = new FileInputStream(fileName);
		byte[] fileInBytes = new byte[numOfBytes];
		inFile.read(fileInBytes);
    
		// HTTP response
		out.writeBytes("HTTP/1.0 200 OK" + EOL);
		out.writeBytes("Date: " + new Date() + EOL);
		out.writeBytes("Server: " + SERVER_ID + EOL);
		out.writeBytes("Content-Length: " + numOfBytes + EOL);
		out.writeBytes("Content-Type: " + doGetContentType(fileName) + EOL);
		out.writeBytes(EOL);
		out.write(fileInBytes, 0, numOfBytes);
    
		// Clean up
		inFile.close();
	    } catch (Exception e) {
		throw new RuntimeException(e.getMessage());
	    }
		
	    consoleMessage("HTTP/1.0 200 OK");
	}

	/**
	* Serve directory listing
	*
	* @param out DataOutputStream 
	* @param fileName String 
	* @param fileList String[]
	* @throws RuntimeException
	*/
	private void doDirectoryListing(DataOutputStream out, String fileName, String[] fileList) {
	    try {
		StringBuffer listing = new StringBuffer();

		listing.append("<html><head><title>Directory listing for ").append(fileName);
		listing.append("</title></head>");
		listing.append("<body>");
		listing.append("<h1>Directory listing for: ").append(fileName).append("</h1>");
		listing.append("<table border=0 width=80% cellpadding=8 cellspacing=0>");
		listing.append("<tr><td width=40%><b>Name</b></td> <td width=40%><b>Last modified</b></td> <td width=20%><b>Size in bytes</b></td></tr>");
		listing.append("<tr><td colspan=3><hr size=1 noshadow></td></tr>");

		boolean isDirectory = false;
		File fileInfo = null;
		String thisFileName = null;
		for (int i = 0; i<fileList.length; i++) {
		    listing.append("<tr>");
		    listing.append("<td>");

		    // Check if file is a directory
		    thisFileName = fileList[i];
		    fileInfo = new File(thisFileName);
		    isDirectory = fileInfo.isDirectory();
		    listing.append("<a href='/").append(fileName).append("/").append(thisFileName).append("'>").append(thisFileName);
		    if (isDirectory) {
			listing.append("/");
		    }
		    listing.append("</a>");
		    listing.append("</td>");

		    listing.append("<td>");
		    listing.append(new Date(fileInfo.lastModified())); 
		    listing.append("</td>");

		    listing.append("<td>");
		    if (isDirectory) {
			listing.append("-");
		    } else {
			listing.append(fileInfo.length());
		    }
		    listing.append("</td>");
		    listing.append("</tr>");
		}

		listing.append("<tr><td colspan=3><hr size=1 noshadow></td></tr>");
		listing.append("<tr><td colspan=3><font size=1><i>Server by <a href='mailto:jose@josesandoval'>jose@josesandoval.com</a></i></font></td></tr>");
		listing.append("</table>");
		listing.append("</body>");
		listing.append("</html>");

		// HTTP response
		out.writeBytes("HTTP/1.0 404 Not Found" + EOL);
		out.writeBytes("Date: " + new Date() + EOL);
		out.writeBytes("Server: " + SERVER_ID + EOL);
		out.writeBytes("Content-Type: text/html" + EOL);
		out.writeBytes(EOL);
		out.writeBytes(listing.toString());
	    } catch (Exception e) {
		throw new RuntimeException(e.getMessage());
	    }

	    consoleMessage("HTTP/1.0 200 OK");
	}
    
	/**
	* File not found HTTP response.
	*
	* @param out DataOutputStream
	* @throws Exception
	*/
	private void doFileNotFound(DataOutputStream out) throws Exception {
	    // HTTP response
	    out.writeBytes("HTTP/1.0 404 Not Found" + EOL);
	    out.writeBytes("Date: " + new Date() + EOL);
	    out.writeBytes("Server: " + SERVER_ID + EOL);
	    out.writeBytes("Content-Type: text/html" + EOL);
	    out.writeBytes(EOL);
	    out.writeBytes("<HTML>\n <HEAD>\n  <TITLE>\n   404 Not Found\n  </TITLE>\n </HEAD>\n <BODY>\n  404 File Not Found\n </BODY>\n</HTML>" + EOL);
	    
	    consoleMessage("HTTP/1.0 404 Not Found");
	}
	
	/**
	* Bad request HTTP response.
	*
	* @param out DataOutputStream
	* @throws Exception
	*/
	private void doBadRequest(DataOutputStream out) throws Exception {
	    // HTTP response
	    out.writeBytes("HTTP/1.0 400 Illegal Request" + EOL);
	    out.writeBytes("Date: " + new Date() + EOL);
	    out.writeBytes("Server: " + SERVER_ID + EOL);
	    out.writeBytes("Content-Type: text/html" + EOL);
	    out.writeBytes(EOL);
	    out.writeBytes("<HTML>\n <HEAD>\n  <TITLE>\n   400 Illegal Request\n  </TITLE>\n </HEAD>\n <BODY>\n  400 Illegal Request\n </BODY>\n</HTML>" + EOL);

	    consoleMessage("HTTP/1.0 400 Illegal Request");
	}

	/**
	* Display console message.
	*
	* @param message String
	*/
	private void consoleMessage(String message) {
	    System.out.println(message);
	}
    }
}
Syntax Highlighting created using the com.Ostermiller.Syntax package.
Sunday, March 02 2003 at 22:20