
/**
 * class HttpProtocol.
 * 
 * Pfff....c'est quoi exactement un protocol
 * 
 * @author Laurent Dehoey I177416 
 * @version 23/01/2003
 */
public class HttpProtocol implements Protocol
{
   /**
    * Socket of a request.
    */
   protected java.net.Socket s = null;

   /**
    * Document root.
    */
   protected static java.io.File docRoot;

   /**
    * Canonical document root.
    */
   protected static String canonicalDocRoot;

   /**
    * The port the server will listen to
    */
   public final static int HTTP_PORT = 8080;

   /**
    * CRLF
    */
   public final static String CRLF = "\r\n";

   /**
    * Protocol out server understands.
    */
   public final static String PROTOCOL = "HTTP/1.0 ";

   /**
    * Status code: All OK.
    */
   public final static String SC_OK = "200 OK";

   /**
    * Status code: Bad request.
    */
   public final static String SC_BAD_REQUEST = "400 Bad Request";

   /**
    * Status code: Forbidden request.
    */
   public final static String SC_FORBIDDEN = "403 Forbidden";

   /**
    * Status code: Resource not found.
    */
   public final static String SC_NOT_FOUND = "404 Not Found";

   /**
    * Current status code.
    */
   protected String statusCode = SC_OK;

   /**
    * Current header.
    */
   protected java.util.Hashtable myHeaders = new java.util.Hashtable();

    /**
     * Da String Constructor
     */
    public HttpProtocol(String doc_root)
    {
      try
      {
    //    this.docRoot=doc_root;
         docRoot = new java.io.File(".");
         canonicalDocRoot = docRoot.getCanonicalPath();
         java.net.ServerSocket listen = new java.net.ServerSocket(HTTP_PORT);
    //     while(true)
    //     {
    //        SimpleHttpd2 aRequest = new SimpleHttpd2(listen.accept());
    //     }
      }
      catch(java.io.IOException e)
      {
         System.err.println("Error: " + e.toString());
      }
   
         setHeader("Server","SimpleHttpd2");
   
    }

    public void service(java.net.Socket s) throws java.lang.Exception
    {
        this.s=s;

      try
      {
//         setHeader("Server","SimpleHttpd2");
         java.io.BufferedReader is = new java.io.BufferedReader(new java.io.InputStreamReader(s.getInputStream()));
         java.io.DataOutputStream os = new java.io.DataOutputStream(s.getOutputStream());
         String request = is.readLine();
         System.out.println("Request: " + request);
         java.util.StringTokenizer st = new java.util.StringTokenizer(request);
         if((st.countTokens() == 3) && st.nextToken().equals("GET"))
         {
            String filename = docRoot.getPath() + st.nextToken();
            if(filename.endsWith("/") || filename.equals(""))
               filename += "index.html";
            java.io.File file = new java.io.File(filename);
            if(file.getCanonicalPath().startsWith(canonicalDocRoot))
               sendDocument(os,file);
            else
               sendError(SC_FORBIDDEN,os);
         }
         else
         {
            sendError(SC_BAD_REQUEST,os);
         }
         is.close();
         os.close();
         s.close();
      }
      catch(java.io.IOException ioe)
      {
         System.err.println("Error: " + ioe.toString());
      }
   




    }


   /**
    * Reads the file, specified in <code>request</code> and writes it to
    * the OutputStream.<br>
    * If the file could not be found, the error message 404,
    * <code>Not Found</code>, is returned.
    *
    * @exception IOException in case writing to the <code>DataOutputStream</code>
    *    fails.
    * @param os Stream, where the requested object is to be copied to.
    * @param file file to copy.
    */
   protected void sendDocument(java.io.DataOutputStream os, java.io.File file) throws java.io.IOException
   {
      try
      {
         java.io.BufferedInputStream in = new java.io.BufferedInputStream(new java.io.FileInputStream(file));
         sendStatusLine(os);
         setHeader("Content-Length",(new Long(file.length())).toString());
         setHeader("Content-Type",guessType(file.getPath()));
         sendHeader(os);
         os.writeBytes(CRLF);
         byte[] buf = new byte[1024];
         int len;
         while((len = in.read(buf,0,1024)) != -1)
         {
            os.write(buf,0,len);
         }
         in.close();
      }
      catch(java.io.FileNotFoundException fnfe)
      {
         sendError(SC_NOT_FOUND,os);
      }
   }

   /**
    * Sets a status code.
    *
    * @param statusCode status code
    */
   protected void setStatusCode(String statusCode)
   {
      this.statusCode = statusCode;
   }

   /**
    * Gets the status code.
    *
    * @return status code
    */
   protected String getStatusCode()
   {
      return statusCode;
   }

   /**
    * Writes the status line to the consigned <code>DataOutputStream</code>.
    *
    * @param out DataOutputStream where the line is to be written.
    * @exception IOException in case writing fails.
    */
   protected void sendStatusLine(java.io.DataOutputStream out) throws java.io.IOException
   {
      out.writeBytes(PROTOCOL + getStatusCode() + CRLF);
   }

   /**
    * Sets an header value.
    *
    * @param key key of the header value.
    * @param value the header value.
    */
   protected void setHeader(String key, String value)
   {
      myHeaders.put(key,value);
   }

   /**
    * Writes the header to the consigned <code>DataOutputStream</code>.
    *
    * @param out DataOutputStream where the header is to be written.
    * @exception IOException in case writing fails.
    */
   protected void sendHeader(java.io.DataOutputStream out) throws java.io.IOException
   {
      String line;
      String key;
      java.util.Enumeration e = myHeaders.keys();
      while(e.hasMoreElements())
      {
         key = (String)e.nextElement();
         out.writeBytes(key + ": " + myHeaders.get(key) + CRLF);
      }
   }

   /**
    * Writes an error message to the consigned <code>DataOutputStream</code>.
    *
    * @param out DataOutputStream where the error message is to be written.
    * @param statusCode status code.
    * @exception IOException in case writing fails.
    */
   protected void sendError(String statusCode, java.io.DataOutputStream out) throws java.io.IOException
   {
      setStatusCode(statusCode);
      sendStatusLine(out);
      out.writeBytes(CRLF + "<html>" + "<head><title>" + getStatusCode() + "</title></head>" + "<body><h1>" + getStatusCode() + "</h1></body>" + "</html>");
      System.err.println(getStatusCode());
   }

   /**
    * Surmise the <code>Content-Type</code> of the file by means
    * of the file extension.
    *
    * @param filename file name
    * @return Content-Type or "unknown/unknown" in case no
    *   appropriate type is found.
    *   
    *   **always unknown for the moment**
    */
   public String guessType(String filename)
   {
      String type = null;
      int i = filename.lastIndexOf(".");
//      if(i > 0)
//         type = typeMap.getProperty(filename.substring(i));
//     if(type == null)
         type = "unknown/unknown";
      return type;
   }


}
