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:
*
The server couldn't understand your request.\n"; // error message 404 static String ERROR_404 = "
Document not found.\n"; // a simple, short home page static String HOME_PAGE = "
Why not visit:
\n"; public EasyWebServer(Socket sock) { this.sock = sock; } public void run() { String inBuffer; try { /* 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 e) {} } public static void main(String[] args) throws IOException { if (args.length != 1) { System.out.println("usage java EasyWebServer port"); System.exit(-1); } int PORT = Integer.parseInt(args[0]); /* open a server socket at the given port */ ServerSocket server = new ServerSocket(PORT); /* the server is running forever (when not crashed :0) */ for (;;) { try { /* accept an incoming connection request */ Socket sock = server.accept(); new EasyWebServer(sock).start(); } 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 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 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 * */ 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 * */ 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 void processForm(BufferedReader sockIn,
DataOutputStream sockOut) {
try {
String inBuffer;
String returnString = "";
int returnStatus;
int returnLength;
int dataLength = Integer.parseInt
((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
";
//
// 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) {};
}
}