Chris Pollett >
Old Classes
> |
HW5 Solutions PageThis solution was heavily modified from student DK's solution. Good work DK! <!-- test.html --> <html> <head> <title>test.html</title> </head> <body> <p>test</p> </body> </html> #!/usr/bin/perl # # test.cgi # # This cgi-script can be used to output the CGI environment # variables and also act as a counter of number of times it # has been accessed # $countFile = "counter.txt"; # file counter stored in print <<HTML_BLOCK; Content-type:text/html <html> <head> <title>Environment + Counter</title> </head> <body> <p><h3>Environment + Counter</h3></p> <table border="2"> HTML_BLOCK foreach (sort keys %ENV) { print " <tr><td> $_ </td><td> $ENV{$_}</td></tr> \n"; } print " </table> \n"; if(-e $countFile) { open(FILE, $countFile) || die "Could not open count file\n"; $count = <FILE>; close(FILE); $count++; } else { $count = 1; } open(FILE, ">$countFile") || die "Could not write to count file"; print FILE "$count\n"; close(FILE); print " <p>You are visitor number: $count</p>"; print <<HTML_BLOCK; <body> </html> HTML_BLOCK /* MyServerProperties.txt */ port= 5000 host=localhost public_html = /home/cpollett/Hw5/ cgi_bin = /home/cpollett/Hw5/ // MyWebServer.java -- a simplified web server that can do CGI import java.io.*; import java.util.*; import java.net.*; /** MyWebServer Java web server that serves text htmls and cgi pages It uses MyServerProperties.txt to read in a property data. The MyServerProperties file should be formatted in the following way: for windows: port=80 perl=w:/perl/bin/perl name=computer name publicHtml = w:/public_html/ cgi_bin = w:/cgi-bin/ for UNIX: port=80 perl= /usr/bin/perl name=computer name publicHtml = /usr/wwwroot/ cgi_bin = /usr/wwwroot/cgi-bin/ @author DK (student) -- heavily modified by C. Pollett @version 1.0 */ public class MyWebServer { /** @return the port number */ public static int getPort() { return port; } /** @return the public_html directory */ public static String publicHtml() { return publicHtml; } /** @return the cgi_bin directory */ public static String getCgiBin() { return cgi; } /** Creates a socket and then listens for users */ public static void startWebServer() { try { //calls for the function to read in property file readConfig("MyServerProperties.txt"); ServerSocket accept = new ServerSocket(port); System.out.println("Server ready to accept connections."); while(true) { Socket s = accept.accept(); //if someone there create a new thread ConnectionHandler handler = new ConnectionHandler(s); handler.start(); } } catch (Exception e) { System.out.println(e.toString()); System.exit(0); } } /** Reads in the Property file @param fileName -- the property file's name */ public static void readConfig(String fileName) { System.out.println( "Attempting to read MyServerProperties.txt..."); Properties properties = new Properties(); try { FileInputStream file = new FileInputStream(fileName); properties.load(file); file.close(); } catch (IOException ie) { System.err.println("Error reading"+ "MyServerProperties.txt configuration file "); System.err.println(ie.toString()); System.exit(0); } port = Integer.parseInt(properties.getProperty("port")); publicHtml = properties.getProperty("public_html"); cgi = properties.getProperty("cgi_bin"); host= properties.getProperty("host"); System.out.println("MyServerProperties.txt file read."); } public static void main(String[] args) { startWebServer(); } public static String publicHtml ; //path to public_html public static String perl; //path to perl directory public static String cgi; //path to cgi-bin public static int port; //port number public static String host; //path to cgi-bin } /** ConnectionHandler class used to handle an individual request by a Thread */ class ConnectionHandler extends Thread { /** Constructor -- sets the socket involved in this request @param s -- the socket */ public ConnectionHandler(Socket s) { socket = s; } /** method that is executed by a thread to handle a single HTTP request */ public void run() { try { String tmp; //input stream to get users requests BufferedReader socketInput = new BufferedReader( new InputStreamReader(socket.getInputStream())); //output stream to respond to users requests DataOutputStream socketOutput = new DataOutputStream(socket.getOutputStream()); //user Request String userRequest = socketInput.readLine().toString(); System.out.println("\nRequest:\n"+userRequest); tmp = socketInput.readLine().toString(); System.out.println(tmp); String accept = tmp.substring(8); boolean flag=true; while(flag) { tmp=socketInput.readLine(); System.out.println(tmp); if(tmp.equalsIgnoreCase("")) flag=false; } StringTokenizer token = new StringTokenizer(userRequest); String getRequest = token.nextToken(); //FILENAME String fileName = token.nextToken(); //HTTP protocol http = token.nextToken(); //checks if the user input correct path if(!fileName.startsWith("/public_html") && !fileName.startsWith("/cgi-bin")) { printMessage("403", Err403, socketOutput); } // we only handle GET requests else if(getRequest.equals("GET")) { if(fileName.startsWith("/public_html")) sendHtml(http, fileName, socketOutput); else executeCgi (fileName, socketOutput, accept); } else printMessage("405", Err405, socketOutput); //all done socket closed socket.close(); } catch(Exception e) { System.err.println(e.toString()); } } /** Sends page user requested @param http -- http protocol user uses @param fileName -- filename user wanted @param socketOutput -- DataOutputStream from socket @throws Exception - exception */ public void sendHtml(String http, String fileName, DataOutputStream socketOutput) throws Exception { String httpOutput=""; String tmp; //if the file is html and exists display it, otherwise error if(fileName.endsWith(".html")) { BufferedReader in = new BufferedReader( new FileReader(MyWebServer.publicHtml() + fileName.substring(12))); /* read the file line by line into a string then send the string */ while( (tmp = in.readLine())!= null) httpOutput+=tmp; printMessage("OK 200", httpOutput, socketOutput); } else { printMessage("415", Err415, socketOutput); } } /** executes a cgi script and displays the results @param fileName file name @param accept MIME serve accepts* @param socketOutput DataOutputStream @throws Exception exception */ public void executeCgi(String fileName, DataOutputStream socketOutput, String accept) { String tmp, cgiOutput=""; Runtime runTime = Runtime.getRuntime(); String[] env = getEnvironment(fileName, accept); try { String cmd = MyWebServer.getCgiBin() + fileName.substring(9); Process p = runTime.exec(cmd, env); String processError=""; //process input stream BufferedReader stdInput = new BufferedReader(new InputStreamReader( p.getInputStream())); //process error stream BufferedReader stdError = new BufferedReader( new InputStreamReader(p.getErrorStream())); //gets all the input stream, ie result of execution while ((tmp = stdInput.readLine()) != null) cgiOutput+=tmp+"\n"; //gets all if any errors in the execution while ((tmp = stdError.readLine()) != null) processError+=tmp; if(processError.equalsIgnoreCase("")) printMessage("200 OK", cgiOutput, socketOutput, false); else printMessage("500", processError, socketOutput); } //catch for the top try catch (Exception e) { System.out.println(e.toString()); } } /** Prints HTTP responses, outputs Content-type as text/html @param code response code @param msg response string @param socketOutput output @throws Exception exception */ public void printMessage(String code, String msg, DataOutputStream socketOutput) throws Exception { printMessage(code, msg, socketOutput, true); } /** Prints HTTP responses @param code response code @param msg response string @param socketOutput output @param outputType says whether we output the Content-type as text/html or not @throws Exception exception */ public void printMessage(String code, String msg, DataOutputStream socketOutput, boolean outputType) throws Exception { socketOutput.writeBytes(http+" "+ code+"\n"); System.out.println("\nResponse:\n"+http +" "+ code + "\n"); socketOutput.writeBytes( "Server: My Server\n MIME - version: 1.0\n"); System.out.println("Server: My Server\n MIME - version: 1.0\n"); if(outputType) { socketOutput.writeBytes("Content-Type: text/html\n"); System.out.println("Content-Type: text/html\n"); socketOutput.writeBytes( "Content-length:"+ msg.length() + "\n\n"); System.out.println( "Content-length:"+ msg.length() + "\n\n"); } socketOutput.writeBytes(msg); System.out.println(msg); socketOutput.flush(); } /** creates an array of cgi environment variables @param fileName - user requested filename @param accept -- connection type @return array on cgi environmental variables */ public String[] getEnvironment(String fileName, String accept) { ArrayList env = new ArrayList(); String[] type = new String[1]; String rname = socket.getInetAddress().toString(); String hname = socket.getLocalAddress().toString(); int slash1 = rname.indexOf("/"); int slash2 = hname.indexOf("/"); int qmark = fileName.indexOf("?"); if (qmark < 0 ) qmark = fileName.length(); env.add("SERVER_SOFTWARE=Java Web server"); env.add("SERVER_NAME=" + hname.substring(0, slash2)); env.add("SERVER_PROTOCOL=" + http); env.add("SERVER_PORT=" + MyWebServer.getPort()); env.add("REQUEST_METHOD=GET"); //request method is always get in this assignment env.add("SCRIPT_NAME=" + fileName.substring(0, qmark)); if(qmark < fileName.length()) env.add("QUERY_STRING=" + fileName.substring(qmark+1)); else env.add("QUERY_STRING="); env.add("REMOTE_HOST=" + rname.substring(0, slash1)); //host contains value from Host header env.add("REMOTE_ADDR=" + rname.substring(slash1+1)); env.add("HTTP_CONNECTION=" + accept.substring(3)); return ( (String[]) env.toArray(type)); } private Socket socket; //http protocol user requested, HTTP/1.0 or something else private String http = ""; //HTTP error messages String Err403 = "<h2>ERROR 403 Forbidden </h2>"; String Err404 = "<h2>ERROR 404 Page not found</h2>"; String Err405 = "<h2>ERROR 405 Method not allowed </h2>"; String Err410 = "<h2>ERROR 410 Page Permanently not available</h2>"; String Err415 = "<h2>ERROR 415 Unsupported media type</h2>"; } |