import java.net.*; import java.io.*; import java.util.*; /* * EasyWebServer is a simple web server that can provide limited * service. Specifically, it can return one of the three pages:

*

    *
  1. the main home page which contains a couple real links, *
  2. a sample.html page which contains other forms of html * components such as images and lists, and *
  3. a search page that can take input data from the browser *
* * @author Xiannong Meng xmeng@bucknell.edu * Fall 2002 * Revised Fall 2003, 2004, 2006 * */ public class EasyWebServer { public static void main(String[] args) throws IOException { if (args.length != 1) { System.out.println("usage java EasyWebServer port"); System.exit(-1); } PORT = Integer.parseInt(args[0]); /* open a server socket at the given port */ ServerSocket server = new ServerSocket(PORT); String inBuffer; /* the server is running forever (when not crashed :0) */ for (;;) { try { /* accept an incoming connection request */ Socket sock = server.accept(); /* prepare for input and output stream */ BufferedReader sockIn = new BufferedReader (new InputStreamReader (sock.getInputStream())); DataOutputStream sockOut = new DataOutputStream(sock.getOutputStream()); inBuffer = readAll(sockIn); http_data = Http.ParseToken(inBuffer); // echo the command, for debug purposes System.out.print("inBuffer : " + inBuffer); System.out.println(); System.out.println("!"+http_data.get("content-length")+"!"); // now process the command, return results when required processHTTPCmd(inBuffer, sockIn, sockOut); /* close the connection */ sock.close(); } catch (IOException ignored) {} } } /* * Reads and returns all the information from a client (browser). * This typically is a request (get or post) from a client.

* * @param fileIn a pointer to the buffered reader where the client * sends in the information. * @author Xiannong Meng */ public static String readAll(BufferedReader fileIn) { String inBuffer = ""; try { String line; do { line = fileIn.readLine(); inBuffer += line + "\r\n"; // System.out.print("in readAll -> " + line + "<-"); if (line.length() == 2 && line.compareTo("\r\n") == 0) { System.out.println("we hit the break in readAll"); break; } } while (line.length() > 0); } catch (IOException ignored) {}; System.out.println("\n end of readAll -> " + inBuffer + "<-"); return inBuffer; } /* * Process the request (cmd) by a client. Determine what to * do based on the parsing result.

* * The results are directly written to the output stream back * to the client.

* * @param cmd the client request * @param sockIn socket input stream * @param sockOut socket output stream * * @author Xiannong Meng * */ public static void processHTTPCmd(String cmd, BufferedReader sockIn, DataOutputStream sockOut) { String operation; // the operation requested String path; // the path to the HTML doc String version; // version of http int returnStatus = 200; // status of operation long returnLength = 0; // length of the doc to return boolean isForm = false; // by default it is not a form input /* take the input command and split it into tokens */ /* here is an example of the command */ /* get /path http/1.0 \r\n */ StringTokenizer tokens = new StringTokenizer(cmd, " \r\n"); operation = (tokens.nextToken()).toUpperCase(); path = tokens.nextToken(); version = (tokens.nextToken()).toUpperCase(); /* for debugging purpose */ System.out.println("operation: " + operation); System.out.println("path: " + path); System.out.println("version: " + version); /* check for a request that we dont' understand */ if ((operation.compareTo("GET") != 0 && operation.compareTo("POST") != 0) || ((version.compareTo("HTTP/1.0") != 0) && (version.compareTo("HTTP/1.1") != 0))) { returnStatus = 400; returnLength = ERROR_400.length(); } else /* the request is trying to get some HTML page */ if (path.compareTo("/") == 0) { returnStatus = 200; returnLength = HOME_PAGE.length(); } else if (path.compareTo("/sample.html") == 0) { returnStatus = 200; File f = new File("sample.html"); returnLength = f.length(); } else if (path.compareTo("/search") == 0) { returnStatus = 200; File f = new File("form.html"); returnLength = f.length(); } else if (path.compareTo("/cross.gif") == 0) { returnStatus = 200; File f = new File("cross.gif"); returnLength = f.length(); } else if (path.compareTo("/form") == 0) isForm = true; else /* the page is unknown */ { returnStatus = 404; returnLength = ERROR_404.length(); } /* now that we know what to do, send the result back */ if (isForm == true) // this is a form request { processForm(sockIn, sockOut); } else try { if (path.compareTo("/cross.gif") == 0) sendHeader(sockOut, returnStatus, returnLength, "image/gif"); else sendHeader(sockOut, returnStatus, returnLength, "text/html"); switch (returnStatus) { case 200: // send the page requested if (path.compareTo("/") == 0) sockOut.writeBytes(HOME_PAGE); // short page else if (path.compareTo("/sample.html") == 0) openAndSendFile(sockOut, "sample.html"); // long page else if (path.compareTo("/cross.gif") == 0) openAndSendFile(sockOut, "cross.gif"); // image page else openAndSendFile(sockOut, "form.html"); // a test form break; case 400: sockOut.writeBytes(ERROR_400); break; case 404: sockOut.writeBytes(ERROR_404); break; } } catch (IOException ignored) {} } /* * Send the returning header to the client, based on the return * status. The response must follow the HTTP protocol.

* * @param out output stream of the socket * @param returnStatus the numerical code for the returning status * @param contentLength the length of the content (not the header) * @param contentType the type of the return content * * @author Xiannong Meng * */ static void sendHeader(DataOutputStream out, int returnStatus, long contentLength, String contentType) { String statusStr; String returnContent; switch (returnStatus) { case 200: statusStr = "OK"; break; case 400: statusStr = "Bad Request"; break; case 404: statusStr = "Not Found"; break; default: statusStr = "Unknown"; break; } /* * send an HTTP/1.0 response with Server, Content-Length, * and Content-Type headers. */ try { returnContent = "HTTP/1.0 " + returnStatus + " " + statusStr + "\r\n"; out.writeBytes(returnContent); returnContent = "Server: " + SERVER_NAME + "\r\n"; out.writeBytes(returnContent); returnContent = "Content-Length: " + contentLength + "\r\n"; out.writeBytes(returnContent); returnContent = "Content-Type: " + contentType + "\r\n"; out.writeBytes(returnContent); returnContent = "\r\n"; out.writeBytes(returnContent); } catch (IOException ignored){} } /* * Send the file requested to the output stream (client).

* * @param out output stream to the client. * @param fileToSend string name of the file to be sent. * * @author Xiannong Meng * */ static void openAndSendFile(DataOutputStream out, String fileToSend) { try { DataInputStream fileIn = new DataInputStream (new FileInputStream (new File(fileToSend))); File f = new File(fileToSend); long length = f.length(); byte[] content = new byte[(int)length]; fileIn.readFully(content); out.write(content); } catch (IOException ignored) {}; } /* * Process the form sent from the client. The content of the form * has been stored in http_data, a member of the class.

* * @param sockIn input stream from the client. * @param sockOut output stream to the client * */ public static void processForm(BufferedReader sockIn, DataOutputStream sockOut) { try { String inBuffer; String returnString = ""; int returnStatus; int returnLength; int dataLength = Integer.parseInt (((String)http_data.get("content-length")).trim()); System.out.println("data length " + dataLength); char[] inChars = new char[dataLength]; sockIn.read(inChars, 0, dataLength); inBuffer = new String(inChars); // for debugging only System.out.print(inBuffer); // // Parse the CGI input string // Hashtable form_data = Html.ParseToken(inBuffer); // // Print out each of the name/value pairs // from sent from the browser. // returnString += Html.Variables(form_data); returnString += "


"; // // Create the Bottom of the returned HTML page - which closes it cleanly. // returnString += Html.HtmlBot(); // // Print the required CGI header. // returnStatus = 200; returnLength = returnString.length(); sendHeader(sockOut, returnStatus, returnLength, "text/html"); // // Send back the contents // sockOut.writeBytes(returnString); } catch (IOException ignored) {}; } /* this is the class data segments */ static int PORT; // the port used for communication static Hashtable http_data; // HTTP header infromation from client // name of the server static String SERVER_NAME = "CSCI 335 Project Web Server"; // error message 400 static String ERROR_400 = "

Error 400

The server couldn't understand your request.\n"; // error message 404 static String ERROR_404 = "

Error 404

Document not found.\n"; // a simple, short home page static String HOME_PAGE = "

Welcome to the CSCI 335 Demo Server

Why not visit:

\n"; }