Tuesday 19 February 2013

Multithreaded Web Server

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

//Start of class HttpRequest
final class HttpRequest implements Runnable
{
   final static String CRLF = "\r\n";
   public final static int SO_KEEPALIVE = 0x0008;
   //Set the default homepage to "index.html"
   private static final String DEFAULT_PAGE = "index.html";
 
   Socket socket;
   //Constructor
   public HttpRequest(Socket socket)throws Exception
   {
     this.socket = socket;
   }
 
   //Implement the run()method of the Runnable interface
   public void run()
       {
        try{
         processRequest();
 }
   catch (Exception e){
        System.out.println(e);
 }
   }
 
  //processRequest() method that processes individual HTTP requests

   private void processRequest() throws Exception
   {
 
String sentence;
//Get a reference to the socket's input and output streams
DataOutputStream os = new DataOutputStream (socket.getOutputStream());
//Set up input stream filters
BufferedReader bfReader = new BufferedReader (new   InputStreamReader(socket.getInputStream()));
sentence = bfReader.readLine() ;
//Get the request line of the HTTP request message.
String requestLine = sentence;

 //Display the request line in a structured way
 System.out.println();
 System.out.println("HTTP request message:");
 System.out.println("---------------------");
 System.out.println(requestLine);
 os.writeBytes("HTTP request message:"+CRLF);
 os.writeBytes("---------------------"+CRLF);
 os.writeBytes(requestLine+CRLF);

 //Get and display the header lines.
 String headerLine;
 while ((headerLine = bfReader.readLine()).length()!= 0){
    System.out.println(headerLine);
  }

    //Split the request line on white space
    String [] tokens=requestLine.split("\\s+" ,3);
    String fileName = tokens[1]; // second element is filename
    //Prepend a "." so that file request is within the current directory
    fileName = "."+fileName;
 //Filenames values is assigned with a file in the directory
 fileName = "homepage.html";

    FileInputStream fis = null;
 boolean fileExists=true;

          try{
              fis = new FileInputStream(fileName);
              }
             catch(FileNotFoundException e)
     {fileExists = false;}

try {

boolean append=true;
//Initialise  log string's value according to common log format
String log= InetAddress.getLocalHost()+" ["+(new Date()).toString()+"]" +" "+requestLine+" "+(new     Integer(fis.available())).toString() ;
//Write each web log generated to a text file
BufferedWriter out = new BufferedWriter(new FileWriter("webLogs.txt",append));
out.append(log);
//Writes each log line by line in the text file
out.newLine();
//closes the stream
out.close();
 
}
catch (IOException |NullPointerException e)
        {
            System.out.println("Log File Exception");    
        }

    //Construct the response message
    String statusLine = null;
    String contentTypeLine = null;
 String contentLengthLine =null;
    String entityBody="error";
 //New string hash for storing the MD5 hash's value
 String hash="";
 //Password is obtained from the URL's content
 String password =requestLine;
 //Username is obtained from the URL's content
 String user =requestLine;
 //URL is splitted in parts using the = symbol as delimiter
    String delimiter = "=";
    //Array of string to hold the split values of the URL
 String[] entry1;
 //Some parts of the URL are then thrown away
 user = user.replace("&pw","");
 entry1 = user.split(delimiter);
 // //Array of string to hold the split values of the URL
 String[] entry2;
 //Some parts of the URL are then thrown away
    password = password.replace("&action","");
    entry2 = password.split(delimiter);
       
 //If the filename is in the linked directory return the corresponding message
          if (fileExists){
              statusLine = "HTTP/1.0 200 OK";
              contentTypeLine = "Content-type:"  + contentType(fileName);
 //Return the size of the file in bytes
 contentLengthLine = "Content-length:" + (new Integer(fis.available())).toString();
          }
 //Else if the filename is not in the linked directory return the corresponding message
          else{
               statusLine = "HTTP/1.0 404 Not found";
               contentTypeLine="Content-type:text/html";
               entityBody ="<HTML>"+
                            "<HEAD><TITLE>404 Not Found</TITLE></HEAD>" +
                            "<BODY>404 Not Found"+"</BODY></HTML>" ;
  //Return the size of the file in bytes
  contentLengthLine="Content-length:" +(new Integer(entityBody.length()).toString());

       }
     //Try catch block for displaying authentication's output if carried out
       try{
 
  //Password string is assigned with the new extracted from the URL value
  password=entry2[2];
    hash=MD5(password);
//Display the username,password and MD5 hash code to the system
System.out.println("----------------------");
 System.out.println("Username:"+entry1[1]);
System.out.println("Password:"+entry2[2]);
System.out.println("MD5 hashcode:"+hash);
//If the URL's size is smaller than 48 bytes and credentials were not entered,
//an error that authentication was not carried out is displayed in the HTTP request.
if(requestLine.length()<48){
statusLine = "HTTP/1.0 403 Forbidden";
                    contentTypeLine="Content-type:text/html";
                    entityBody ="<HTML>" +
                            "<HEAD><TITLE>403 Forbidden</TITLE></HEAD>" +
                            "<BODY>NOT AUTHENTICATED" +                                            
                            "</BODY></HTML>" ;
       contentLengthLine="Content-length:" +(new Integer(entityBody.length()).toString());}

      }
 catch(ArrayIndexOutOfBoundsException|NullPointerException e)
            {hash="";}

//Send the Status line to server
    os.writeBytes(statusLine+CRLF);
os.writeBytes(contentTypeLine+CRLF);
  //Send the content length line
  os.writeBytes(contentLengthLine+CRLF);
 //Print a timestamp of the request
 os.writeBytes("Request Date:" + (new Date()).toString() + "\n");
    //Send a blank line to indicate the end of the header lines.
    os.writeBytes(CRLF);

        //Print the lines in the system output as well
      System.out.println("--------------------");
      System.out.println(statusLine);
      System.out.println(contentTypeLine);
      System.out.println(contentLengthLine);
      //Print a timestamp of the request
      System.out.println("Last Modified:" + (new Date()).toString());
      System.out.println("--------------------");
         //Flush the output
      System.out.flush();

          //Send the entity body
          if (fileExists){
              sendBytes(fis,os);
              fis.close();
          }
          else{
              os.writeBytes(entityBody);
       }

 //Close streams and sockets
 os.close();
 bfReader.close();
 socket.close();
 }
 
//Method to calculate an MD5 checksum of the entered password String in the HTML form
private static String MD5(String password) {
    try {
        //Create an object from java's security library
        java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
        byte[] array = md.digest(password.getBytes());
        StringBuilder sb = new StringBuilder();
//For loop for calculating each digit of the hash string
        for (int i = 0; i < array.length; ++i) {
          sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1,3));
       }
  //returns the hash string
        return sb.toString();

    } catch (java.security.NoSuchAlgorithmException e) {}
    return null;
}

   //ContentType() method that returns a String included in the content type line
   private static String contentType(String fileName)
   {  
   //if filename is of type html return the corresponding string
//and so on..
        if(fileName.endsWith(".htm")|| fileName.endsWith(".html"))
          { return "text/html";}
if(fileName.endsWith(".txt")|| fileName.endsWith(".text"))
          { return "text/plain";}
        if(fileName.endsWith(".gif")|| fileName.endsWith(".ico"))
          { return "image/gif";}
if(fileName.endsWith(".xml"))
          { return "text/xml";}
if(fileName.endsWith(".png"))
          { return "image/png";}
        if(fileName.endsWith(".jpeg")|| fileName.endsWith(".jpg"))
          { return "image/jpeg";}
       
//otherwise return this string
   return "application/octet-stream";
    }
     //Method sendBytes
     private static void sendBytes(FileInputStream fis, OutputStream os)
     throws Exception
     {
       //Construct a 1K buffer to hold bytes on their way to the socket.
       byte[] buffer = new byte[1024];
       int bytes = 0;
     
       //Copy requested file into the socket's output stream.
       while((bytes = fis.read(buffer))!= -1){
           os.write(buffer, 0, bytes);
       }
  //close the file input stream
  fis.close();
    }

 //End of class HttpRequest
 }

_________________________________________________________________________________

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

public final class WebServer
{
    public static void main(String argv[]) throws Exception
    {
         //set the port number
         int port = 4040;
 
    //Establish the listen socket
   ServerSocket welcomeSocket = new ServerSocket (4040) ;
//Prints a message to inform the user that the server is running and on which port
System.out.println("Web server is running on port " + port + "... (press CTRL-C to quit)");
//Prints a message about the date of the session's starting point
System.out.println("Session started on:" + (new Date()).toString());
System.out.println();
   //Process HTTP service requests in an infinite loop.
   while (true){
   //Listen for a TCP connection request
   Socket connectionSocket = welcomeSocket.accept() ;
   System.out.println();
//Prints out some information about the new connection
System.out.println("NEW CONNECTION ESTABLISHED:" +
   InetAddress.getLocalHost() + ":" + connectionSocket.getPort());
System.out.println("------------------------------------------------------------");
 
     try
       {
  //Set keep alive to true
connectionSocket.setKeepAlive(true);
//Set timeout to 5 minutes
  connectionSocket.setSoTimeout(300000);
//Prints some information about the new connection
System.out.format("Send Buffer Size:          %s\n",   connectionSocket.getSendBufferSize());
   System.out.format("Keep-Alive:                %s\n",   connectionSocket.getKeepAlive());
System.out.format("Socket Timeout:            %s\n",   connectionSocket.getSoTimeout()/60000+" minutes");
    System.out.println();
}
catch (Exception e)
          {e.printStackTrace();}
 
           try{
             //Construct an object to process the HTTP request message
             HttpRequest request = new HttpRequest(connectionSocket);
             //Create a new thread to process the request
             Thread thread = new Thread(request);
 
             //Start the thread.
             thread.start();
  }
  catch(Exception e) 
            { e.printStackTrace();
          }
        }
     }
//End of class WebServer   
}

Nikolas Georgiou