// HTTPHeader.java

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

/** A class to handle a HTTPHeader.
 */
public class HTTPHeader extends GeneralHeader
{    
    /** @serial */
    private String line;                      // the request- or statusline
    /** @serial */
    private String method = "";
    /** @serial */
    private String requestURI = "";
    /** @serial */
    private String httpVersion = null;
    /** @serial */
    private String content = null;              // the content of the request/response (mostly not set for responses).
    
    /** Create a new HTTPHeader from scratch
     */
    public HTTPHeader () {    
    }
    
    /** Read in a HTTPHeader from an inputstream.
     * @param in the stream from which this header is read.
     * @throws IOException if reading from in results in exceptions.
     */
    public HTTPHeader (InputStream in) throws IOException {
	//System.out.println("Creating a new Header");
	readHTTPHeader (in);
    }

    public void readHTTPHeader (InputStream input) throws IOException {

	BufferedReader in = new BufferedReader ( new InputStreamReader (input, "latin1"));            
	do {
	    line = in.readLine ();
	    if (line == null)
		throw (new IOException ("Couldnt read requestline, connection must be closed"));
	} while (line.length () == 0);   // empty string
	setRequestLine (line);
	
	if (isDot9Request ())
	    return;
	String msg;
	
	// ok, allow for some evil webservers (Domino) that allow this...
	msg = in.readLine ();
	while (msg != null && 
	       msg.length () > 0 && 
	       (msg.charAt (0) == ' ' || 
		msg.charAt (0) == '\t')) {
	    setReasonPhrase (getReasonPhrase () + msg);
	    msg = in.readLine ();
	}
	super.readHeader (in, msg);
    }

     public HTTPHeader ifModifiedHeader (HTTPHeader pxyHeader, HTTPHeader webHeader) {
	
	HTTPHeader requestHeader = new HTTPHeader ();
	
	String es = webHeader.getHeader("ETag");
	String ms = webHeader.getHeader("Last-Modified");

	if (es != null) {
	    requestHeader.setMethod(pxyHeader.getMethod());
	    requestHeader.setRequestURI(pxyHeader.getRequestURI());
	    requestHeader.setHTTPVersion(pxyHeader.getHTTPVersion());
	    requestHeader.setHeader("If-None-Match", es);
	    return requestHeader;
	}
	return pxyHeader;
    }

   /** get the text value of this header 
     * @return a String describing this HTTP-Header.
     */
    public String toString () {
	StringBuffer ret = new StringBuffer (getRequestLine ());
	ret.append (CRLF);
	ret.append (super.toString ());
	if (content != null)
	    ret.append (content);
	    
	return ret.toString ();
    }
    
    /** Get the statusline of this header (only valid for responses). 
     * @return the status of the request.
     */
    public String getStatusLine () {
	return getRequestLine ();
    }
    
    /** Set the statusline of this header.
     * @param line a Status-Line )RFC 2068: 6.1)
     */
    public void setStatusLine (String line) {
	setRequestLine (line);
    }

    /** Get the requestline of this header (only valid for requests).
     * @return the request. 
     */
    public String getRequestLine () {
	return method + ' ' + requestURI + (httpVersion != null ? ' ' + httpVersion : "");
    }

    /** Set the requestline of this header
     * @param line a Request-Line (RFC 2068: 5.1)
     */
    public void setRequestLine (String line) {
	this.line = line;
	int s1 = line.indexOf (' ');
	if (s1 < 0) {
	    method = line;
	    return;
	}
	int s2 = line.indexOf (' ', s1+1);
	method = line.substring(0,s1);
	if (s2 > 0) {
	    requestURI = line.substring (s1+1,s2);
	    httpVersion = line.substring (s2+1);
	} else {
	    requestURI = line.substring (s1+1);
	    httpVersion = null;
	}
    }

    /** Is this request for the head only?
     * @return true if this request is for HEAD, false otherwise
     */
    public boolean isHeadOnlyRequest () {
	return method.equals ("HEAD");     // method is casesensitive.
    }
    
    /** Get the request method of this header (only valid for requests).
     * @return the request method.
     */
    public String getMethod (){
	return method;
    }
    
    /** Sets the request method of this header 
     * @param method the new requestmethod
     */
    public void setMethod (String method) {
	this.method = method;
    }

    /** Get the requestURI of this request (only valid for requests).
     * @return the requestURI.
     */
    public String getRequestURI () {
 	return requestURI;
    }
    
    /** Sets the request URI of this header 
     * @param method the new URI
     */
    public void setRequestURI (String requestURI) {
	this.requestURI = requestURI;
    }
    
    /** Get the HTTP Version of this request (only valid for requests).
     * @return the http version.
     */
    public String getHTTPVersion () {
	return httpVersion;
    }

    /** Set the HTTP Version to use for request.
     * @param version the version to use.
     */
    public void setHTTPVersion (String version) {
	httpVersion = version;
    }
    
    /** Get the HTTP version of the response (only valid for responses).
     * @return the HTTP version.
     */
    public String getResponseHTTPVersion () {
	return method;
    }
    
    /** Set the HTTP version for this response.
     * @param httpVersion the version to use.
     */
    public void setResponseHTTPVersion (String httpVersion) {
	method = httpVersion;
    }

    /** Get the Status code of the response (only valid for responses).
     * @return the status code.
     */
    public String getStatusCode () {
	return requestURI;
    }
    
    /** Set the Status code for this response.
     * @param status the new status code.
     */
    public void setStatusCode (String status) {
	requestURI = status;
    }

    /** Get the Reason phrase of the response (only valid for responses).
     * @return the reason phrase.
     */
    public String getReasonPhrase () {
	return httpVersion;
    }
    
    /** Set the reason phrase for this reqponse.
     * @param reason the new reasonphrase
     */
    public void setReasonPhrase (String reason) {
	httpVersion = reason;
    }

    /** Set the Content for the request/response
     *  Mostly not used for responses.
     *  As a side effect the &quot;Content-Length&quot; header is also set.
     * @param content the binary content.
     */
    public void setContent (String content) {
	this.content = content;
	setHeader ("Content-Length", "" + content.length ());
    }    

    /** Get the content of the request/response.
     */
    public String getContent () {
	return content;
    }

    /** Is this request a HTTP/0.9 type request?
     *  A 0.9 request doesnt have a full HTTPheader, only a requestline 
     *  so we need to treat it differently.
     */
    public boolean isDot9Request () {
	return httpVersion == null;
    }    
    
    /** Get the hashCode for this header.
     * @return the hash code for this object.
     */
    public int hashCode() {
	return getRequestURI ().hashCode ();
    }
    
    /** Is this Header equal to the other object?
     *  Two HTTPHeaders are assumed equal if the requesURI's are equal.
     * @param o the Object to compare to.
     * @return true if o and this object are equal, false otherwise.
     */
    public boolean equals (Object o) {
	if (o instanceof HTTPHeader) 
	    return getRequestURI ().equals (((HTTPHeader)o).getRequestURI ());
	return false;
    }

    /** Try to guess if this header is a request.
     * @return true if this (probably) is a request, false otherwise.
     */
    public boolean isRequest () {
	return !isResponse ();
    }

    /** Try to guess if this header is a response. 
     * @return true if this (probably) is a response, false otherwise.
     */
    public boolean isResponse () {
	return (getResponseHTTPVersion () != null &&
		getResponseHTTPVersion ().toLowerCase ().startsWith ("http/"));
    }

    /** Try to guess if this header is a secure thing.
     * @return true if this (probably) is a secure connection.
     */
    public boolean isSecure () {
	return (getMethod () != null &&
		getMethod ().equals ("CONNECT"));
    }
    
}

