Logo Search packages:      
Sourcecode: paros version File versions  Download package

HttpHeader.java

/*
 * Created on Jun 14, 2004
 *
 * Paros and its related class files.
 * 
 * Paros is an HTTP/HTTPS proxy for assessing web application security.
 * Copyright (C) 2003-2004 Chinotec Technologies Company
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the Clarified Artistic License
 * as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * Clarified Artistic License for more details.
 * 
 * You should have received a copy of the Clarified Artistic License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.parosproxy.paros.network;

import java.util.Hashtable;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;


abstract public class HttpHeader implements java.io.Serializable{


      public static final String CRLF                 = "\r\n";
      public static final String LF                         = "\n";
      public static final String CONTENT_LENGTH       = "Content-length";
      public static final String TRANSFER_ENCODING = "Transfer-encoding";
      public static final String CONTENT_ENCODING = "Content-encoding";
      public static final String CONTENT_TYPE   = "Content-Type";
      public static final String PROXY_CONNECTION = "Proxy-Connection";
      public static final String PROXY_AUTHENTICATE = "Proxy-authenticate";
      public static final String CONNECTION           = "Connection";
      public static final String AUTHORIZATION  = "Authorization";
      public static final String WWW_AUTHENTICATE = "WWW-Authenticate";
      public static final String LOCATION                   = "Location";
      public static final String IF_MODIFIED_SINCE    = "If-Modified-Since";
      public static final String IF_NONE_MATCH        = "If-None-Match";
      public static final String USER_AGENT           = "User-Agent";
      public static final String ACCEPT_ENCODING = "Accept-Encoding";
      public static final String CACHE_CONTROL  = "Cache-control";
      public static final String PRAGMA               = "Pragma";
      public static final String REFERER              = "Referer";
      
      public static final String HTTP09   = "HTTP/0.9";
      public static final String HTTP10   = "HTTP/1.0";
      public static final String HTTP11   = "HTTP/1.1";
      public static final String _CLOSE               = "Close";
      public static final String _KEEP_ALIVE          = "Keep-alive";
      public static final String _CHUNKED             = "Chunked";
      
      public static final String SCHEME_HTTP          = "http://";
      public static final String SCHEME_HTTPS         = "https://";
      public static final String HTTP                       = "http";
      public static final String HTTPS                = "https";

      public static final Pattern patternCRLF               = Pattern.compile("\\r\\n", Pattern.MULTILINE);
      public static final Pattern patternLF                       = Pattern.compile("\\n", Pattern.MULTILINE);
      
      private static final Pattern patternCharset = Pattern.compile("charset *= *([^;\\s]+)", Pattern.CASE_INSENSITIVE);

      protected static final String p_TEXT            = "[^\\x00-\\x1f\\r\\n]*"; 
      protected static final String p_METHOD          = "(\\w+)";
      protected static final String p_SP              = " +";
      // protected static final String p_URI                = "(\\S+)";
      // allow space in URI for encoding to %20
      protected static final String p_URI             = "([^\\r\\n]+)";
      protected static final String p_VERSION         = "(HTTP/\\d+\\.\\d+)";
      protected static final String p_STATUS_CODE     = "(\\d{3})";
      protected static final String p_REASON_PHRASE = "(" + p_TEXT + ")";
      
      protected String mStartLine = "";
      protected String mMsgHeader = "";
      protected boolean mMalformedHeader = false;
      protected Hashtable mHeaderFields = new Hashtable();
      protected int mContentLength = -1;
      protected String mLineDelimiter = CRLF;
      protected String mVersion = "";
      
      public HttpHeader() {
            init();
      }


      /**
       * Construct a HttpHeader from a given String.
       * @param data
       * @throws HttpMalformedHeaderException
       */
      public HttpHeader(String data) throws HttpMalformedHeaderException {
            this();
            setMessage(data);
      }

      /**
       * Inititialization.
       */
      private void init() {
            mHeaderFields = new Hashtable();
            mStartLine = "";
            mMsgHeader = "";
            mMalformedHeader = false;
            mContentLength = -1;
            mLineDelimiter = CRLF;
            mVersion = "";
      }

      /**
       * Set and parse this HTTP header with the string given.
       * 
       * @param data
       * @throws HttpMalformedHeaderException
       */
      public void setMessage(String data) throws HttpMalformedHeaderException {
            init(); 

            mMsgHeader = data;
            try {
                  if (!this.parse(data)) {
                        mMalformedHeader = true;
                  }
            } catch (Exception e) {
                  mMalformedHeader = true;
            }

            if (mMalformedHeader) {
                  throw new HttpMalformedHeaderException();
            }

      }
      
      public void clear() {
          init();
      }

      /**
       * Get the first header value using the name given.  If there are multiple occurence,
       * only the first one will be returned as String.
       * @param name
       * @return the header value.  null if not found.
       */
      public String getHeader(String name) {
            Vector v = getHeaders(name);
            if (v == null) {
                  return null;
            }
            
            return (String) (v.firstElement());
      }
    
      /**
       * Get headers with the name.  Multiple value can be returned.
       * @param name
       * @return a vector holding the value as string.
       */
    public Vector getHeaders(String name) {
      Vector v = (Vector) mHeaderFields.get(name.toUpperCase());
      return v;
    }

    /**
     * Add a header with the name and value given.  It will be appended to the header string.
     * @param name
     * @param val
     */
      public void addHeader(String name, String val) {
            mMsgHeader = mMsgHeader + name + ": " + val + mLineDelimiter;
            addInternalHeaderFields(name, val);
      }

      /**
       * Set a header name and value.
       * If the name is not found, it will be added.
       * If the value is null, the header will be removed.
       * @param name
       * @param value
       */
    public void setHeader(String name, String value) {
//          int pos = 0;
//          int crlfpos = 0;
            Pattern pattern = null;

            if (getHeaders(name) == null && value != null) {
                  // header value not found, append to end
                  addHeader(name, value);
            } else {
                  try {
                        pattern = getHeaderRegex(name);
                        Matcher matcher = pattern.matcher(mMsgHeader);
                        if (value == null) {
                              // delete header
                              mMsgHeader = matcher.replaceAll("");
                        } else {
                              // replace header
                              String newString = name + ": " + value + mLineDelimiter;
                              mMsgHeader = matcher.replaceAll(newString);
                        }

                        // set into hashtable
                        replaceInternalHeaderFields(name, value);
                        
                  }
                  catch (Exception e) {
                  }
                  
            }
    }
    
    private Pattern getHeaderRegex(String name) throws PatternSyntaxException
      {
            return Pattern.compile("^ *"+ name + " *: *[^\\r\\n]*" + mLineDelimiter, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
      }

    /**
     * Return the HTTP version (eg HTTP/1.0, HTTP/1.1)
     * @return
     */
      public String getVersion() {
            return mVersion;
      }

      /**
       * Set the HTTP version of this header.
       * @param version
       */
      abstract public void setVersion(String version);

      /**
       * Get the content length of this header.
       *  
       * @return content length.  -1 means content length not set.
       */
      public int getContentLength() {
        return mContentLength;
    }

      /**
       * Set the content length of this header.
       * @param len
       */
      public void setContentLength(int len) {
            if (mContentLength != len) {
                  setHeader(CONTENT_LENGTH, Integer.toString(len));
                  mContentLength = len;
            }
      }

      /**
       * Check if this header expect connection to be closed.  HTTP/1.0 default to close.  HTTP/1.1 default to keep-alive.
       * @return
       */
      public boolean isConnectionClose() {
            boolean result = true;
            if (mMalformedHeader) {
                  return true;
            }

            if (isHttp10()) {
                  // HTTP 1.0 default to close unless keep alive.
                  result = true;
                  try {
                        if (getHeader(CONNECTION).equalsIgnoreCase(_KEEP_ALIVE) || getHeader(PROXY_CONNECTION).equalsIgnoreCase(_KEEP_ALIVE)) {
                              return false;
                        }
                  } catch (NullPointerException e) {
                  }

            } else if (isHttp11()) {
                  // HTTP 1.1 default to keep alive unless close.
                  result = false;
                  try {
                        if (getHeader(CONNECTION).equalsIgnoreCase(_CLOSE)) {
                              return true;
                        } else if  (getHeader(PROXY_CONNECTION).equalsIgnoreCase(_CLOSE)) {
                              return true;
                        }
                  } catch (NullPointerException e) {
                  }
            }
            return result;
      }

      /**
       * Check if this header is HTTP 1.0.
       * @return true if HTTP 1.0.
       */
      public boolean isHttp10() {
            if (mVersion.equalsIgnoreCase(HTTP10)) {
                  return true;
            }
            return false;
      }

      /**
       * Check if this header is HTTP 1.1.
       * @return true if HTTP 1.0.
       */
      public boolean isHttp11() {
            if (mVersion.equalsIgnoreCase(HTTP11)) {
                  return true;
            }
            return false;
      }

      /**
       * Check if Transfer Encoding Chunked is set in this header.
       * @return true if transfer encoding chunked is set.
       */
    public boolean isTransferEncodingChunked() {
      String transferEncoding = getHeader(TRANSFER_ENCODING);
      if (transferEncoding != null && transferEncoding.equalsIgnoreCase(_CHUNKED)) {
            return true;
      }
      return false;
    }

    /**
     * Parse this Http header using the String given.
     * @param data String to be parsed to form this header.
     * @return
     * @throws Exception
     */
    protected boolean parse(String data) throws Exception {

        String    token = null,
                        name = null,
                        value = null;
        int pos = 0;
        Pattern pattern = null;

        if(data == null || data.equals("")) {
            return true;
        }

        if ((pos = data.indexOf(CRLF)) < 0) {
            if ((pos = data.indexOf(LF)) < 0) {
                  return false;
            } else {
                  mLineDelimiter = LF;
                  pattern = patternLF;
            }
        } else {
            mLineDelimiter = CRLF;
            pattern = patternCRLF;
        }
        
            String[] split = pattern.split(data);
            mStartLine = split[0];

            StringBuffer sb = new StringBuffer(2048);
            for (int i=1; i<split.length; i++)
            {
                  token = split[i];
                  if (token.equals("")) {
                        continue;
                  }
                  
            if((pos = token.indexOf(":")) < 0) {
                        mMalformedHeader = true;
                return false;
            }
            name  = token.substring(0, pos).trim();
            value = token.substring(pos +1).trim();

            if(name.equalsIgnoreCase(CONTENT_LENGTH)) {
                  try {
                  mContentLength = Integer.parseInt(value);
                  } catch (NumberFormatException nfe){}
            }
                  
            /*
            if (name.equalsIgnoreCase(PROXY_CONNECTION)) {
                  sb.append(name + ": " + _CLOSE + mLineDelimiter);
            } else if (name.equalsIgnoreCase(CONNECTION)) {
                  sb.append(name + ": " + _CLOSE + mLineDelimiter);
            } else {
            */
                  sb.append(name + ": " + value + mLineDelimiter);
                  //}
                  
                  addInternalHeaderFields(name, value);
            }

        mMsgHeader = sb.toString();
            return true;
      }

    /**
     * Replace the header stored in internal hashtable
     * @param name
     * @param value
     */
      private void replaceInternalHeaderFields(String name, String value) {
            String key = name.toUpperCase();
            Vector v = getHeaders(key);
            if (v == null) {
                  v = new Vector();
                  mHeaderFields.put(key, v);
            }

            if (value != null) {
                v.clear();
                  v.add(value);
            } else {
                  mHeaderFields.remove(key);
            }
      }

      /**
       * Add the header stored in internal hashtable
       * @param name
       * @param value
       */
      private void addInternalHeaderFields(String name, String value) {
            String key = name.toUpperCase();
            Vector v = getHeaders(key);
            if (v == null) {
                  v = new Vector();
                  mHeaderFields.put(key, v);
            }

            if (value != null) {
                  v.add(value);
            } else {
                  mHeaderFields.remove(key);
            }
      }

      
      /**
       * Get if this is a malformed header.
       * @return
       */
    public boolean isMalformedHeader() {
        return mMalformedHeader;
    }
    
    /**
     * Get a string representation of this header.
     */
    public String toString() {
            return getPrimeHeader() + mLineDelimiter + mMsgHeader + mLineDelimiter;
    }

    /**
     * Get the prime header.
     * @return startline for request, statusline for response.
     */
    abstract public String getPrimeHeader();

    /**
     * Get if this is a image header.
     * @return true if image.
     */
    public boolean isImage() {
      return false;
    }

    /**
     * Get if this is a text header.
     * @return true if text.
     */
    public boolean isText() {
      return true;
    }

    /**
     * Get the line delimiter of this header.
     * @return
     */
    public String getLineDelimiter() {
      return mLineDelimiter;
    }

    /**
     * Get the headers as string.  All the headers name value pair is concatenated and delimited.
     * @return Eg "Host: www.example.com\r\nUser-agent: some agent\r\n"
     */
    public String getHeadersAsString() {
      return mMsgHeader;
    }

    public boolean isEmpty() {
        if (mMsgHeader == null || mMsgHeader.equals("")) {
            return true;
        }
        
        return false;
    }
    
      public String getCharset() {
          String contentType = getHeader(CONTENT_TYPE);
          String charset = "";
          if (contentType == null) {
              return null;
          }
          
          Matcher matcher = patternCharset.matcher(contentType);
          if (matcher.find()) {
              charset = matcher.group(1);
          }
          return charset;
      }
}

Generated by  Doxygen 1.6.0   Back to index