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

// Small, simple HTTP server
public class HTTPServer {
 String NAME;
 String VERSION;
 int serverPort;

 // No command line parameters are required
 public static void main(String args[]){
  HTTPServer server = new HTTPServer("HTTPServer", "1.0", 8000);
  server.run();
 }
 // Create an HTTPServer for a particular TCP port forward 
 public HTTPServer(String name, String version, int port) {
  this.NAME = name;
  this.VERSION = version;
  this.serverPort = port;
 }
 // Display name and version number
 public void displayVersionInfo(){
  System.out.println(NAME+" version "+VERSION);
 }
 // Run until interrupted
 public void run() {
  displayVersionInfo();
  try {
   // Get a server socket
   ServerSocket server = getServerSocket();
   int localPort = server.getLocalPort();
   // Let us know that you're listening
   System.out.println(NAME+" is listening on port "+localPort+".");
   do {
    // Accept a connection
    Socket client = server.accept();
    // Handle the connection with a separate thread
    (new HTTPServerThread(client)).start();
   } while(true);
  } catch(Exception ex) {
   System.out.println("Unable to listen on "+serverPort+".");
   ex.printStackTrace();
   System.exit(1);
  }
 }
 // Get a server socket on the hard-wired server port
 ServerSocket getServerSocket() throws Exception {
  return new ServerSocket(serverPort);
 }
}

// Handle a single server connection
class HTTPServerThread extends Thread {
 Socket client;
 // Keep track of the client socket
 public HTTPServerThread(Socket client) {
  this.client = client;
 }
 // Thread entry point
 public void run() {
  try {
   // Display info about the connection
   describeConnection(client);
   // Create a stream to send data to the client
   BufferedOutputStream outStream = new
BufferedOutputStream(client.getOutputStream());
   HTTPInputStream inStream = new HTTPInputStream(client.getInputStream());
   // Get the client's request
   HTTPRequest request = inStream.getRequest();
   // Display info about it
   request.log();
   // Sorry, we only handle gets
   if(request.isGetRequest())
    processGetRequest(request,outStream);
   System.out.println("Request completed. Closing connection.");
  }catch(IOException ex) {
   System.out.println("IOException occurred when processing request.");
  }
  try {
   client.close();
  }catch(IOException ex) {
   System.out.println("IOException occurred when closing socket.");
  }
 }
 // Display info about the connection
 void describeConnection(Socket client) {
  String destName = client.getInetAddress().getHostName();
  String destAddr = client.getInetAddress().getHostAddress();
  int destPort = client.getPort();
  System.out.println("Accepted connection to "+destName+" ("
   +destAddr+")"+" on port "+destPort+".");
 }
 // Process an HTTP GET
 void processGetRequest(HTTPRequest request,BufferedOutputStream outStream)
   throws IOException {
  /* If you want to use this in a secure environment then you should place some
 restrictions on the requested file name */
  String fileName = request.getFileName();
  File file = new File(fileName);
  // Give them the requested file
  if(file.exists()) sendFile(outStream,file);
  else System.out.println("File "+file.getCanonicalPath()+" does not exist.");
 }
 // A simple HTTP 1.0 response
 void sendFile(BufferedOutputStream out,File file) {
  try {
   DataInputStream in = new DataInputStream(new FileInputStream(file));
   int len = (int) file.length();
   byte buffer[] = new byte[len];
   in.readFully(buffer);
   in.close();
   out.write("HTTP/1.0 200 OK\r\n".getBytes());
   out.write(("Content-Length: " + buffer.length + "\r\n").getBytes());
   out.write("Content-Type: text/html\r\n\r\n".getBytes());
   out.write(buffer);
   out.flush();
   out.close();
   System.out.println("File sent: "+file.getCanonicalPath());
   System.out.println("Number of bytes: "+len);
  }catch(Exception ex){
   try {
    out.write(("HTTP/1.0 400 " + "No can do" + "\r\n").getBytes());
    out.write("Content-Type: text/html\r\n\r\n".getBytes());
   }catch(IOException ioe) {
   }
   System.out.println("Error retrieving "+file);
  }
 }
}

// Convenience class for reading client requests
class HTTPInputStream extends FilterInputStream {
 public HTTPInputStream(InputStream in) {
  super(in);
 }
 // Get a line
 public String readLine() throws IOException {
  StringBuffer result=new StringBuffer();
  boolean finished = false;
  boolean cr = false;
  do {
   int ch = -1;
   ch = read();
   if(ch==-1) return result.toString();
   result.append((char) ch);
   if(cr && ch==10){
    result.setLength(result.length()-2);
    return result.toString();
   }
   if(ch==13) cr = true;
   else cr=false;
  } while (!finished);
  return result.toString();
 }
 // Get the whole request
 public HTTPRequest getRequest() throws IOException {
  HTTPRequest request = new HTTPRequest();
  String line;
  do {
   line = readLine();
   if(line.length()>0) request.addLine(line);
   else break;
  }while(true);
  return request;
 }
}

// Used to process GET requests
class HTTPRequest {
 Vector lines = new Vector();

 public HTTPRequest() {
 }
 public void addLine(String line) {
  lines.addElement(line);
 }
 // Is this a GET or isn't it?
 boolean isGetRequest() {
  if(lines.size() > 0) {
   String firstLine = (String) lines.elementAt(0);
   if(firstLine.length() > 0)
    if(firstLine.substring(0,3).equalsIgnoreCase("GET"))
     return true;
  }
  return false;
 }
 // What do they want to get?
 String getFileName() {
  if(lines.size()>0) {
   String firstLine = (String) lines.elementAt(0);
   String fileName = firstLine.substring(firstLine.indexOf(" ")+1);
   int n = fileName.indexOf(" ");
   if(n!=-1) fileName = fileName.substring(0,n);
   try {
    if(fileName.charAt(0) == '/') fileName = fileName.substring(1);
   } catch(StringIndexOutOfBoundsException ex) {}
   if(fileName.equals("")) fileName = "index.htm";
   if(fileName.charAt(fileName.length()-1)=='/')
    fileName+="index.htm";
   return fileName;
  }else return "";
 }
 // Display some info so we know what's going on
 void log() {
  System.out.println("Received the following request:");
  for(int i=0;i<lines.size();++i)
   System.out.println((String) lines.elementAt(i));
 }
}

