/////////////////////////////////////////////// // // // An HTTP 1.1 compliant web server // // (Version 0.5) // // Copyright 1999-2001 D. Clayton // // You may freely use this code so long as // // this header is not modified. // // // /////////////////////////////////////////////// import java.io.*; import java.net.*; import java.util.*; public class WebServer { public static int PORT = 8080; // port on which the server runs public static void main(String [] args) { try { ServerSocket s = new ServerSocket(PORT); // create a server socket waiting for client connections for (;;) { // loop for infinity... Socket connection = s.accept(); // a client has opened the connection System.out.println("Spawning server thread..."); new ServerThread( connection ).start(); // start the thread to handle the new connection } // end server loop } catch (Exception e) { System.out.println(e); // catch any exceptions } } } // end main class ServerThread extends Thread { // these variables configure the default paths for the server // mapping from http://www.wherever:8080/ to the filestore representing it // **** Change this to any path in CS with read access to see better // **** demonstrations than the couple of pages I put up. ;) public static String WEBDIR = "d:\\nwthack\\"; // default index page filename public static String DEFAULT = "index.html"; // default "404 File not Found" html page public static String FNFPATH = "\\it\\fnf.html"; // default "403 Forbidden" html page public static String FORBPATH = "\\it\\forb.html"; // the above two files themselves private static File fnf404 = new File(FNFPATH); private static File forb403 = new File(FORBPATH); public ServerThread( Socket c ) { connection = c; } // end constructor for the thread public void run() { BufferedReader in; BufferedOutputStream out; String ver; String httpRequestURI; try { // attach primary (buffered) I/O streams to the socket in = new BufferedReader (new InputStreamReader(connection.getInputStream())); out = new BufferedOutputStream(connection.getOutputStream()); String input[] = new String[128]; // the input header buffer boolean done = false; boolean donereading = false; // control variables int i = 0; String str; while (!donereading) { // read the Client's output (request header) str = in.readLine(); if (str == null) { donereading = true; if (i == 0) { done = true; } } if (!(str.equals(""))) { input[ i++ ] = str; } else { donereading = true; } System.out.println("Input: " + str); // echo to stdout for debugging } // end the initial request header read loop // now the fun begins... processing the request header and trying to figure out what the client's asking for while (!done) { // persistent connection implementation String httpMethod; // get request line and parse // split up request line to get method, URI and HTTP version of Client StringTokenizer t = new StringTokenizer(input[0], " \n\r"); try { httpMethod = t.nextToken(); httpRequestURI = t.nextToken(); ver = t.nextToken(); } catch (Exception e) { System.out.println("Malformed URI"); connection.close(); // this should return a 400er (error) return; } // end request line parse // process the request. At the moment only the "get" method is supported if (httpMethod.equals("GET")) { // create file from URI String path = WEBDIR + httpRequestURI; // construct a full path System.out.println("Request for: " + path); File target = new File(path); // create a new file from the path String MIME = getMIMEtype( target ); // get the MIME type boolean bin = (MIME.equals("text/html") || MIME.equals("text/plain")) ? false : true; // figure out whether file is binary or text from its MIME type // now check whether file is a directory or not if (target.isDirectory()) { if (!path.endsWith("/")) { path = path + "/"; httpRequestURI = httpRequestURI + "/"; } String defaultPath = path + DEFAULT; File newTarget = new File(defaultPath); if (newTarget.exists()) { // if an index page exists, use that... if (newTarget.canRead()) { outputHead(out, 200, newTarget, MIME, httpRequestURI, ver); outputBody(out, bin, newTarget, httpRequestURI); } else { System.out.println("Forbidden, sending reply"); outputHead(out, 403, forb403, "text/html", httpRequestURI, ver); outputBody(out, false, forb403, httpRequestURI); } } else { // otherwise generate an index page (directory listing) outputHead(out, 200, target, "text/html", httpRequestURI, ver); outputBody(out, false, target, httpRequestURI); } } else { if (target.exists()) { if (target.canRead()) { outputHead(out, 200, target, MIME, httpRequestURI, ver); outputBody(out, bin, target, httpRequestURI); } else { outputHead(out, 403, forb403, "text/html", httpRequestURI, ver); outputBody(out, false, forb403, httpRequestURI); } } else { outputHead(out, 404, fnf404, "text/html", httpRequestURI, ver); outputBody(out, false, fnf404, httpRequestURI); } } } else if (httpMethod.equals("POST")) { System.out.println("post?"); } // done = true; if (ver.equals("HTTP/1.0")) { done = true; } else { i = 0; while (!donereading) { str = in.readLine(); if (str == null) { donereading = true; if (i == 0) { done = true; } } if (!(str.equals(""))) { input[ i++ ] = str; } else { donereading = true; } System.out.println("Input: " + str); } // end next input read } // end connection state testing } // end persistent connection loop // Close the connection and terminate this thread System.out.println("Connection closed by server"); connection.close(); } catch (Exception e) { System.out.println(e); // should be to log file } // end try block } // end run method private Socket connection; public static synchronized void outputHead( BufferedOutputStream out, int statusCode, File content, String MIME, String URI, String ver ) { long contentLen = content.length(); PrintWriter hout = new PrintWriter(out); System.out.println("Sending header, mime type " + MIME + ", size " + contentLen ); hout.println( ver + " " + statusCode + " " + "OK" ); hout.println("Date: " + getDate()); System.out.println("Date: " + getDate()); hout.println("Server: HoshiWebServer 0.2"); hout.println("Content-base: " + URI); hout.println("Content-type: " + MIME); hout.println("Content-length: " + contentLen); // unless directory... hout.println("Last-modified: Mon, 15 Feb 1999 22:20:00 GMT\n"); hout.flush(); } // output header file public static synchronized void outputBody( BufferedOutputStream out, boolean bin, File source, String httpRequestURI ) { if (source.isDirectory()) { // list directory System.out.println("Listing directory."); PrintWriter dout = new PrintWriter(out); String dir[] = new String[128]; dir = source.list(); dout.println("Directory " + httpRequestURI + ""); dout.flush(); } else { if ( bin ) { System.out.println("Sending binary file."); BufferedInputStream fin; try { fin = new BufferedInputStream (new FileInputStream(source)); } catch (FileNotFoundException e) { System.out.println("File not found, is someone messing with the filestore?"); return; // couldn't send file } try { System.out.println("Sending binary file."); int b = fin.read(); while (b != -1) { out.write(b); b = fin.read(); } out.flush(); fin.close(); } catch (IOException e) { System.out.println("IO Exception." + e); } } else { System.out.println("Sending text file."); BufferedReader fin; try { fin = new BufferedReader (new FileReader(source)); } catch (FileNotFoundException e) { System.out.println("File not found, is someone messing with the filestore?"); return; // couldn't send file } PrintWriter tout = new PrintWriter(out); String str; try { str = fin.readLine(); while (str != null) { tout.println(str); str = fin.readLine(); } fin.close(); tout.flush(); } catch (Exception e) { System.out.println("Exception: " + e); } } } } public static String getMIMEtype( File source ) { String fileName = source.getName(); if (source.isDirectory()) { fileName = null; return "text/html"; } String fileExt = "???", MIMEtype; StringTokenizer s = new StringTokenizer(fileName, "."); while (s.hasMoreTokens()) { fileExt = s.nextToken(); } System.out.println("Filename: " + fileName); if (fileExt.equals("html")) { MIMEtype = "text/html"; } else if (fileExt.equals("gif")) { MIMEtype = "image/gif"; } else if (fileExt.equals("jpg")) { MIMEtype = "image/jpeg"; } else if (fileExt.equals("txt")) { MIMEtype = "text/plain"; } else if (fileExt.equals("htm")) { MIMEtype = "text/html"; } else { System.out.println("Unknown MIME type: " + fileExt); MIMEtype = "application/octet-stream"; } return MIMEtype; } public static String getDate() { Calendar c = new GregorianCalendar(); int month = c.get(Calendar.MONTH) + 1; int h,m,s; String ms,ss; if (c.get(Calendar.AM_PM) == 1) { h = c.get(Calendar.HOUR) + 12; if (h == 24) { h = 0; } } else { h = c.get(Calendar.HOUR); } m = c.get(Calendar.MINUTE); s = c.get(Calendar.SECOND); if (m < 10) { ms = "0" + m; } else { ms = "" + m; } if (s < 10) { ss = "0" + s; } else { ss = "" + s; } return c.get(Calendar.DAY_OF_MONTH)+"/"+month+"/"+c.get(Calendar.YEAR)+ " "+h+":"+ms+":"+ss; } }