You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@locus.apache.org on 2000/11/17 04:30:44 UTC

cvs commit: jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http HttpHeader.java HttpRequestLine.java SocketInputStream.java HttpProcessor.java LocalStrings.properties

remm        00/11/16 19:30:43

  Modified:    catalina/src/share/org/apache/catalina/connector/http
                        HttpProcessor.java LocalStrings.properties
  Added:       catalina/src/share/org/apache/catalina/connector/http
                        HttpHeader.java HttpRequestLine.java
                        SocketInputStream.java
  Log:
  - Optimized the socket byte reading, which results in a big boost of the
    connector performance. Overall servlet performance is increased by around
    30%, and is on par with the current CVS version of Tomcat 3.3.
  - Add some recyclable specilized buffer objects for the handling of the
    request line and the headers.
  - HttpProcessor currently do not take advantage of these objects, and wrap
    them into String objects immediately after reading them. Very little changes
    have been made to the HTTP processor, so far.
  - The request header parsing is now done inside the socket stream, to get
    maximum performance.
  - The new buffer objects will eventually allow to have 0 GC inside the
    connector.
  
  Revision  Changes    Path
  1.12      +57 -76    jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpProcessor.java
  
  Index: HttpProcessor.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpProcessor.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- HttpProcessor.java	2000/11/11 01:38:09	1.11
  +++ HttpProcessor.java	2000/11/17 03:30:43	1.12
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpProcessor.java,v 1.11 2000/11/11 01:38:09 craigmcc Exp $
  - * $Revision: 1.11 $
  - * $Date: 2000/11/11 01:38:09 $
  + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpProcessor.java,v 1.12 2000/11/17 03:30:43 remm Exp $
  + * $Revision: 1.12 $
  + * $Date: 2000/11/17 03:30:43 $
    *
    * ====================================================================
    *
  @@ -106,7 +106,7 @@
    *
    * @author Craig R. McClanahan
    * @author Remy Maucherat
  - * @version $Revision: 1.11 $ $Date: 2000/11/11 01:38:09 $
  + * @version $Revision: 1.12 $ $Date: 2000/11/17 03:30:43 $
    */
   
   final class HttpProcessor
  @@ -272,6 +272,24 @@
       private static final byte[] CRLF = (new String("\r\n")).getBytes();
   
   
  +    /**
  +     * Line buffer.
  +     */
  +    private char[] lineBuffer = new char[4096];
  +
  +
  +    /**
  +     * Request line buffer.
  +     */
  +    private HttpRequestLine requestLine = new HttpRequestLine();
  +
  +
  +    /**
  +     * HTTP header.
  +     */
  +    private HttpHeader header = new HttpHeader();
  +
  +
       // -------------------------------------------------------- Package Methods
   
   
  @@ -497,27 +515,33 @@
        * @exception IOException if an input/output error occurs
        * @exception ServletException if a parsing error occurs
        */
  -    private void parseHeaders(InputStream input)
  +    private void parseHeaders(SocketInputStream input)
           throws IOException, ServletException {
   
   	while (true) {
  -
  -	    // Read the next header line
  -	    String line = read(input);
  -	    if ((line == null) || (line.length() < 1))
  -		break;
   
  -	    // Parse the header name and value
  -	    int colon = line.indexOf(":");
  -	    if (colon < 0)
  -		throw new ServletException
  -		    (sm.getString("httpProcessor.parseHeaders.colon"));
  -	    String name = line.substring(0, colon).trim();
  -	    String match = name.toLowerCase();
  -	    String value = line.substring(colon + 1).trim();
  +            try {
  +                // Read the next header
  +                input.readHeader(header);
  +            } catch (Throwable t) {
  +                t.printStackTrace();
  +            }
  +            if (header.nameEnd == 0) {
  +                if (header.valueEnd == 0) {
  +                    return;
  +                } else {
  +                    throw new ServletException
  +                        (sm.getString("httpProcessor.parseHeaders.colon"));
  +                }
  +            }
  +            
  +	    String name = new String(header.name, 0, header.nameEnd);
  +	    String match = name;
  +	    String value = new String(header.value, 0, header.valueEnd);
  +            //System.out.println("  Header:" + name + "_ Value:" + value + "_");
   	    if (debug >= 1)
   	        log(" Header " + name + " = " + value);
  -
  +            
   	    // Set the corresponding request headers
   	    if (match.equals("authorization")) {
   		request.setAuthorization(value);
  @@ -603,26 +627,20 @@
        * @exception IOException if an input/output error occurs
        * @exception ServletException if a parsing error occurs
        */
  -    private void parseRequest(InputStream input, OutputStream output)
  +    private void parseRequest(SocketInputStream input, OutputStream output)
           throws IOException, ServletException {
   
   	// Parse the incoming request line
  -	String line = read(input);
  -	if (line == null)
  -	    throw new EOFException
  -		(sm.getString("httpProcessor.parseRequest.read"));
  -	parser.setString(line);
  -
  -	int methodStart = parser.skipWhite();
  -	int methodEnd = parser.findWhite();
  -	int uriStart = parser.skipWhite();
  -	int uriEnd = parser.findWhite();
  -	int protocolStart = parser.skipWhite();
  -	int protocolEnd = parser.findWhite();
  -
  -	String method = parser.extract(methodStart, methodEnd);
  -	String uri = parser.extract(uriStart, uriEnd);
  -	String protocol = parser.extract(protocolStart, protocolEnd);
  +        input.readRequestLine(requestLine);
  +        String method = 
  +            new String(requestLine.method, 0, requestLine.methodEnd);
  +        String uri = new String(requestLine.uri, 0, requestLine.uriEnd);
  +        String protocol = new String(requestLine.protocol, 0, 
  +                              requestLine.protocolEnd);
  +        
  +        //System.out.println(" Method:" + method + "_ Uri:" + uri 
  +        //                   + "_ Protocol:" + protocol);
  +        
   	if (protocol.length() == 0)
   	    protocol = "HTTP/0.9";
   
  @@ -720,13 +738,13 @@
       private void process(Socket socket) {
   
   	boolean ok = true;
  -	InputStream input = null;
  +	SocketInputStream input = null;
   	OutputStream output = null;
   
   	// Construct and initialize the objects we will need
   	try {
  -	    input = new BufferedInputStream(socket.getInputStream(),
  -	    				    connector.getBufferSize());
  +	    input = new SocketInputStream(socket.getInputStream(),
  +                                          connector.getBufferSize());
   	} catch (Exception e) {
   	    log("process.create", e);
   	    ok = false;
  @@ -844,43 +862,6 @@
   	    ;
   	}
   	socket = null;
  -
  -    }
  -
  -
  -    /**
  -     * Read a line from the specified input stream, and strip off the
  -     * trailing carriage return and newline (if any).  Return the remaining
  -     * characters that were read as a String.
  -     *
  -     * @param input The input stream connected to our socket
  -     *
  -     * @return The line that was read, or <code>null</code> if end-of-file
  -     *  was encountered
  -     *
  -     * @exception IOException if an input/output error occurs
  -     */
  -    private String read(InputStream input) throws IOException {
  -
  -	StringBuffer sb = new StringBuffer();
  -	while (true) {
  -	    int ch = input.read();
  -	    if (ch < 0) {
  -		if (sb.length() == 0) {
  -		    return (null);
  -		} else {
  -		    break;
  -		}
  -	    } else if (ch == '\r') {
  -		continue;
  -	    } else if (ch == '\n') {
  -		break;
  -	    }
  -	    sb.append((char) ch);
  -	}
  -	if (debug >= 2)
  -	    log("  Read: " + sb.toString());
  -	return (sb.toString());
   
       }
   
  
  
  
  1.2       +3 -1      jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/LocalStrings.properties
  
  Index: LocalStrings.properties
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/LocalStrings.properties,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- LocalStrings.properties	2000/08/11 22:40:53	1.1
  +++ LocalStrings.properties	2000/11/17 03:30:43	1.2
  @@ -23,4 +23,6 @@
   httpProcessor.stopping=Stopping background thread
   requestStream.close.closed=Request stream has already been closed
   requestStream.read.closed=Unable to read from a closed stream
  -requestStream.read.error=Unexpected end of stream
  \ No newline at end of file
  +requestStream.read.error=Unexpected end of stream
  +requestStream.readline.error=Couldn't read line
  +requestStream.readline.toolong=Line too long
  \ No newline at end of file
  
  
  
  1.1                  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpHeader.java
  
  Index: HttpHeader.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpHeader.java,v 1.1 2000/11/17 03:30:43 remm Exp $
   * $Revision: 1.1 $
   * $Date: 2000/11/17 03:30:43 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  
  package org.apache.catalina.connector.http;
  
  
  import java.io.IOException;
  import java.net.InetAddress;
  import javax.servlet.ServletInputStream;
  import org.apache.catalina.connector.HttpRequestBase;
  
  
  /**
   * HTTP header enum type.
   *
   * @author Remy Maucherat
   * @version $Revision: 1.1 $ $Date: 2000/11/17 03:30:43 $
   */
  
  final class HttpHeader {
  
  
      // -------------------------------------------------------------- Constants
  
  
      public static final int INITIAL_NAME_SIZE = 32;
      public static final int INITIAL_VALUE_SIZE = 64;
      public static final int MAX_NAME_SIZE = 128;
      public static final int MAX_VALUE_SIZE = 4096;
  
  
      // ----------------------------------------------------------- Constructors
  
  
      public HttpHeader() {
  
          this(new char[INITIAL_NAME_SIZE], 0, new char[INITIAL_VALUE_SIZE], 0);
  
      }
  
  
      public HttpHeader(char[] name, int nameEnd, char[] value, int valueEnd) {
  
          this.name = name;
          this.nameEnd = nameEnd;
          this.value = value;
          this.valueEnd = valueEnd;
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      public char[] name;
      public int nameEnd;
      public char[] value;
      public int valueEnd;
  
  
      // ------------------------------------------------------------- Properties
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Release all object references, and initialize instance variables, in
       * preparation for reuse of this object.
       */
      public void recycle() {
  
          nameEnd = 0;
          valueEnd = 0;
  
      }
  
  
      // --------------------------------------------------------- Object Methods
  
  
      public int hashCode() {
          // FIXME
          return 0;
      }
  
  
      public boolean equals(Object obj) {
          return false;
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpRequestLine.java
  
  Index: HttpRequestLine.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/HttpRequestLine.java,v 1.1 2000/11/17 03:30:43 remm Exp $
   * $Revision: 1.1 $
   * $Date: 2000/11/17 03:30:43 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  
  package org.apache.catalina.connector.http;
  
  
  import java.io.IOException;
  import java.net.InetAddress;
  import javax.servlet.ServletInputStream;
  import org.apache.catalina.connector.HttpRequestBase;
  
  
  /**
   * HTTP request line enum type.
   *
   * @author Remy Maucherat
   * @version $Revision: 1.1 $ $Date: 2000/11/17 03:30:43 $
   */
  
  final class HttpRequestLine {
  
  
      // -------------------------------------------------------------- Constants
  
  
      public static final int INITIAL_METHOD_SIZE = 8;
      public static final int INITIAL_URI_SIZE = 64;
      public static final int INITIAL_PROTOCOL_SIZE = 8;
      public static final int MAX_METHOD_SIZE = 128;
      public static final int MAX_URI_SIZE = 4096;
      public static final int MAX_PROTOCOL_SIZE = 32;
  
  
      // ----------------------------------------------------------- Constructors
  
  
      public HttpRequestLine() {
  
          this(new char[INITIAL_METHOD_SIZE], 0, new char[INITIAL_URI_SIZE], 0, 
               new char[INITIAL_URI_SIZE], 0);
  
      }
  
  
      public HttpRequestLine(char[] method, int methodEnd, 
                             char[] uri, int uriEnd,
                             char[] protocol, int protocolEnd) {
  
          this.method = method;
          this.methodEnd = methodEnd;
          this.uri = uri;
          this.uriEnd = uriEnd;
          this.protocol = protocol;
          this.protocolEnd = protocolEnd;
  
      }
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      public char[] method;
      public int methodEnd;
      public char[] uri;
      public int uriEnd;
      public char[] protocol;
      public int protocolEnd;
  
  
      // ------------------------------------------------------------- Properties
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Release all object references, and initialize instance variables, in
       * preparation for reuse of this object.
       */
      public void recycle() {
  
          methodEnd = 0;
          uriEnd = 0;
          protocolEnd = 0;
  
      }
  
  
      // --------------------------------------------------------- Object Methods
  
  
      public int hashCode() {
          // FIXME
          return 0;
      }
  
  
      public boolean equals(Object obj) {
          return false;
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/SocketInputStream.java
  
  Index: SocketInputStream.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/connector/http/SocketInputStream.java,v 1.1 2000/11/17 03:30:43 remm Exp $
   * $Revision: 1.1 $
   * $Date: 2000/11/17 03:30:43 $
   *
   * ====================================================================
   * 
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  
  
  package org.apache.catalina.connector.http;
  
  import java.io.IOException;
  import java.io.BufferedInputStream;
  import java.io.InputStream;
  import org.apache.catalina.util.StringManager;
  
  /**
   * Extends BufferedInputStream to be more efficient reading lines during HTTP
   * header processing.
   *
   * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
   */
  public class SocketInputStream extends BufferedInputStream {
  
  
      // -------------------------------------------------------------- Constants
  
  
      /**
       * CR.
       */
      private static final byte CR = (byte) '\r';
  
  
      /**
       * LF.
       */
      private static final byte LF = (byte) '\n';
  
  
      /**
       * SP.
       */
      private static final byte SP = (byte) ' ';
  
  
      /**
       * COLON.
       */
      private static final byte COLON = (byte) ':';
  
  
      /**
       * Lower case offset.
       */
      private static final int LC_OFFSET = 'A' - 'a';
  
  
      // ----------------------------------------------------------- Constructors
  
  
      /**
       * Construct a servlet input stream associated with the specified socket
       * input.
       *
       * @param is socket input stream
       * @param bufferSize size of the internal buffer
       */
      public SocketInputStream(InputStream is, int bufferSize) {
  
  	super(is, bufferSize);
  
      }
  
  
      // -------------------------------------------------------------- Variables
  
  
      /**
       * The string manager for this package.
       */
      protected static StringManager sm =
  	StringManager.getManager(Constants.Package);
  
  
      // ----------------------------------------------------- Instance Variables
  
  
      // --------------------------------------------------------- Public Methods
  
  
      /**
       * Read the request line, and copies it to the given buffer. This 
       * function is meant to be used during the HTTP request header parsing. 
       * Do NOT attempt to read the request body using it.
       * 
       * @param requestLine Request line object
       * @throws IOException If an exception occurs during the underlying socket
       * read operations, or if the given buffer is not big enough to accomodate
       * the whole line.
       */
      public void readRequestLine(HttpRequestLine requestLine) 
          throws IOException {
  
          // Recycling check
          if (requestLine.methodEnd != 0)
              requestLine.recycle();
          
          // Reading the method name
  
          int maxRead = requestLine.method.length;
          int readStart = pos;
          int readCount = 0;
          
          boolean space = false;
          
          while (!space) {
              // if the buffer is full, extend it
              if (readCount >= maxRead) {
                  if ((2 * maxRead) <= HttpRequestLine.MAX_METHOD_SIZE) {
                      char[] newBuffer = new char[2 * maxRead];
                      System.arraycopy(requestLine.method, 0, newBuffer, 0,
                                       maxRead);
                      requestLine.method = newBuffer;
                      maxRead = requestLine.method.length;
                  } else {
                      throw new IOException
                          (sm.getString("requestStream.readline.toolong"));
                  }
              }
              // We're at the end of the internal buffer
              if (pos >= count) {
                  int val = read();
                  if (val == -1) {
                      throw new IOException
                          (sm.getString("requestStream.readline.error"));
                  }
                  pos = 0;
                  readStart = 0;
              }
              if (buf[pos] == SP) {
                  space = true;
              }
              requestLine.method[readCount] = (char) buf[pos];
              readCount++;
              pos++;
          }
          
          requestLine.methodEnd = readCount - 1;
  
          // Reading URI
  
          maxRead = requestLine.uri.length;
          readStart = pos;
          readCount = 0;
          
          space = false;
          
          while (!space) {
              // if the buffer is full, extend it
              if (readCount >= maxRead) {
                  if ((2 * maxRead) <= HttpRequestLine.MAX_URI_SIZE) {
                      char[] newBuffer = new char[2 * maxRead];
                      System.arraycopy(requestLine.uri, 0, newBuffer, 0,
                                       maxRead);
                      requestLine.uri = newBuffer;
                      maxRead = requestLine.uri.length;
                  } else {
                      throw new IOException
                          (sm.getString("requestStream.readline.toolong"));
                  }
              }
              // We're at the end of the internal buffer
              if (pos >= count) {
                  int val = read();
                  if (val == -1)
                      throw new IOException
                          (sm.getString("requestStream.readline.error"));
                  pos = 0;
                  readStart = 0;
              }
              if (buf[pos] == SP) {
                  space = true;
              }
              requestLine.uri[readCount] = (char) buf[pos];
              readCount++;
              pos++;
          }
          
          requestLine.uriEnd = readCount - 1;
  
          // Reading protocol
  
          maxRead = requestLine.protocol.length;
          readStart = pos;
          readCount = 0;
          
          int crPos = -2;
          
          boolean eol = false;
          
          while (!eol) {
              // if the buffer is full, extend it
              if (readCount >= maxRead) {
                  if ((2 * maxRead) <= HttpRequestLine.MAX_PROTOCOL_SIZE) {
                      char[] newBuffer = new char[2 * maxRead];
                      System.arraycopy(requestLine.protocol, 0, newBuffer, 0,
                                       maxRead);
                      requestLine.protocol = newBuffer;
                      maxRead = requestLine.protocol.length;
                  } else {
                      throw new IOException
                          (sm.getString("requestStream.readline.toolong"));
                  }
              }
              // We're at the end of the internal buffer
              if (pos >= count) {
                  // Copying part (or all) of the internal buffer to the line
                  // buffer
                  if (pos != readStart) {
                      // Hack to reintialize the internal buffer. We pretend the 
                      // first character was never read and we'll reread it from
                      // the buffer.
                      crPos = crPos - count;
                  }
                  int val = read();
                  if (val == -1)
                      throw new IOException
                          (sm.getString("requestStream.readline.error"));
                  pos = 0;
                  readStart = 0;
              }
              if (buf[pos] == CR) {
                  // We found a CR. Next character has to be a LF.
                  crPos = pos;
              } else if ((buf[pos] == LF) && (crPos == (pos - 1))) {
                  eol = true;
              }
              requestLine.protocol[readCount] = (char) buf[pos];
              readCount++;
              pos++;
          }
          
          requestLine.protocolEnd = readCount - 2;
          
      }
  
  
      /**
       * Read a header, and copies it to the given buffer. This 
       * function is meant to be used during the HTTP request header parsing. 
       * Do NOT attempt to read the request body using it.
       * 
       * @param requestLine Request line object
       * @throws IOException If an exception occurs during the underlying socket
       * read operations, or if the given buffer is not big enough to accomodate
       * the whole line.
       */
      public void readHeader(HttpHeader header) 
          throws IOException {
          
          // Recycling check
          if (header.nameEnd != 0)
              header.recycle();
          
          // Checking for a blank line
          if (read() == CR) { // Skipping CR
              read(); // Skipping LF
              header.nameEnd = 0;
              header.valueEnd = 0;
              return;
          } else {
              pos--;
          }
          
          // Reading the header name
  
          int maxRead = header.name.length;
          int readStart = pos;
          int readCount = 0;
          
          boolean colon = false;
          
          while (!colon) {
              // if the buffer is full, extend it
              if (readCount >= maxRead) {
                  if ((2 * maxRead) <= HttpHeader.MAX_NAME_SIZE) {
                      char[] newBuffer = new char[2 * maxRead];
                      System.arraycopy(header.name, 0, newBuffer, 0, maxRead);
                      header.name = newBuffer;
                      maxRead = header.name.length;
                  } else {
                      throw new IOException
                          (sm.getString("requestStream.readline.toolong"));
                  }
              }
              // We're at the end of the internal buffer
              if (pos >= count) {
                  int val = read();
                  if (val == -1) {
                      throw new IOException
                          (sm.getString("requestStream.readline.error"));
                  }
                  pos = 0;
                  readStart = 0;
              }
              if (buf[pos] == COLON) {
                  colon = true;
              }
              char val = (char) buf[pos];
              if ((val >= 'A') && (val <= 'Z')) {
                  val = (char) (val - LC_OFFSET);
              }
              header.name[readCount] = val;
              readCount++;
              pos++;
          }
          
          header.nameEnd = readCount - 1;
          
          // Reading the header value (which can be spanned over multiple lines)
  
          maxRead = header.value.length;
          readStart = pos;
          readCount = 0;
          
          int crPos = -2;
          
          boolean eol = false;
          boolean validLine = true;
          
          while (validLine) {
              
              boolean space = true;
              
              // Skipping spaces
              // Note : Only leading white spaces are removed. Trailing white 
              // spaces are not.
              while (space) {
                  // We're at the end of the internal buffer
                  if (pos >= count) {
                      // Copying part (or all) of the internal buffer to the line
                      // buffer
                      int val = read();
                      if (val == -1)
                          throw new IOException
                              (sm.getString("requestStream.readline.error"));
                      pos = 0;
                      readStart = 0;
                  }
                  if (buf[pos] == SP) {
                      pos++;
                  } else {
                      space = false;
                  }
              }
              
              while (!eol) {
                  // if the buffer is full, extend it
                  if (readCount >= maxRead) {
                      if ((2 * maxRead) <= HttpHeader.MAX_VALUE_SIZE) {
                          char[] newBuffer = new char[2 * maxRead];
                          System.arraycopy(header.value, 0, newBuffer, 0,
                                           maxRead);
                          header.value = newBuffer;
                          maxRead = header.value.length;
                      } else {
                          throw new IOException
                              (sm.getString("requestStream.readline.toolong"));
                      }
                  }
                  // We're at the end of the internal buffer
                  if (pos >= count) {
                      // Copying part (or all) of the internal buffer to the line
                      // buffer
                      if (pos != readStart) {
                          // Hack to reintialize the internal buffer. 
                          // We pretend the first character was never read and 
                          // we'll reread it from the buffer.
                          crPos = crPos - count;
                      }
                      int val = read();
                      if (val == -1)
                          throw new IOException
                              (sm.getString("requestStream.readline.error"));
                      pos = 0;
                      readStart = 0;
                  }
                  if (buf[pos] == CR) {
                      // We found a CR. Next character has to be a LF.
                      crPos = pos;
                  } else if ((buf[pos] == LF) && (crPos == (pos - 1))) {
                      eol = true;
                  } else {
                      // FIXME : Check if binary conversion is working fine
                      header.value[readCount] = (char) (buf[pos] & 0xff);
                      readCount++;
                  }
                  pos++;
              }
              
              if (read() != SP) {
                  pos--;
                  validLine = false;
              } else {
                  eol = false;
                  // if the buffer is full, extend it
                  if (readCount >= maxRead) {
                      if ((2 * maxRead) <= HttpHeader.MAX_VALUE_SIZE) {
                          char[] newBuffer = new char[2 * maxRead];
                          System.arraycopy(header.value, 0, newBuffer, 0,
                                           maxRead);
                          header.value = newBuffer;
                          maxRead = header.value.length;
                      } else {
                          throw new IOException
                              (sm.getString("requestStream.readline.toolong"));
                      }
                  }
                  header.value[readCount] = ' ';
                  readCount++;
              }
              
          }
          
          header.valueEnd = readCount;
          
      }
  
  
      /**
       * Read a line, and copies it to the given buffer. This function is meant
       * to be used during the HTTP request header parsing. Do NOT attempt to 
       * read the request body using it.
       * 
       * @param buffer char buffer
       * @return the number of bytes read
       * @throws IOException If an exception occurs during the underlying socket
       * read operations, or if the given buffer is not big enough to accomodate
       * the whole line.
       */
      public int readLine(char[] buffer) 
          throws IOException {
          return readLine(buffer, 0);
      }
  
  
      /**
       * Read a line, and copies it to the given buffer. This function is meant
       * to be used during the HTTP request header parsing. Do NOT attempt to 
       * read the request body using it. Read data must be US-ASCII.
       * 
       * @param buffer char buffer
       * @param startPos position in the buffer from which the read character
       * will be copied
       * @return the number of bytes read
       * @throws IOException If an exception occurs during the underlying socket
       * read operations, or if the given buffer is not big enough to accomodate
       * the whole line.
       */
      public int readLine(char[] buffer, int startPos) 
          throws IOException {
          int maxRead = buffer.length - startPos;
          int readStart = pos;
          int readCount = 0;
          int bufferPos = startPos;
          
          int crPos = -2;
          
          boolean eol = false;
          
          while (!eol && (readCount < maxRead)) {
              
              // We're at the end of the internal buffer
              if (pos >= count) {
                  // Copying part (or all) of the internal buffer to the line
                  // buffer
                  if (pos != readStart) {
                      // Hack to reintialize the internal buffer. We pretend the 
                      // first character was never read and we'll reread it from
                      // the buffer.
                      crPos = crPos - count;
                  }
                  int val = read();
                  if (val == -1)
                      throw new IOException
                          (sm.getString("requestStream.readline.error"));
                  pos = 0;
                  readStart = 0;
              }
              if (buf[pos] == CR) {
                  // We found a CR. Next character has to be a LF.
                  crPos = pos;
              } else if ((buf[pos] == LF) && (crPos == (pos - 1))) {
                  eol = true;
              }
              buffer[startPos + readCount] = (char) buf[pos];
              readCount++;
              pos++;
          }
          
          if (readCount == maxRead)
              throw new IOException
                  (sm.getString("requestStream.readline.toolong"));
          
          return readCount - 2;
      }
  
  
      /**
       * Read a line, and copies it to the given buffer. This function is meant
       * to be used during the HTTP request header parsing. Do NOT attempt to 
       * read the request body using it.
       * 
       * @param buffer byte buffer
       * @return the number of bytes read
       * @throws IOException If an exception occurs during the underlying socket
       * read operations, or if the given buffer is not big enough to accomodate
       * the whole line.
       */
      public int readLine(byte[] buffer) 
          throws IOException {
          return readLine(buffer, 0);
      }
  
  
      /**
       * Read a line, and copies it to the given buffer. This function is meant
       * to be used during the HTTP request header parsing. Do NOT attempt to 
       * read the request body using it.
       * 
       * @param buffer byte buffer
       * @param startPos position in the buffer from which the read character
       * will be copied
       * @return the number of bytes read
       * @throws IOException If an exception occurs during the underlying socket
       * read operations, or if the given buffer is not big enough to accomodate
       * the whole line.
       */
      public int readLine(byte[] buffer, int startPos) 
          throws IOException {
          int maxRead = buffer.length - startPos;
          int readStart = pos;
          int readCount = 0;
          int bufferPos = startPos;
          
          int crPos = -2;
          
          boolean eol = false;
          
          while (!eol && (readCount < maxRead)) {
              
              // We're at the end of the internal buffer
              if (pos >= count) {
                  // Copying part (or all) of the internal buffer to the line
                  // buffer
                  if (pos != readStart) {
                      System.arraycopy(buf, readStart, buffer, bufferPos, 
                                       pos - readStart);
                      // Hack to reintialize the internal buffer. We pretend the 
                      // first character was never read and we'll reread it from
                      // the buffer.
                      crPos = crPos - count;
                      bufferPos += pos - readStart;
                  }
                  int val = read();
                  if (val == -1)
                      throw new IOException
                          (sm.getString("requestStream.readline.error"));
                  pos = 0;
                  readStart = 0;
              }
              if (buf[pos] == CR) {
                  // We found a CR. Next character has to be a LF.
                  crPos = pos;
              } else if ((buf[pos] == LF) && (crPos == (pos - 1))) {
                  eol = true;
                  // Copy the line from the buffer
                  if ((pos - 1 - readStart) > 0)
                      System.arraycopy
                          (buf, readStart, buffer, bufferPos, 
                           pos - 1 - readStart);
              }
              readCount++;
              pos++;
          }
          
          if (readCount == maxRead)
              throw new IOException
                  (sm.getString("requestStream.readline.toolong"));
          
          return readCount - 2;
      }
  
  
      // ------------------------------------------------------ Protected Methods
  
  
  }