You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@locus.apache.org on 2000/08/11 08:14:21 UTC

cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/util ArrayEnumerator.java Ascii.java DateTool.java MessageBytes.java MimeHeaderField.java

costin      00/08/10 23:14:20

  Modified:    .        build.xml
               src/share/org/apache/tomcat/context DefaultCMSetter.java
               src/share/org/apache/tomcat/core ContextManager.java
                        OutputBuffer.java Request.java RequestImpl.java
                        Response.java ResponseImpl.java
               src/share/org/apache/tomcat/facade
                        HttpServletResponseFacade.java
                        ServletOutputStreamFacade.java
                        ServletWriterFacade.java
               src/share/org/apache/tomcat/request AccessInterceptor.java
                        SimpleMapper1.java StaticInterceptor.java
               src/share/org/apache/tomcat/service/connector
                        Ajp12ConnectionHandler.java
                        Ajp13ConnectorRequest.java
                        JNIConnectionHandler.java
               src/share/org/apache/tomcat/service/http
                        HttpRequestAdapter.java HttpResponseAdapter.java
               src/share/org/apache/tomcat/util ArrayEnumerator.java
                        Ascii.java DateTool.java MessageBytes.java
                        MimeHeaderField.java
  Log:
  This is a big change, I couldn't find a good way of spliting it
  ( most changes are related with each other ).
  
  This is just a start for a big refactoring - the goal is security and
  performance.
  
  This change:
  
  - For all internal Handlers, use a per/thread re-usable StringBuffer.
  The buffer is not converted toString, so it generates no garbage.
  
  - use OutputBuffer - the code from BufferedServletOutputStream is now here,
  plus addition to write a StringBuffer ( without the expensive toString())
  ( still need to make sure the char/byte mixing works in all cases - this
  is the DEV branch )
  
  - removed the old ByteBuffer code - interesting experiment, too complex.
  
  - enhanced MessageBytes ( used as an efficient way to store headers ).
  Also use MessageBytes for efficient storage of request fields.
  This still require a lot of work, but we are getting very close to 0 GC.
  ( at least for requests without params and without cookies - those will
  also need to be converted to recyclable structures )
  
  - also few small cosmetic changes in RequestImpl to allow better visibility.
  Most fields will disapear soon, it will be a very simple class.
  
  - Same for response - only OutputBuffer is used in Request and core, the
  Output/Writer is handled by facade.
  
  - few minor optimizations ( cache, avoid GC )
  
  - a bit of cleanup ( more to come )
  
  - few optimizations in HttpRequest
  
  Revision  Changes    Path
  1.59      +1 -1      jakarta-tomcat/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/build.xml,v
  retrieving revision 1.58
  retrieving revision 1.59
  diff -u -r1.58 -r1.59
  --- build.xml	2000/08/05 15:56:06	1.58
  +++ build.xml	2000/08/11 06:14:02	1.59
  @@ -10,7 +10,7 @@
       <property name="tomcat.build" value="../build/tomcat"/>
       <property name="tomcat.home" value="../dist/tomcat"/>
       <property name="j2ee.home" value="../j2ee/build/unix"/>
  -    <property name="optimize" value="true" />
  +    <property name="optimize" value="false" />
       <property name="jaxp" value="../jaxp1.0.1" />
     </target>
   
  
  
  
  1.48      +65 -43    jakarta-tomcat/src/share/org/apache/tomcat/context/DefaultCMSetter.java
  
  Index: DefaultCMSetter.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/context/DefaultCMSetter.java,v
  retrieving revision 1.47
  retrieving revision 1.48
  diff -u -r1.47 -r1.48
  --- DefaultCMSetter.java	2000/08/02 02:17:06	1.47
  +++ DefaultCMSetter.java	2000/08/11 06:14:04	1.48
  @@ -137,7 +137,8 @@
   class NotFoundHandler extends Handler {
       static StringManager sm=StringManager.
   	getManager("org.apache.tomcat.resources");
  -
  +    int sbNote=0;
  +    
       NotFoundHandler() {
   	initialized=true;
   	internal=true;
  @@ -155,8 +156,20 @@
   	if (requestURI == null) {
   	    requestURI = req.getRequestURI();
   	}
  +
  +	if( sbNote==0 ) {
  +	    sbNote=req.getContextManager().getNoteId(ContextManager.REQUEST_NOTE,
  +						     "NotFoundHandler.buff");
  +	}
   
  -	StringBuffer buf = new StringBuffer();
  +	// we can recycle it because
  +	// we don't call toString();
  +	StringBuffer buf=(StringBuffer)req.getNote( sbNote );
  +	if( buf==null ) {
  +	    buf = new StringBuffer();
  +	    req.setNote( sbNote, buf );
  +	}
  +	
   	buf.append("<head><title>")
   	    .append(sm.getString("defaulterrorpage.notfound404"))
   	    .append("</title></head>\r\n");
  @@ -167,25 +180,17 @@
   	    .append( requestURI );
   	buf.append("</body>\r\n");
   
  -	String body = buf.toString();
  +	res.setContentLength(buf.length());
   
  -	res.setContentLength(body.length());
  -
  -	if( res.isUsingStream() ) {
  -	    ServletOutputStream out = res.getOutputStream();
  -	    out.print(body);
  -	    out.flush();
  -	} else {
  -	    PrintWriter out = res.getWriter();
  -	    out.print(body);
  -	    out.flush();
  -	}
  +	res.getBuffer().write( buf );
  +	buf.setLength(0);
       }
   }
   
   class ExceptionHandler extends Handler {
       static StringManager sm=StringManager.
   	getManager("org.apache.tomcat.resources");
  +    int sbNote=0;
   
       ExceptionHandler() {
   	initialized=true;
  @@ -208,7 +213,18 @@
   	res.setContentType("text/html");
   	res.setStatus( 500 );
   	
  -	StringBuffer buf = new StringBuffer();
  +	if( sbNote==0 ) {
  +	    sbNote=req.getContextManager().getNoteId(ContextManager.REQUEST_NOTE,
  +						     "ExceptionHandler.buff");
  +	}
  +
  +	// we can recycle it because
  +	// we don't call toString();
  +	StringBuffer buf=(StringBuffer)req.getNote( sbNote );
  +	if( buf==null ) {
  +	    buf = new StringBuffer();
  +	    req.setNote( sbNote, buf );
  +	}
   	buf.append("<h1>");
   	if( res.isIncluded() ) {
   	    buf.append(sm.getString("defaulterrorpage.includedservlet") ).
  @@ -240,19 +256,15 @@
   	
   	buf.append("\r\n");
   	
  -	if( res.isUsingStream() ) {
  -	    ServletOutputStream out = res.getOutputStream();
  -	    out.print(buf.toString());
  -	} else {
  -	    PrintWriter out = res.getWriter();
  -	    out.print(buf.toString());
  -	}
  +	res.getBuffer().write( buf );
  +	buf.setLength(0);
       }
   }
   
   class StatusHandler extends Handler {
       static StringManager sm=StringManager.
   	getManager("org.apache.tomcat.resources");
  +    int sbNote=0;
   
       StatusHandler() {
   	initialized=true;
  @@ -272,7 +284,18 @@
   	// status is already set
   	int sc=res.getStatus();
   	
  -	StringBuffer buf = new StringBuffer();
  +	if( sbNote==0 ) {
  +	    sbNote=req.getContextManager().getNoteId(ContextManager.REQUEST_NOTE,
  +						     "StatusHandler.buff");
  +	}
  +
  +	// we can recycle it because
  +	// we don't call toString();
  +	StringBuffer buf=(StringBuffer)req.getNote( sbNote );
  +	if( buf==null ) {
  +	    buf = new StringBuffer();
  +	    req.setNote( sbNote, buf );
  +	}
   	buf.append("<h1>");
   	if( res.isIncluded() ) {
   	    buf.append(sm.getString("defaulterrorpage.includedservlet") );
  @@ -293,19 +316,16 @@
   	    .append(msg)
   	    .append("</b><br>");
   
  -	if( res.isUsingStream() ) {
  -	    ServletOutputStream out = res.getOutputStream();
  -	    out.print(buf.toString());
  -	} else {
  -	    PrintWriter out = res.getWriter();
  -	    out.print(buf.toString());
  -	}
  +	res.setContentLength(buf.length());
  +	res.getBuffer().write( buf );
  +	buf.setLength(0);
       }
   }
   	
   class RedirectHandler extends Handler {
       static StringManager sm=StringManager.
   	getManager("org.apache.tomcat.resources");
  +    int sbNote=0;
   
       RedirectHandler() {
   	initialized=true;
  @@ -329,7 +349,18 @@
   	res.setContentType("text/html");	// ISO-8859-1 default
   	res.setHeader("Location", location);
   
  -	StringBuffer buf = new StringBuffer();
  +	if( sbNote==0 ) {
  +	    sbNote=req.getContextManager().getNoteId(ContextManager.REQUEST_NOTE,
  +						     "RedirectHandler.buff");
  +	}
  +
  +	// we can recycle it because
  +	// we don't call toString();
  +	StringBuffer buf=(StringBuffer)req.getNote( sbNote );
  +	if( buf==null ) {
  +	    buf = new StringBuffer();
  +	    req.setNote( sbNote, buf );
  +	}
   	buf.append("<head><title>").
   	    append(sm.getString("defaulterrorpage.documentmoved")).
   	    append("</title></head>\r\n<body><h1>").
  @@ -340,19 +371,10 @@
   	    append(location).
   	    append("\">here</a>.<p>\r\n</body>\r\n");
   
  -	String body = buf.toString();
  +	res.setContentLength(buf.length());
  +	res.getBuffer().write( buf );
  +	buf.setLength(0);
   
  -	res.setContentLength(body.length());
  -
  -	if( res.isUsingStream() ) {
  -	    ServletOutputStream out = res.getOutputStream();
  -	    out.print(body);
  -	    out.flush();
  -	} else {
  -	    PrintWriter out = res.getWriter();
  -	    out.print(body);
  -	    out.flush();
  -	}
       }
   
       // XXX Move it to URLUtil !!!
  
  
  
  1.110     +1 -1      jakarta-tomcat/src/share/org/apache/tomcat/core/ContextManager.java
  
  Index: ContextManager.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ContextManager.java,v
  retrieving revision 1.109
  retrieving revision 1.110
  diff -u -r1.109 -r1.110
  --- ContextManager.java	2000/08/09 13:43:48	1.109
  +++ ContextManager.java	2000/08/11 06:14:06	1.110
  @@ -640,7 +640,7 @@
   	    if( status >= 400 ) {
   		if( debug > 0)
   		    log( "Error reading request " + req + " " + status);
  -		handleStatus( req, res, status );
  +		handleStatus( req, res, status ); 
   		return;
   	    }
   
  
  
  
  1.2       +265 -32   jakarta-tomcat/src/share/org/apache/tomcat/core/OutputBuffer.java
  
  Index: OutputBuffer.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/OutputBuffer.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- OutputBuffer.java	2000/07/31 02:35:15	1.1
  +++ OutputBuffer.java	2000/08/11 06:14:06	1.2
  @@ -56,11 +56,10 @@
    * [Additional notices, if required by prior licensing conditions]
    *
    */ 
  -
  -
   package org.apache.tomcat.core;
   
   import java.io.*;
  +import java.util.*;
   
   /**
    * The buffer used by tomcat response. It allows writting chars and
  @@ -71,17 +70,25 @@
    *
    * @author Costin Manolache
    */
  -public final class OutputBuffer {
  +public final class OutputBuffer extends Writer {
       public static final int DEFAULT_BUFFER_SIZE = 8*1024;
       int defaultBufferSize = DEFAULT_BUFFER_SIZE;
  +    int defaultCharBufferSize = DEFAULT_BUFFER_SIZE / 2 ;
  +
  +    // The buffer can be used for byte[] and char[] writing
  +    // ( this is needed to support ServletOutputStream and for
  +    // efficient implementations of templating systems )
  +    public final int INITIAL_STATE=0;
  +    public final int CHAR_STATE=1;
  +    public final int BYTE_STATE=2;
  +    int state=0;
  +
  +    static final int debug=0;
       int bytesWritten = 0;
   
       /** The buffer
        */
       public byte buf[];
  -
  -    public int start;
  -    public int end;
       
       /**
        * The index one greater than the index of the last valid byte in 
  @@ -89,7 +96,6 @@
        */
       public int count;
   
  -    final static int debug=0;
   
       Response resp;
       Request req;
  @@ -97,37 +103,37 @@
       
       public OutputBuffer(Response resp) {
   	buf=new byte[defaultBufferSize];
  + 	cbuf=new char[defaultCharBufferSize];
   	this.resp=resp;
   	req=resp.getRequest();
   	cm=req.getContextManager();
       }
   
  +    void log( String s ) {
  +	System.out.println("OutputBuffer: " + s );
  +    }
  +
       public void recycle() {
  +	if( debug > 0 ) log("recycle()");
  +	state=INITIAL_STATE;
   	bytesWritten=0;
  +	charsWritten=0;
  +	ccount=0;
   	count=0;
       }
  -
  -    /** This method will call the interceptors and then write the buf[]
  -     *  to the adapter's doWrite.
  -     */
  -    void doWrite( byte buf[], int off, int count ) throws IOException {
  -	cm.doWrite( req, resp, buf, off, count );
  -    }
   
  -    // -------------------- Adding to the buffer -------------------- 
  +    // -------------------- Adding bytes to the buffer -------------------- 
       // Like BufferedOutputStream, without sync
   
  -    public void write(int b) throws IOException {
  -	if( debug>1 )System.out.write( b );
  -	if (count >= buf.length) {
  -	    flush();
  -	}
  -	buf[count++] = (byte)b;
  -	bytesWritten++;
  -    }
  -
       public void write(byte b[], int off, int len) throws IOException {
  -	if( debug>1 ) System.out.write( b, off, len );
  +	if( state==CHAR_STATE )
  +	    flushChars();
  +	state=BYTE_STATE;
  +	writeBytes( b, off, len );
  +    }
  +    
  +    public void writeBytes(byte b[], int off, int len) throws IOException {
  +	if( debug > 0 ) log("write(b,off,len)");
   	int avail=buf.length - count;
   
   	bytesWritten += len;
  @@ -153,7 +159,7 @@
   	    */
   	    System.arraycopy(b, off, buf, count, avail);
   	    count += avail;
  -	    flush();
  +	    flushBytes();
   	    
   	    System.arraycopy(b, off+avail, buf, count, len - avail);
   	    count+= len - avail;
  @@ -162,17 +168,191 @@
   	}
   
   	// len > buf.length + avail
  -	flush();
  -	doWrite( b, off, len );
  +	flushBytes();
  +	cm.doWrite( req, resp, b, off, len );
   
   	return;
       }
   
  -    // --------------------  BufferedOutputStream compatibility
  +    // XXX Char or byte ?
  +    public void writeByte(int b) throws IOException {
  +	if( state==CHAR_STATE )
  +	    flushChars();
  +	state=BYTE_STATE;
  +	if( debug > 0 ) log("write(b)");
  +	if (count >= buf.length) {
  +	    flushBytes();
  +	}
  +	buf[count++] = (byte)b;
  +	bytesWritten++;
  +    }
  +
  +
  +    // -------------------- Adding chars to the buffer
  +    String enc;
  +    boolean gotEnc=false;
  +    public char cbuf[];
  +    public int ccount;
  +    int charsWritten;
  +    
  +    
  +    public void write( int c ) throws IOException {
  +	state=CHAR_STATE;
  +	if( debug > 0 ) log("writeChar(b)");
  +	if (ccount >= cbuf.length) {
  +	    flushChars();
  +	}
  +	cbuf[ccount++] = (char)c;
  +	charsWritten++;
  +    }
  +
  +    public void write( char c[] ) throws IOException {
  +	write( c, 0, c.length );
  +    }
  +    
  +    public void write(char c[], int off, int len) throws IOException {
  +	state=CHAR_STATE;
  +	if( debug > 0 ) log("write(c,off,len)");
  +	int avail=cbuf.length - ccount;
  +
  +	charsWritten += len;
  +
  +	// fit in buffer, great.
  +	if( len <= avail ) {
  +	    System.arraycopy(c, off, cbuf, ccount, len);
  +	    ccount += len;
  +	    return;
  +	}
  +
  +	if (len - avail < cbuf.length) {
  +	    /* If the request length exceeds the size of the output buffer,
  +    	       flush the output buffer and then write the data directly.
  +	       We can't avoid 2 writes, but we can write more on the second
  +	    */
  +	    System.arraycopy(c, off, cbuf, ccount, avail);
  +	    ccount += avail;
  +	    flushChars();
  +	    
  +	    System.arraycopy(c, off+avail, cbuf, ccount, len - avail);
  +	    ccount+= len - avail;
  +	    charsWritten += len - avail;
  +	    return;
  +	}
  +
  +	// len > buf.length + avail
  +	flushChars();
  +	cWrite(  c, off, len );
   
  +	return;
  +    }
  +
  +    private int min(int a, int b) {
  +	if (a < b) return a;
  +	return b;
  +    }
  +
  +    public void write( StringBuffer sb ) throws IOException {
  +	state=CHAR_STATE;
  +	if( debug > 0 ) log("write(s,off,len)");
  +	int len=sb.length();
  +	charsWritten += len;
  +
  +	int off=0;
  +	int b = off;
  +	int t = off + len;
  +	while (b < t) {
  +	    int d = min(cbuf.length - ccount, t - b);
  +	    sb.getChars( b, b+d, cbuf, ccount);
  +	    b += d;
  +	    ccount += d;
  +	    if (ccount >= cbuf.length)
  +		flushChars();
  +	}
  +	return;
  +    }
  +
  +    public void write(String s, int off, int len) throws IOException {
  +	state=CHAR_STATE;
  +	if( debug > 0 ) log("write(s,off,len)");
  +	charsWritten += len;
  +	if (s==null) s="null";
  +	
  +	// different strategy: we can't write more then cbuf[]
  +	// because of conversions. Writing in 8k chunks is not bad.
  +	int b = off;
  +	int t = off + len;
  +	while (b < t) {
  +	    int d = min(cbuf.length - ccount, t - b);
  +	    s.getChars( b, b+d, cbuf, ccount);
  +	    b += d;
  +	    ccount += d;
  +	    if (ccount >= cbuf.length)
  +		flushChars();
  +	}
  +	return;
  +    }
  +    
  +    public void write(String s) throws IOException {
  +	state=CHAR_STATE;
  +	if (s==null) s="null";
  +	write( s, 0, s.length() );
  +    } 
  +
  +    public void flushChars() throws IOException {
  +	if( debug > 0 ) log("flushChars() " + ccount);
  +	if( ccount > 0) {
  +	    cWrite(  cbuf, 0, ccount );
  +	    ccount=0;
  +	}
  +    }
  +
  +    public void close() throws IOException {
  +	//nothing
  +    }
  +
       public void flush() throws IOException {
  +	System.out.println("No flush ");
  +    }
  +    
  +    Hashtable encoders=new Hashtable();
  +    WriteConvertor conv;
  +    
  +    void cWrite( char c[], int off, int len ) throws IOException {
  +	if( debug > 0 ) log("cWrite(c,o,l) " + ccount);
  +	if( !gotEnc ) setConverter();
  +
  +	conv.write(c, off, len);
  +	conv.flush();
  +    }
  +
  +    private void setConverter() {
  +	enc = resp.getCharacterEncoding();
  +	gotEnc=true;
  +	if(enc==null) enc="8859_1";
  +	conv=(WriteConvertor)encoders.get(enc);
  +	if(conv==null) {
  +	    IntermediateOutputStream ios=new IntermediateOutputStream(this);
  +	    try {
  +		conv=new WriteConvertor(ios,enc);
  +		encoders.put(enc, conv);
  +	    } catch(UnsupportedEncodingException ex ) {
  +		conv=(WriteConvertor)encoders.get("8859_1");
  +		if(conv==null) {
  +		    try {
  +			conv=new WriteConvertor(ios, "8859_1");
  +			encoders.put("8859_1", conv);
  +		    } catch( UnsupportedEncodingException e ) {}
  +		}
  +	    }
  +	}
  +    }
  +    
  +    // --------------------  BufferedOutputStream compatibility
  +
  +    public void flushBytes() throws IOException {
  +	if( debug > 0 ) log("flushBytes() " + count);
   	if( count > 0) {
  -	    doWrite( buf, 0, count );
  +	    cm.doWrite( req, resp, buf, 0, count );
   	    count=0;
   	}
       }
  @@ -199,8 +379,61 @@
   
       // -------------------- Utils
   
  -    void log( String s ) {
  -	System.out.println("OutputBuffer: " + s );
  +}
  +
  +class WriteConvertor extends OutputStreamWriter {
  +    /* Has a private, internal byte[8192]
  +     */
  +    public WriteConvertor( OutputStream out, String enc )
  +	throws UnsupportedEncodingException
  +    {
  +	super( out, enc );
       }
  +
  +    public void close() throws IOException {
  +	// NOTHING
  +	// Calling super.close() would reset out and cb.
  +    }
  +
  +    public void flush() throws IOException {
  +	// Will flushBuffer and out()
  +	// flushBuffer put any remaining chars in the byte[] 
  +	super.flush();
  +    }
  +
  +    public void write(char cbuf[], int off, int len) throws IOException {
  +	// will do the conversion and call write on the output stream
  +	super.write( cbuf, off, len );
  +    }
  +}
  +
  +
  +class IntermediateOutputStream extends OutputStream {
  +    OutputBuffer tbuff;
       
  +    public IntermediateOutputStream(OutputBuffer tbuff) {
  +	this.tbuff=tbuff;
  +    }
  +
  +    public void close() throws IOException {
  +	// shouldn't be called - we filter it out in writer
  +	System.out.println("close() called - shouldn't happen ");
  +	throw new IOException("close() called - shouldn't happen ");
  +    }
  +
  +    public void flush() throws IOException {
  +	// nothing - write will go directly to the buffer,
  +	// we don't keep any state
  +    }
  +
  +    public void write(byte cbuf[], int off, int len) throws IOException {
  +	//	System.out.println("IOS: " + len );
  +	tbuff.writeBytes( cbuf, off, len );
  +    }
  +
  +    public void write( int i ) throws IOException {
  +	System.out.println("write(int ) called - shouldn't happen ");
  +	throw new IOException("write(int ) called - shouldn't happen ");
  +    }
   }
  +
  
  
  
  1.50      +0 -5      jakarta-tomcat/src/share/org/apache/tomcat/core/Request.java
  
  Index: Request.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/Request.java,v
  retrieving revision 1.49
  retrieving revision 1.50
  diff -u -r1.49 -r1.50
  --- Request.java	2000/08/02 02:17:11	1.49
  +++ Request.java	2000/08/11 06:14:06	1.50
  @@ -340,11 +340,6 @@
       /** This is the top request ( for a sub-request )
        */
       public Request getTop();
  -    // -------------------- Buffers --------------------
  -
  -    //    public ByteBuffer getInputBuffer();
  -
  -    //    public void setInputBuffer(ByteBuffer buf);
   
       // -------------------- Notes --------------------
       /** Add a per/request internal attribute.
  
  
  
  1.57      +82 -92    jakarta-tomcat/src/share/org/apache/tomcat/core/RequestImpl.java
  
  Index: RequestImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/RequestImpl.java,v
  retrieving revision 1.56
  retrieving revision 1.57
  diff -u -r1.56 -r1.57
  --- RequestImpl.java	2000/08/02 02:17:11	1.56
  +++ RequestImpl.java	2000/08/11 06:14:07	1.57
  @@ -83,53 +83,64 @@
    */
   public class RequestImpl  implements Request {
   
  +    protected int serverPort;
  +    protected String remoteAddr;
  +    protected String remoteHost;
  +    protected String localHost;
  +
  +    // Request components represented as MB.
  +    // MB are also used for headers - it allows lazy
  +    // byte->char conversion so we can add the encoding
  +    // that is known only after header parsing. Work in progress.
  +    protected MessageBytes schemeMB=new MessageBytes();
  +    protected MessageBytes methodMB=new MessageBytes();
  +    protected MessageBytes uriMB=new MessageBytes();
  +    protected MessageBytes queryMB=new MessageBytes();
  +    protected MessageBytes protoMB=new MessageBytes();
  +    // uri components
  +    protected MessageBytes contextMB=new MessageBytes();
  +    protected MessageBytes servletPathMB=new MessageBytes();
  +    protected MessageBytes pathInfoMB=new MessageBytes();
  +
       // GS, used by the load balancing layer in the Web Servers
       // jvmRoute == the name of the JVM inside the plugin.
       protected String jvmRoute;
   
  -    // XXX used by forward to override, need a better
  -    // mechanism
  -    protected String requestURI;
  -    protected String queryString;
  -
  -   //  RequestAdapterImpl Hints
  -    protected String serverName=null;
  +    protected Hashtable attributes = new Hashtable();
  +    protected MimeHeaders headers;
       protected Vector cookies = new Vector();
   
  -    protected String contextPath;
  -    protected String lookupPath; // everything after contextPath before ?
  -    protected String servletPath;
  -    protected String pathInfo;
  -    protected String pathTranslated;
  -    // Need to distinguish between null pathTranslated and
  -    // lazy-computed pathTranlsated
  -    protected boolean pathTranslatedIsSet=false;
  -
  +    // Processed information ( redundant ! )
       protected Hashtable parameters = new Hashtable();
  +
  +
       protected int contentLength = -1;
       protected String contentType = null;
       protected String charEncoding = null;
  +    protected String serverName=null;
  +
  +    // auth infor
       protected String authType;
       boolean notAuthenticated=true;
       protected String remoteUser;
  -
       protected Principal principal;
       // active roles for the current user
       protected String userRoles[];
       protected String reqRoles[];
   
  -    // Request
  +    // Association with other tomcat comp.
       protected Response response;
  -    protected HttpServletRequest requestFacade;
  -    protected Context context;
       protected ContextManager contextM;
  -    protected Hashtable attributes = new Hashtable();
  +    protected Context context;
   
       protected boolean didReadFormData;
       protected boolean didParameters;
       protected boolean didCookies;
       // end "Request" variables
   
  +    // @deprecated
  +    protected HttpServletRequest requestFacade;
  +
       // Session
       // set by interceptors - the session id
       protected String reqSessionId;
  @@ -137,44 +148,54 @@
       // cache- avoid calling SessionManager for each getSession()
       protected HttpSession serverSession;
   
  -
  -    // LookupResult - used by sub-requests and
  -    // set by interceptors
  -    protected String servletName;
       protected Handler handler = null;
       Container container;
   
  -    protected String mappedPath = null;
  -
  -    protected String scheme;
  -    protected String method;
  -    protected String protocol;
  -    protected MimeHeaders headers;
       protected ServletInputStream in;
  -
  -    protected int serverPort;
  -    protected String remoteAddr;
  -    protected String remoteHost;
  -    protected String localHost;
  -    protected ByteBuffer bBuffer;
   
  +    // sub-request support 
       Request top;
       Request parent;
       Request child;
   
  +    // ResourceBundle
       protected static StringManager sm =
           StringManager.getManager("org.apache.tomcat.core");
   
  +    // @deprecated
  +    protected String method;
  +    protected String requestURI;
  +    protected String queryString;
  +    protected String protocol;
  +    protected String servletName;
  +    
  +    protected String mappedPath = null;
  +    protected String contextPath;
  +    protected String lookupPath; // everything after contextPath before ?
  +    protected String servletPath;
  +    protected String pathInfo;
  +    protected String pathTranslated;
  +    // Need to distinguish between null pathTranslated and
  +    // lazy-computed pathTranlsated
  +    protected boolean pathTranslatedIsSet=false;
  +    
       public RequestImpl() {
  -	//	log("XXX new ri " );
    	headers = new MimeHeaders();
    	recycle(); // XXX need better placement-super()
       }
   
  +    /** Called by mapper interceptors after the context
  +	is found or directly by server adapters when
  +	this is known in advance
  +    */
       public void setContext(Context context) {
   	this.context = context;
       }
   
  +    public Context getContext() {
  +	return context;
  +    }
  +
       public void setContextManager( ContextManager cm ) {
   	contextM=cm;
       }
  @@ -183,8 +204,16 @@
   	return contextM;
       }
   
  +    public MessageBytes getSchemeMB() {
  +	return schemeMB;
  +    }
  +
       public String getScheme() {
  -        return scheme;
  +        return schemeMB.toString();
  +    }
  +
  +    public void setScheme( String scheme ) {
  +	schemeMB.setString(scheme);
       }
   
       public String getMethod() {
  @@ -294,6 +323,7 @@
   	return contentType;
       }
   
  +
       /** All adapters that know the PT needs to call this method,
   	in order to set pathTranslatedIsSet, otherwise tomcat
   	will try to compute it again
  @@ -347,7 +377,7 @@
   
       public boolean isSecure() {
   	// The adapter is responsible for providing this information
  -        return getScheme().equalsIgnoreCase("HTTPS");
  +        return schemeMB.equalsIgnoreCase("HTTPS");
       }
   
       public void setUserPrincipal( Principal p ) {
  @@ -414,10 +444,6 @@
   	return requestFacade;
       }
   
  -    public Context getContext() {
  -	return context;
  -    }
  -
       public void setResponse(Response response) {
   	this.response = response;
       }
  @@ -468,7 +494,7 @@
   	//	context.log("RequestImpl:  created new session!");
   	contextM.doNewSessionRequest( this, response );
   	if ( serverSession == null ) {
  -	    log("RequestImpl: no session created!");
  +	    //	    context.log("RequestImpl: no session created!");
   	    return null;
   	}
   
  @@ -712,7 +738,6 @@
           container=null;
           handler=null;
           jvmRoute = null;
  -        scheme = "http";// no need to use Constants
           method = "GET";
           requestURI="/";
           queryString=null;
  @@ -730,7 +755,6 @@
           remoteAddr="127.0.0.1";
           remoteHost="localhost";
           localHost="localhost";
  -	if( bBuffer != null ) bBuffer.recycle();
           for( int i=0; i<ACCOUNTS; i++ ) accTable[i]=0;
           for( int i=0; i<ContextManager.MAX_NOTES; i++ ) notes[i]=null;
   	parent=null;
  @@ -740,6 +764,16 @@
   	userRoles=null;
   	reqRoles=null;
   	in=null;
  +
  +	uriMB.recycle();
  +	contextMB.recycle();
  +	pathInfoMB.recycle();
  +	servletPathMB.recycle();
  +	queryMB.recycle();
  +	methodMB.recycle();
  +	protoMB.recycle();
  +        schemeMB.setString("http");
  +
       }
   
       public MimeHeaders getMimeHeaders() {
  @@ -754,15 +788,6 @@
           return headers.names();
       }
   
  -    public ByteBuffer getInputBuffer() {
  -	return bBuffer;
  -    }
  -
  -    public void setInputBuffer(ByteBuffer buf) {
  -	bBuffer=buf;
  -    }
  -
  -
       public ServletInputStream getInputStream() throws IOException {
   	// will be removed from here
   	return getFacade().getInputStream();
  @@ -815,10 +840,6 @@
   	return null;
       }
   
  -    public void setScheme( String scheme ) {
  -	this.scheme=scheme;
  -    }
  -
       public void setMethod( String method ) {
   	this.method=method;
       }
  @@ -831,10 +852,6 @@
   	this.headers=headers;
       }
   
  -    public void setBody( StringBuffer body ) {
  -	// ???
  -    }
  -
       public void setServerPort(int serverPort ) {
   	this.serverPort=serverPort;
       }
  @@ -872,18 +889,6 @@
   	return sb.toString();
       }
   
  -    public String toStringDebug() {
  -	StringBuffer sb=new StringBuffer();
  -	sb.append( "Request( " + context ).append("\n");
  -	sb.append( "    URI:" + getRequestURI()  ).append("\n");
  -	sb.append( "    SP:" + getServletPath() );
  -	sb.append( ",PI:" + getPathInfo() );
  -	sb.append( ",LP:" + getLookupPath() );
  -	sb.append( ",MP:" + getMappedPath() );
  -	sb.append( "," + getWrapper() +") ");
  -	return sb.toString();
  -    }
  -
       // -------------------- Accounting --------------------
       // XXX Will be implemented as a note !
       public static final int ACC_PRE_CMAP=0;
  @@ -905,7 +910,7 @@
   	return accTable[pos];
       }
   
  -    // -------------------- Per-Container "notes"
  +    // -------------------- Per-Request "notes"
       Object notes[]=new Object[ContextManager.MAX_NOTES];
   
       public void setNote( int pos, Object value ) {
  @@ -916,19 +921,4 @@
   	return notes[pos];
       }
   
  -    Logger.Helper loghelper = new Logger.Helper("tc_log", this);
  -    
  -    protected void log(String s) {
  -	log(s, null);
  -    }
  -    protected void log(String s, Throwable t) {
  -	if (context != null) {
  -	    loghelper.setLogger(context.getLoggerHelper().getLogger());
  -	}
  -	else if (contextM != null) {
  -	    loghelper.setLogger(contextM.getLoggerHelper().getLogger());
  -	}
  -	loghelper.log(s);
  -    }		       
  -    
   }
  
  
  
  1.25      +19 -25    jakarta-tomcat/src/share/org/apache/tomcat/core/Response.java
  
  Index: Response.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/Response.java,v
  retrieving revision 1.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- Response.java	2000/08/02 02:17:12	1.24
  +++ Response.java	2000/08/11 06:14:07	1.25
  @@ -100,23 +100,23 @@
        */
       public boolean isStarted() ;
   
  -    /** True if getOutputStream was called.
  -     *  Used to avoid the ugly try getWriter() catch getOutputStream.
  -     */
  -    public boolean isUsingStream();
  -
  -    /** The output stream is used.
  -     */
  -    public void setUsingStream( boolean stream );
  -
  -    /** Stream/Writer control
  -     */
  -    public boolean isUsingWriter();
  +//     /** True if getOutputStream was called.
  +//      *  Used to avoid the ugly try getWriter() catch getOutputStream.
  +//      */
  +//     public boolean isUsingStream();
  +
  +//     /** The output stream is used.
  +//      */
  +//     public void setUsingStream( boolean stream );
  +
  +//     /** Stream/Writer control
  +//      */
  +//     public boolean isUsingWriter();
  +
  +//     /** Stream/Writer control
  +//      */
  +//     public void setUsingWriter( boolean writer );
   
  -    /** Stream/Writer control
  -     */
  -    public void setUsingWriter( boolean writer );
  -
       
       /** Signal that we're done with a particular request, the
        *	server can go on and read more requests or close the socket
  @@ -126,14 +126,14 @@
       /** Either re-implement getOutputStream or return BufferedServletOutputStream(this)
        *  and implement doWrite();
        */
  -    public ServletOutputStream getOutputStream() throws IOException;
  +//     public ServletOutputStream getOutputStream() throws IOException;
   
       public void setServletOutputStream(ServletOutputStream s );
  -    public void setWriter( PrintWriter w );
  +//     public void setWriter( PrintWriter w );
       
       public void doWrite( byte buffer[], int pos, int count) throws IOException;
       
  -    public PrintWriter getWriter() throws IOException ;
  +//     public PrintWriter getWriter() throws IOException ;
   
       /** True if we are in an included servlet
        */
  @@ -211,12 +211,6 @@
   
       public OutputBuffer getBuffer();
   
  -    // @deprecated
  -    //    public ByteBuffer getOutputBuffer();
  -
  -    //    public void  setOutputBuffer(ByteBuffer buf);
  -
  -    
       // -------------------- Internal methods --------------------
       /** One-to-one with Facade.
        *  You can use HttpResponseFacade.
  
  
  
  1.38      +77 -57    jakarta-tomcat/src/share/org/apache/tomcat/core/ResponseImpl.java
  
  Index: ResponseImpl.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ResponseImpl.java,v
  retrieving revision 1.37
  retrieving revision 1.38
  diff -u -r1.37 -r1.38
  --- ResponseImpl.java	2000/08/02 02:17:12	1.37
  +++ ResponseImpl.java	2000/08/11 06:14:07	1.38
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ResponseImpl.java,v 1.37 2000/08/02 02:17:12 costin Exp $
  - * $Revision: 1.37 $
  - * $Date: 2000/08/02 02:17:12 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ResponseImpl.java,v 1.38 2000/08/11 06:14:07 costin Exp $
  + * $Revision: 1.38 $
  + * $Date: 2000/08/11 06:14:07 $
    *
    * ====================================================================
    *
  @@ -209,11 +209,12 @@
       }
   
       public void finish() throws IOException {
  -	if (usingWriter && (writer != null)) {
  -	    writer.flush();
  -	    writer.close();
  -	}
  -	oBuffer.flush();
  +	// 	if (usingWriter && (writer != null)) {
  +	// 	    writer.flush();
  +	// 	    writer.close();
  +	// 	}
  +	oBuffer.flushChars();
  +	oBuffer.flushBytes();
   
   	// 	if( bBuffer != null) {
   	// 	    bBuffer.flush();
  @@ -252,59 +253,61 @@
   	//	if( out!=null ) out.setUsingWriter(true);
       }
   
  -    public void setWriter( PrintWriter w ) {
  -	this.writer=w;
  -    }
  +//     public void setWriter( PrintWriter w ) {
  +// 	this.writer=w;
  +//     }
       
  -    public PrintWriter getWriter() throws IOException {
  -	// usingWriter
  -	if( writer != null )
  -	    return writer;
  +//     public PrintWriter getWriter() throws IOException {
  +// 	// usingWriter
  +// 	if( writer != null )
  +// 	    return writer;
   
  -	sos=getFacade().getOutputStream();
  +// 	sos=getFacade().getOutputStream();
   	    
  -	writer=getWriter( sos );
  +// 	writer=getWriter( sos );
   
  -	return writer;
  +// 	return writer;
      
  -	// 	if( out !=null )
  -	// 	    return getWriter( out );
  +// 	// 	if( out !=null )
  +// 	// 	    return getWriter( out );
   	
  -	// it will know what to do. This method is here
  -	// just to keep old code happy ( internal error handlers)
  -	//if( usingStream ) {
  -	//    return getWriter( getFacade().getOutputStream());
  -	//}
  -	//return getFacade().getWriter();
  -    }
  +// 	// it will know what to do. This method is here
  +// 	// just to keep old code happy ( internal error handlers)
  +// 	//if( usingStream ) {
  +// 	//    return getWriter( getFacade().getOutputStream());
  +// 	//}
  +// 	//return getFacade().getWriter();
  +//     }
   
  -    public PrintWriter getWriter(ServletOutputStream outs) throws IOException {
  -	if(writer!=null) return writer;
  -	// it already did all the checkings
  +//     public PrintWriter getWriter(ServletOutputStream outs) throws IOException {
   	
  -	started = true;
  -	usingWriter = true;
  +// 	if(writer!=null) return writer;
  +// 	// it already did all the checkings
   	
  -	writer = new ServletWriterFacade( getConverter(outs), this);
  -	return writer;
  -    }
  -
  -    public Writer getConverter( ServletOutputStream outs ) throws IOException {
  -	String encoding = getCharacterEncoding();
  +// 	started = true;
  +// 	usingWriter = true;
  +	
  +// 	//	writer = new ServletWriterFacade( getConverter(outs), this);
  +// 	writer = new ServletWriterFacade( oBuffer, this);
  +// 	return writer;
  +//     }
   
  -	if (encoding == null) {
  -	    // use default platform encoding - is this correct ? 
  -	    return  new OutputStreamWriter(outs);
  -        }  else {
  -	    try {
  -		return  new OutputStreamWriter(outs, encoding);
  -	    } catch (java.io.UnsupportedEncodingException ex) {
  -		log("Unsuported encoding: " + encoding, Logger.ERROR );
  +//     public Writer getConverter( ServletOutputStream outs ) throws IOException {
  +// 	String encoding = getCharacterEncoding();
   
  -		return new OutputStreamWriter(outs);
  -	    }
  -	}
  -    }
  +// 	if (encoding == null) {
  +// 	    // use default platform encoding - is this correct ? 
  +// 	    return  new OutputStreamWriter(outs);
  +//         }  else {
  +// 	    try {
  +// 		return  new OutputStreamWriter(outs, encoding);
  +// 	    } catch (java.io.UnsupportedEncodingException ex) {
  +// 		log("Unsuported encoding: " + encoding, Logger.ERROR );
  +
  +// 		return new OutputStreamWriter(outs);
  +// 	    }
  +// 	}
  +//     }
   
       public OutputBuffer getBuffer() {
   	return oBuffer;
  @@ -347,14 +350,22 @@
   
       public void setHeader(String name, String value) {
   	if( ! notIncluded ) return; // we are in included sub-request
  -	if( ! checkSpecialHeader(name, value) ) 
  -	    headers.putHeader(name, value);
  +	char cc=name.charAt(0);
  +	if( cc=='C' || cc=='c' ) {
  +	    if( checkSpecialHeader(name, value) )
  +		return;
  +	}
  +	headers.putHeader(name, value);
       }
   
       public void addHeader(String name, String value) {
   	if( ! notIncluded ) return; // we are in included sub-request
  -	if( ! checkSpecialHeader(name, value) ) 
  -	    headers.addHeader(name, value);
  +	char cc=name.charAt(0);
  +	if( cc=='C' || cc=='c' ) {
  +	    if( checkSpecialHeader(name, value) )
  +		return;
  +	}
  +	headers.addHeader(name, value);
       }
   
       
  @@ -471,10 +482,11 @@
   
       public void flushBuffer() throws IOException {
   	//	if( notIncluded) {
  -	if (usingWriter == true && writer != null)
  -	    writer.flush();
  +	// 	if (usingWriter == true && writer != null)
  +	// 	    writer.flush();
   
  -	oBuffer.flush();
  +	oBuffer.flushChars();
  +	oBuffer.flushBytes();
   	// 	if( out!=null ) out.reallyFlush();
   	// 	if(bBuffer!=null) bBuffer.flush();
   	    //} 
  @@ -634,6 +646,8 @@
   
       static String st_200=null;
       static String st_302=null;
  +    static String st_400=null;
  +    static String st_404=null;
       
       // utility method - should be in a different class
       public static String getMessage( int status ) {
  @@ -647,6 +661,12 @@
   	case 302:
   	    if( st_302==null ) st_302=sm.getString( "sc.302");
   	    return st_302;
  +	case 400:
  +	    if( st_400==null ) st_400=sm.getString( "sc.400");
  +	    return st_400;
  +	case 404:
  +	    if( st_404==null ) st_404=sm.getString( "sc.404");
  +	    return st_404;
   	}
   	return sm.getString("sc."+ status);
       }
  
  
  
  1.12      +13 -10    jakarta-tomcat/src/share/org/apache/tomcat/facade/HttpServletResponseFacade.java
  
  Index: HttpServletResponseFacade.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/facade/HttpServletResponseFacade.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- HttpServletResponseFacade.java	2000/08/02 02:17:25	1.11
  +++ HttpServletResponseFacade.java	2000/08/11 06:14:09	1.12
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/facade/HttpServletResponseFacade.java,v 1.11 2000/08/02 02:17:25 costin Exp $
  - * $Revision: 1.11 $
  - * $Date: 2000/08/02 02:17:25 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/facade/HttpServletResponseFacade.java,v 1.12 2000/08/11 06:14:09 costin Exp $
  + * $Revision: 1.12 $
  + * $Date: 2000/08/11 06:14:09 $
    *
    * ====================================================================
    *
  @@ -103,7 +103,7 @@
       void recycle() {
   	usingStream = false;
   	usingWriter= false;
  -	writer=null;
  +	// 	writer=null; // no need - the OutputBuffer will deal with enc
   	if( osFacade != null ) osFacade.recycle();
       }
   
  @@ -160,12 +160,12 @@
   	    throw new IllegalStateException(msg);
   	}
   	usingStream=true;
  -	response.setUsingStream( true );
  +	// 	response.setUsingStream( true );
   
   	if( osFacade!=null) return osFacade;
   	//if( response.getOutputBuffer() != null ) {
   	osFacade=new ServletOutputStreamFacade(response);
  -	response.setServletOutputStream( osFacade );
  +	// response.setServletOutputStream( osFacade );
   	//}
   	return osFacade;
   
  @@ -180,7 +180,7 @@
   	    throw new IllegalStateException(msg);
   	}
   	usingWriter= true ;
  -	response.setUsingWriter( true );
  +	// 	response.setUsingWriter( true );
   
   	// old mechanism
   	// if( osFacade==null && response.getOutputBuffer() == null )
  @@ -191,9 +191,12 @@
   	    osFacade=new ServletOutputStreamFacade(response);
   	}
   
  -	writer=((ResponseImpl)response).getWriter( osFacade );
  -	response.setServletOutputStream( osFacade );
  -	response.setWriter(  writer );
  +	OutputBuffer oBuffer= response.getBuffer();
  +	writer = new ServletWriterFacade( oBuffer, response);
  +	
  +	// writer=((ResponseImpl)response).getWriter( osFacade );
  +	// 	response.setServletOutputStream( osFacade );
  +	// 	response.setWriter(  writer );
   
   	return writer;
       }
  
  
  
  1.7       +22 -66    jakarta-tomcat/src/share/org/apache/tomcat/facade/ServletOutputStreamFacade.java
  
  Index: ServletOutputStreamFacade.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/facade/ServletOutputStreamFacade.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- ServletOutputStreamFacade.java	2000/07/31 02:35:16	1.6
  +++ ServletOutputStreamFacade.java	2000/08/11 06:14:09	1.7
  @@ -70,18 +70,10 @@
    * 
    */
   final class ServletOutputStreamFacade extends ServletOutputStream {
  -    // Use the strings from core
  -    protected StringManager sm = StringManager.
  -	getManager("org.apache.tomcat.core");
  -
  -    // encoding
  -    private Writer writer=null;
  -    
       protected boolean closed = false;
   
       Response resA;
       OutputBuffer ob;
  -    //ByteBuffer bb;
       
       /** Encoding - first time print() is used.
   	IMPORTANT: print() is _bad_, if you want to write Strings and mix
  @@ -96,15 +88,12 @@
       protected ServletOutputStreamFacade( Response resA) {
   	this.resA=resA;
   	ob=resA.getBuffer();
  -	// 	bb=resA.getOutputBuffer();
  -	// 	bb.addBufferListener( new  BufferResponseAdapter());
       }
   
       // -------------------- Write methods --------------------
       
       public void write(int i) throws IOException {
  -	//	bb.write(i);
  -	ob.write(i);
  +	ob.writeByte(i);
       }
   
       public void write(byte[] b) throws IOException {
  @@ -112,7 +101,6 @@
       }
       
       public void write(byte[] b, int off, int len) throws IOException {
  -	//	bb.write( b, off, len );
   	ob.write( b, off, len );
       }
   
  @@ -128,37 +116,36 @@
   	Please use getWriter() if you want to send strings.
       */
       public void print(String s) throws IOException {
  -	if (s==null) s="null";
  -	byte b[]=null;
  -	if( !gotEnc ) {
  -	    enc = resA.getCharacterEncoding();
  -	    gotEnc=true;
  -	    if ( Constants.DEFAULT_CHAR_ENCODING.equals(enc) )
  -		enc=null;
  -	}
  -	if( enc==null) 
  -	    b=s.getBytes();
  -	else 
  -	    try {
  -		b=s.getBytes( enc );
  -	    } catch (java.io.UnsupportedEncodingException ex) {
  -		b=s.getBytes();
  -		enc=null;
  -	    } 
  +// 	if (s==null) s="null";
  +// 	byte b[]=null;
  +// 	if( !gotEnc ) {
  +// 	    enc = resA.getCharacterEncoding();
  +// 	    gotEnc=true;
  +// 	    if ( Constants.DEFAULT_CHAR_ENCODING.equals(enc) )
  +// 		enc=null;
  +// 	}
  +// 	if( enc==null) 
  +// 	    b=s.getBytes();
  +// 	else 
  +// 	    try {
  +// 		b=s.getBytes( enc );
  +// 	    } catch (java.io.UnsupportedEncodingException ex) {
  +// 		b=s.getBytes();
  +// 		enc=null;
  +// 	    } 
   	
  -	write( b );
  +// 	write( b );
  +	ob.write(s);
       } 
   
       /** Will send the buffer to the client.
        */
       public void flush() throws IOException {
  -	//	bb.flush(); // send it now !
  -	ob.flush();
  +	ob.flushBytes();
       }
   
       public void close() throws IOException {
  -	//	bb.flush(); // send it now !
  -	ob.flush();
  +	ob.flushBytes();
   	closed = true;
       }
   
  @@ -166,40 +153,9 @@
        *  Called from BSOS
        */
       void recycle() {
  -	writer=null;
   	closed = false;
   	enc=null;
   	gotEnc=false;
       }
  -
  -//     // -------------------- ByteBuffer
  -//     // Initial experimental support - this will change.
  -//     // This is an adapter between ByteBuffer and server adapters implementing
  -//     // doWrite
  -//     class BufferResponseAdapter implements BufferListener {
  -// 	BufferResponseAdapter() {
  -// 	}
  -
  -// 	public void bufferEmpty( BufferEvent ev ) {
  -// 	    return;
  -// 	}
  -    
  -// 	public void bufferFull( BufferEvent ev ) {
  -// 	    try {
  -// 		// Find if this is the first chunk , if so do send head 
  -// 		//	    log( "Buffer full event ");
  -// 		ByteBuffer bb=(ByteBuffer)ev.getSource();
  -// 		Response res=(Response)bb.getParent();
  -// 		Request request=res.getRequest();
  -// 		request.getContextManager().doWrite( request, res,
  -// 						     ev.getByteBuffer(),
  -// 						     ev.getOffset(),
  -// 						     ev.getLength() );
  -// 	    } catch( IOException ex ) {
  -// 		ex.printStackTrace();
  -// 		// XXX mark exception ?
  -// 	    }
  -// 	}
  -//     }
   }
   
  
  
  
  1.4       +4 -26     jakarta-tomcat/src/share/org/apache/tomcat/facade/ServletWriterFacade.java
  
  Index: ServletWriterFacade.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/facade/ServletWriterFacade.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- ServletWriterFacade.java	2000/06/30 20:21:34	1.3
  +++ ServletWriterFacade.java	2000/08/11 06:14:09	1.4
  @@ -80,56 +80,34 @@
   // XXX hack - public will be removed after we add the CharBuffer and we fix the converter
   public final class ServletWriterFacade extends PrintWriter {
       Response resA;
  -    RequestImpl req;
  -    static final boolean ACCT=false;// a smart compiler will remove all in/out
  +    OutputBuffer ob;
       
  -    public ServletWriterFacade( Writer w, Response resp ) {
  -	super( w );
  +    public ServletWriterFacade( OutputBuffer ob, Response resp ) {
  +	super( ob );
   	this.resA=resp;
  -	req=(RequestImpl)resA.getRequest();
  +	this.ob=ob;
       }
   
       // -------------------- Write methods --------------------
   
       public void flush() {
  -	if( ACCT ) in();
   	super.flush();
  -	if( ACCT ) out();
       }
   
       public void print( String str ) {
  -	if( ACCT ) in();
   	super.print( str );
  -	if( ACCT ) out(); 
      }
   
       public void println( String str ) {
  -	if( ACCT ) in();
   	super.println( str );
  -	if( ACCT ) out(); 
      }
   
       public void write( char buf[], int offset, int count ) {
  -	if( ACCT ) in();
   	super.write( buf, offset, count );
  -	if( ACCT ) out();
       }
   
       public void write( String str ) {
  -	if( ACCT ) in();
   	super.write( str );
  -	if( ACCT ) out();
  -    }
  -
  -    private void in() {
  -	req.setAccount( RequestImpl.ACC_IN_OUT, System.currentTimeMillis() );
  -    }
  -
  -    private void out() {
  -	long l=System.currentTimeMillis();
  -	long l1=req.getAccount( RequestImpl.ACC_IN_OUT);
  -	long l3=req.getAccount( RequestImpl.ACC_OUT_COUNT);
  -	req.setAccount( RequestImpl.ACC_OUT_COUNT, l - l1 + l3 );
       }
   
       /** Reuse the object instance, avoid GC
  
  
  
  1.17      +15 -12    jakarta-tomcat/src/share/org/apache/tomcat/request/AccessInterceptor.java
  
  Index: AccessInterceptor.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/AccessInterceptor.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- AccessInterceptor.java	2000/08/05 16:01:20	1.16
  +++ AccessInterceptor.java	2000/08/11 06:14:11	1.17
  @@ -329,6 +329,7 @@
   }
   
   class BasicAuthHandler extends Handler {
  +    int sbNote=0;
       
       BasicAuthHandler() {
   	initialized=true;
  @@ -349,22 +350,24 @@
   	// and notify the user they are not authorized if BasicAuth fails
           res.setContentType("text/html");        // ISO-8859-1 default  
   
  -        StringBuffer buf = new StringBuffer();
  +	if( sbNote==0 ) {
  +	    sbNote=req.getContextManager().getNoteId(ContextManager.REQUEST_NOTE,
  +						     "BasicAuthHandler.buff");
  +	}
  +
  +	// we can recycle it because
  +	// we don't call toString();
  +	StringBuffer buf=(StringBuffer)req.getNote( sbNote );
  +	if( buf==null ) {
  +	    buf = new StringBuffer();
  +	    req.setNote( sbNote, buf );
  +	}
    
           buf.append("<html><head><title>Not Authorized</title></head>");
           buf.append("<body>Not Authorized</body></html>");
  -        String body = buf.toString(); 
  +
           res.setContentLength(buf.length());
  - 
  -        if( res.isUsingStream() ) {
  -            ServletOutputStream out = res.getOutputStream(); 
  -            out.print(body);
  -            out.flush();   
  -        } else {
  -            PrintWriter out = res.getWriter();
  -            out.print(body);
  -            out.flush();
  -        }
  +	res.getBuffer().write( buf );
       }
   }
   
  
  
  
  1.17      +10 -1     jakarta-tomcat/src/share/org/apache/tomcat/request/SimpleMapper1.java
  
  Index: SimpleMapper1.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/SimpleMapper1.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- SimpleMapper1.java	2000/07/11 03:48:51	1.16
  +++ SimpleMapper1.java	2000/08/11 06:14:11	1.17
  @@ -255,7 +255,16 @@
   	    throw new RuntimeException("ASSERT: ? in requestURI");
   	
   	try {
  -	    String host=req.getServerName();
  +	    String host=null;
  +
  +// 	    MimeHeaders headers=req.getMimeHeaders();
  +// 	    MimeHeaderField hostH=headers.find("host");
  +	    
  +	    host=req.getServerName();
  +	    
  +// 	    if( hostH==null ) host=req.getLocalHost();
  +// 	    if(hostH==null) host="localhost";
  +	    
   	    if(debug>0) cm.log("Host = " + host);
   
   	    Container container =(Container)map.getLongestPrefixMatch(  host,
  
  
  
  1.12      +23 -27    jakarta-tomcat/src/share/org/apache/tomcat/request/StaticInterceptor.java
  
  Index: StaticInterceptor.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/StaticInterceptor.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- StaticInterceptor.java	2000/08/02 02:17:27	1.11
  +++ StaticInterceptor.java	2000/08/11 06:14:11	1.12
  @@ -270,24 +270,13 @@
   	try {
   	    in = new FileInputStream(file);
   
  -	    if( res.isUsingWriter() ) {
  -		InputStreamReader r = new InputStreamReader(in);
  -		PrintWriter out=res.getWriter();
  -		char[] buf = new char[1024];
  -		int read = 0;
  -		
  -		while ((read = r.read(buf)) != -1) {
  -		    out.write(buf, 0, read);
  -		}
  -	    } else {
  -		OutputStream out=res.getOutputStream();
  -		byte[] buf = new byte[1024];
  -		int read = 0;
  -		
  -		while ((read = in.read(buf)) != -1) {
  -		    out.write(buf, 0, read);
  -		}
  -	    } 
  +	    OutputBuffer out=res.getBuffer();
  +	    byte[] buf = new byte[1024];
  +	    int read = 0;
  +	    
  +	    while ((read = in.read(buf)) != -1) {
  +		out.write(buf, 0, read);
  +	    }
   	} catch (FileNotFoundException e) {
   	    // Figure out what we're serving
   	    context.getContextManager().handleStatus( req, res, 404);
  @@ -342,6 +331,7 @@
   class DirHandler extends Handler  {
       private static final String datePattern = "EEE, dd MMM yyyyy HH:mm z";
       int realFileNote;
  +    int sbNote=0;
       
       DirHandler() {
   	initialized=true;
  @@ -385,8 +375,19 @@
   		}
   	}
   
  -	StringBuffer buf = new StringBuffer();
  -	
  +		if( sbNote==0 ) {
  +	    sbNote=req.getContextManager().getNoteId(ContextManager.REQUEST_NOTE,
  +						     "RedirectHandler.buff");
  +	}
  +
  +	// we can recycle it because
  +	// we don't call toString();
  +	StringBuffer buf=(StringBuffer)req.getNote( sbNote );
  +	if( buf==null ) {
  +	    buf = new StringBuffer();
  +	    req.setNote( sbNote, buf );
  +	}
  +
   	if (! inInclude) {
   	    res.setContentType("text/html");
   	    buf.append("<html>\r\n");
  @@ -538,13 +539,8 @@
   	
   	if (! inInclude)  buf.append("</body></html>\r\n");
   
  -	if( res.isUsingWriter() ) {
  -	    PrintWriter out=res.getWriter();
  -	    out.print(buf);
  -	} else {
  -	    ServletOutputStream out=res.getOutputStream();
  -	    out.print(buf.toString());
  -	}
  +	res.getBuffer().write(buf);
  +	buf.setLength(0);
       }
   
       void displaySize( StringBuffer buf, int filesize ) {
  
  
  
  1.31      +30 -23    jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp12ConnectionHandler.java
  
  Index: Ajp12ConnectionHandler.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp12ConnectionHandler.java,v
  retrieving revision 1.30
  retrieving revision 1.31
  diff -u -r1.30 -r1.31
  --- Ajp12ConnectionHandler.java	2000/07/29 18:25:18	1.30
  +++ Ajp12ConnectionHandler.java	2000/08/11 06:14:13	1.31
  @@ -181,6 +181,12 @@
       boolean isPing=false;
       boolean doLog;
   
  +    // Debug only - use only to debug this component
  +    void d( String s ) {
  +	System.out.print("Ajp12RequestAdapter: ");
  +	System.out.println( s );
  +    }
  +    
       public int doRead() throws IOException {
   	return ajpin.read();
       }
  @@ -233,55 +239,55 @@
   		    // combination to hang with a 404!!!
   		    // if("ROOT".equals( contextPath ) ) contextPath="";
   		    if("ROOT".equalsIgnoreCase( contextPath ) ) contextPath=null;
  -		    if( doLog ) log("AJP: CP=" + contextPath);
  +		    if( doLog ) d("AJP: CP=" + contextPath);
   		    
   		    if( contextPath!= null )
   			context=contextM.getContext( contextPath );
  -		    if( doLog ) log("AJP: context=" + context );
  +		    if( doLog ) d("AJP: context=" + context );
   		    
   		    servletName = readString(ajpin, null);         //Servlet
  -		    if( doLog ) log("AJP: servlet=" + servletName );
  +		    if( doLog ) d("AJP: servlet=" + servletName );
   		    
   		    serverName = readString(ajpin, null);            //Server hostname
  -		    if( doLog ) log("AJP: serverName=" + serverName );
  +		    if( doLog ) d("AJP: serverName=" + serverName );
   		    
   		    dummy = readString(ajpin, null);               //Apache document root
   		    
   		    pathInfo = readString(ajpin, null);               //Apache parsed path-info
  -		    if( doLog ) log("AJP: PI=" + pathInfo );
  +		    if( doLog ) d("AJP: PI=" + pathInfo );
   		    
   		    // XXX Bug in mod_jserv !!!!!
   		    pathTranslated = readString(ajpin, null);               //Apache parsed path-translated
  -		    if( doLog ) log("AJP: PT=" + pathTranslated );
  +		    if( doLog ) d("AJP: PT=" + pathTranslated );
   		    
   		    queryString = readString(ajpin, null);         //query string
  -		    if( doLog ) log("AJP: QS=" + queryString );
  +		    if( doLog ) d("AJP: QS=" + queryString );
   		    
   		    remoteAddr = readString(ajpin, "");            //remote address
  -		    if( doLog ) log("AJP: RA=" + remoteAddr );
  +		    if( doLog ) d("AJP: RA=" + remoteAddr );
   		    
   		    remoteHost = readString(ajpin, "");            //remote host
  -		    if( doLog ) log("AJP: RH=" + remoteHost );
  +		    if( doLog ) d("AJP: RH=" + remoteHost );
   		    
   		    remoteUser = readString(ajpin, null);                 //remote user
  -		    if( doLog ) log("AJP: RU=" + remoteUser);
  +		    if( doLog ) d("AJP: RU=" + remoteUser);
   		    
   		    authType = readString(ajpin, null);                 //auth type
  -		    if( doLog ) log("AJP: AT=" + authType);
  +		    if( doLog ) d("AJP: AT=" + authType);
   		    
   		    dummy = readString(ajpin, null);                 //remote port
   		    
   		    method = readString(ajpin, null);                //request method
  -		    if( doLog ) log("AJP: Meth=" + method );
  +		    if( doLog ) d("AJP: Meth=" + method );
   		    
   		    requestURI = readString(ajpin, "");             //request uri
  -		    if( doLog ) log("AJP: URI: " + requestURI + " CP:" + contextPath + " LP: " + lookupPath);
  +		    if( doLog ) d("AJP: URI: " + requestURI + " CP:" + contextPath + " LP: " + lookupPath);
   
   		    // XXX don't set lookup path - problems with URL rewriting.
   		    // need to be fixed.
   		    //		if(contextPath!=null && contextPath.length() >0 )
   		    //		    lookupPath=requestURI.substring( contextPath.length() + 1 );
  -		    if( doLog ) log("AJP: URI: " + requestURI + " CP:" + contextPath + " LP: " + lookupPath);
  +		    if( doLog ) d("AJP: URI: " + requestURI + " CP:" + contextPath + " LP: " + lookupPath);
   		    
   		    dummy = readString(ajpin, null);                   //script filename
   		    //		System.out.println("AJP: Script filen=" + dummy);
  @@ -290,7 +296,7 @@
   		    //		System.out.println("AJP: Script name=" + dummy);
   
   		    serverName = readString(ajpin, "");                //server name
  -		    if( doLog ) log("AJP: serverName=" + serverName );
  +		    if( doLog ) d("AJP: serverName=" + serverName );
   		    try {
   			serverPort = Integer.parseInt(readString(ajpin, "80")); //server port
   		    } catch (Exception any) {
  @@ -307,7 +313,7 @@
   		    if(jvmRoute.length() == 0) {
   			jvmRoute = null;
   		    }
  -		    if( doLog ) log("AJP: Server jvmRoute=" + jvmRoute);
  +		    if( doLog ) d("AJP: Server jvmRoute=" + jvmRoute);
   
   
                       /**
  @@ -370,7 +376,7 @@
   			    socket.getOutputStream().write(0); // PING reply
   			    sin.close();
   			} catch (IOException ignored) {
  -			    log("Exception closing, ignored", ignored);
  +			    contextM.log("Exception closing, ignored",  ignored);
   			}
                           isPing = true;
                           return;
  @@ -394,7 +400,8 @@
   				return;
   			    }
   			} catch (Exception ignored) {
  -			    log("Ignored exception processing signal " + signal, ignored);
  +			    contextM.log("Ignored exception processing signal " +
  +			      signal, ignored);
   			}
   		    }
   		    return;
  @@ -417,21 +424,21 @@
   	} catch (IOException ioe) {
   	    throw ioe;
           } catch (Exception e) {
  -	    log("Uncaught exception handling request", e);
  +	    contextM.log("Uncaught exception handling request", e);
           }
   	
   	// REQUEST_URI includes query string
   	int indexQ=requestURI.indexOf("?");
   	int rLen=requestURI.length();
   	if ( (indexQ >-1) && ( indexQ  < rLen) ) {
  -	    if(doLog) log("Orig QS " + queryString );
  +	    if(doLog) d("Orig QS " + queryString );
   	    queryString = requestURI.substring(indexQ + 1, requestURI.length());
  -	    if(doLog) log("New QS " + queryString );
  +	    if(doLog) d("New QS " + queryString );
   	    requestURI = requestURI.substring(0, indexQ);
   	} 
   	
  -	if( doLog ) log("Request: " + requestURI );
  -	if( doLog ) log ("Query: " + queryString );
  +	if( doLog ) d("Request: " + requestURI );
  +	if( doLog ) d("Query: " + queryString );
   	// System.out.println("ENV: " + env_vars );
   	// 	System.out.println("HEADERS: " + headers_in );
   	// 	System.out.println("PARAMETERS: " + parameters );
  
  
  
  1.8       +4 -5      jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp13ConnectorRequest.java
  
  Index: Ajp13ConnectorRequest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp13ConnectorRequest.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- Ajp13ConnectorRequest.java	2000/07/29 18:44:01	1.7
  +++ Ajp13ConnectorRequest.java	2000/08/11 06:14:13	1.8
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp13ConnectorRequest.java,v 1.7 2000/07/29 18:44:01 costin Exp $
  - * $Revision: 1.7 $
  - * $Date: 2000/07/29 18:44:01 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp13ConnectorRequest.java,v 1.8 2000/08/11 06:14:13 costin Exp $
  + * $Revision: 1.8 $
  + * $Date: 2000/08/11 06:14:13 $
    *
    * ====================================================================
    *
  @@ -179,7 +179,7 @@
                   break;
   
                   case SC_A_SERVLET_PATH :
  -                    log("SC_A_SERVLET_PATH not in use " + msg.getString());
  +                    //log("SC_A_SERVLET_PATH not in use " + msg.getString());
                   break;
   
                   case SC_A_REMOTE_USER  :
  @@ -261,7 +261,6 @@
           for(int i = off ; i < (len + off) ; i++) {
               int a = doRead();
               if(-1 == a) {
  -                log("Y");
                   return i-off;
               }
               b[i] = (byte)a;
  
  
  
  1.12      +5 -5      jakarta-tomcat/src/share/org/apache/tomcat/service/connector/JNIConnectionHandler.java
  
  Index: JNIConnectionHandler.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/JNIConnectionHandler.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- JNIConnectionHandler.java	2000/07/29 18:44:01	1.11
  +++ JNIConnectionHandler.java	2000/08/11 06:14:13	1.12
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/JNIConnectionHandler.java,v 1.11 2000/07/29 18:44:01 costin Exp $
  - * $Revision: 1.11 $
  - * $Date: 2000/07/29 18:44:01 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/JNIConnectionHandler.java,v 1.12 2000/08/11 06:14:13 costin Exp $
  + * $Revision: 1.12 $
  + * $Date: 2000/08/11 06:14:13 $
    *
    * ====================================================================
    *
  @@ -264,11 +264,11 @@
               serverPort  = Integer.parseInt(env[6]);
               authType    = env[7];
               remoteUser  = env[8];
  -            scheme      = env[9];
  +            schemeMB.setString(env[9]);
               protocol    = env[10];
               // response.setServerHeader(env[11]);
               
  -            if(scheme.equalsIgnoreCase("https")) {
  +            if(schemeMB.equalsIgnoreCase("https")) {
                   if(null != env[12]) {
   		            attributes.put("javax.servlet.request.X509Certificate",
   	                               env[12]);
  
  
  
  1.22      +43 -15    jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpRequestAdapter.java
  
  Index: HttpRequestAdapter.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpRequestAdapter.java,v
  retrieving revision 1.21
  retrieving revision 1.22
  diff -u -r1.21 -r1.22
  --- HttpRequestAdapter.java	2000/07/29 18:44:03	1.21
  +++ HttpRequestAdapter.java	2000/08/11 06:14:15	1.22
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpRequestAdapter.java,v 1.21 2000/07/29 18:44:03 costin Exp $
  - * $Revision: 1.21 $
  - * $Date: 2000/07/29 18:44:03 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpRequestAdapter.java,v 1.22 2000/08/11 06:14:15 costin Exp $
  + * $Revision: 1.22 $
  + * $Date: 2000/08/11 06:14:15 $
    *
    * ====================================================================
    *
  @@ -344,6 +344,7 @@
   	return -1;
       }
   
  +    
       private void processRequestLine(Response response)
   	throws IOException
       {
  @@ -372,34 +373,61 @@
   	    response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
   	    return;
   	}
  -	
  -	method= new String( buf, startMethod, endMethod - startMethod );
   
  +	methodMB.setBytes( buf, startMethod, endMethod - startMethod );
  +	method=null;
  +	if( Ascii.toLower( buf[startMethod]) == 'g' ) {
  +	    if( methodMB.equalsIgnoreCase( "get" ))
  +		method="GET";
  +	}
  +	if( Ascii.toLower( buf[startMethod]) == 'p' ) {
  +	    if( methodMB.equalsIgnoreCase( "post" ))
  +		method="POST";
  +	    if( methodMB.equalsIgnoreCase( "put" ))
  +		method="PUT";
  +	}
  +
  +	if( method==null )
  +	    method= new String( buf, startMethod, endMethod - startMethod );
  +
  +	protocol=null;
   	if( endReq < 0 ) {
  -	    protocol=null;
   	    endReq=count;
   	} else {
   	    if( endProto < 0 ) endProto = count;
  -	    protocol=new String( buf, startProto, endProto-startProto );
  +	    protoMB.setBytes( buf, startProto, endProto-startProto);
  +	    if( protoMB.equalsIgnoreCase( "http/1.0" ))
  +		protocol="HTTP/1.0";
  +	    if( protoMB.equalsIgnoreCase( "http/1.1" ))
  +		protocol="HTTP/1.1";
  +	    
  +	    if( protocol==null) 
  +		protocol=new String( buf, startProto, endProto-startProto );
   	}
   
   	int qryIdx= findChar( '?', startReq, endReq );
   	if( qryIdx <0 ) {
  -	    requestURI = new String( buf, startReq, endReq - startReq );
  +	    uriMB.setBytes(buf, startReq, endReq - startReq );
  +	    //= new String( buf, startReq, endReq - startReq );
   	} else {
  -	    requestURI = new String( buf, startReq, qryIdx - startReq );
  -	    queryString = new String( buf, qryIdx+1, endReq - qryIdx -1 );
  +	    uriMB.setBytes( buf, startReq, qryIdx - startReq );
  +	    queryMB.setBytes( buf, qryIdx+1, endReq - qryIdx -1 );
   	}
   
  +	// temp. fix until the rest of the code is changed
  +	requestURI=uriMB.toString();
  +	queryString=queryMB.toString();
  +
   	// Perform URL decoding only if necessary
  -	if ((requestURI != null) &&
  -	    ((requestURI.indexOf('%') >= 0) || (requestURI.indexOf('+') >= 0))) {
  +	if ((uriMB.indexOf('%') >= 0) || (uriMB.indexOf('+') >= 0)) {
   
   	    try {
  -		    requestURI = RequestUtil.URLDecode(requestURI);
  +		// XXX rewrite URLDecode to avoid allocation
  +		requestURI = uriMB.toString();
  +		requestURI = RequestUtil.URLDecode(requestURI);
   	    } catch (Exception e) {
  -		    response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
  -		    return;
  +		response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
  +		return;
   	    }
   	}
   
  
  
  
  1.14      +7 -3      jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpResponseAdapter.java
  
  Index: HttpResponseAdapter.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpResponseAdapter.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- HttpResponseAdapter.java	2000/07/31 02:35:16	1.13
  +++ HttpResponseAdapter.java	2000/08/11 06:14:15	1.14
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpResponseAdapter.java,v 1.13 2000/07/31 02:35:16 costin Exp $
  - * $Revision: 1.13 $
  - * $Date: 2000/07/31 02:35:16 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpResponseAdapter.java,v 1.14 2000/08/11 06:14:15 costin Exp $
  + * $Revision: 1.14 $
  + * $Date: 2000/08/11 06:14:15 $
    *
    * ====================================================================
    *
  @@ -134,6 +134,10 @@
   	printHead("HTTP/1.0 ");
   	switch( status ) {
   	case 200: printHead("200");
  +	    break;
  +	case 400: printHead("400");
  +	    break;
  +	case 404: printHead("404");
   	    break;
   	    
   	default:
  
  
  
  1.3       +11 -3     jakarta-tomcat/src/share/org/apache/tomcat/util/ArrayEnumerator.java
  
  Index: ArrayEnumerator.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/ArrayEnumerator.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ArrayEnumerator.java	2000/06/16 17:59:10	1.2
  +++ ArrayEnumerator.java	2000/08/11 06:14:18	1.3
  @@ -70,24 +70,32 @@
   
       Object array[];
       int pos;
  +    int end;
       
       public ArrayEnumerator( Object array[] ) {
   	this.array=array;
   	pos=0;
  +	end=array.length;
       }
  +
  +    public ArrayEnumerator( Object array[], int start, int end ) {
  +	this.array=array;
  +	pos=start;
  +	this.end=end;
  +    }
       
       public Object nextElement( ) {
   	synchronized( array ) {
  -	    if( pos < array.length )
  +	    if( pos < end )
   		return array[ pos ++ ];
   	}
   	throw new NoSuchElementException( "No more elements: " +
  -					  pos + " / " + array.length);
  +					  pos + " / " + end);
   	
       }
   
       public boolean hasMoreElements() {
  -	return pos < array.length;
  +	return pos < end;
       }
       
   }
  
  
  
  1.5       +24 -40    jakarta-tomcat/src/share/org/apache/tomcat/util/Ascii.java
  
  Index: Ascii.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/Ascii.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- Ascii.java	2000/05/24 18:57:10	1.4
  +++ Ascii.java	2000/08/11 06:14:18	1.5
  @@ -1,8 +1,4 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/Ascii.java,v 1.4 2000/05/24 18:57:10 costin Exp $
  - * $Revision: 1.4 $
  - * $Date: 2000/05/24 18:57:10 $
  - *
    * ====================================================================
    *
    * The Apache Software License, Version 1.1
  @@ -61,7 +57,6 @@
    *
    */ 
   
  -
   package org.apache.tomcat.util;
   
   /**
  @@ -70,10 +65,7 @@
    * @author dac@eng.sun.com
    * @author James Todd [gonzo@eng.sun.com]
    */
  -
  -public class Ascii {
  -    static StringManager sm =
  -	StringManager.getManager("org.apache.tomcat.util");
  +public final class Ascii {
       /*
        * Character translation tables.
        */
  @@ -187,26 +179,20 @@
        * @param len the length of the bytes
        * @exception NumberFormatException if the integer format was invalid
        */
  -
       public static int parseInt(byte[] b, int off, int len)
   	throws NumberFormatException
       {
           int c;
   
   	if (b == null || len <= 0 || !isDigit(c = b[off++])) {
  -            String msg = sm.getString("ascii.parseInit.nfe", b);
  -	    throw new NumberFormatException(msg);
  +	    throw new NumberFormatException();
   	}
   
   	int n = c - '0';
   
   	while (--len > 0) {
   	    if (!isDigit(c = b[off++])) {
  -                StringManager sm =
  -                    StringManager.getManager("org.apache.tomcat.util");
  -                String msg = sm.getString("ascii.parseInit.nfe", b);
  -
  -		throw new NumberFormatException(msg);
  +		throw new NumberFormatException();
   	    }
   	    n = n * 10 + c - '0';
   	}
  @@ -214,31 +200,29 @@
   	return n;
       }
   
  -    /**
  -     * Compares this message string to the specified subarray of bytes.
  -     * Case is ignored in the comparison.
  -     * @param b the bytes to compare
  -     * @param off the start offset of the bytes
  -     * @param len the length of the bytes
  -     * @return true if the comparison succeeded, false otherwise
  -     */
  -    public static boolean equalsIgnoreCase(String str, MessageBytes mB ) {
  -	byte[] b=mB.getBytes();
  -	int off=mB.getOffset();
  -	int len=mB.getLength();
  -	if (str != null) {
  -	    String s = str;
  -	    if (len != s.length()) {
  -		return false;
  -	    }
  -	    for (int i = 0; i < len; i++) {
  -		if (Ascii.toLower(b[off++]) != Ascii.toLower(s.charAt(i))) {
  -		    return false;
  -		}
  +    public static int parseInt(char[] b, int off, int len)
  +	throws NumberFormatException
  +    {
  +        int c;
  +
  +	if (b == null || len <= 0 || !isDigit(c = b[off++])) {
  +	    throw new NumberFormatException();
  +	}
  +
  +	int n = c - '0';
  +
  +	while (--len > 0) {
  +	    if (!isDigit(c = b[off++])) {
  +		throw new NumberFormatException();
   	    }
  -	    return true;
  +	    n = n * 10 + c - '0';
   	}
  -	return false;
  +
  +	return n;
  +    }
  +
  +    public static boolean equalsIgnoreCase(String str, MessageBytes mB ) {
  +	return mB.equalsIgnoreCase( str );
       }
   
   
  
  
  
  1.4       +3 -6      jakarta-tomcat/src/share/org/apache/tomcat/util/DateTool.java
  
  Index: DateTool.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/DateTool.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- DateTool.java	2000/07/11 03:28:30	1.3
  +++ DateTool.java	2000/08/11 06:14:18	1.4
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/DateTool.java,v 1.3 2000/07/11 03:28:30 alex Exp $
  - * $Revision: 1.3 $
  - * $Date: 2000/07/11 03:28:30 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/DateTool.java,v 1.4 2000/08/11 06:14:18 costin Exp $
  + * $Revision: 1.4 $
  + * $Date: 2000/08/11 06:14:18 $
    *
    * ====================================================================
    *
  @@ -79,9 +79,6 @@
    * @author Costin Manolache
    */
   public class DateTool {
  -
  -    private static StringManager sm =
  -        StringManager.getManager("org.apache.tomcat.util");
   
       /** US locale - all HTTP dates are in english
        */
  
  
  
  1.6       +396 -159  jakarta-tomcat/src/share/org/apache/tomcat/util/MessageBytes.java
  
  Index: MessageBytes.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/MessageBytes.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- MessageBytes.java	2000/05/24 18:57:10	1.5
  +++ MessageBytes.java	2000/08/11 06:14:19	1.6
  @@ -1,8 +1,4 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/MessageBytes.java,v 1.5 2000/05/24 18:57:10 costin Exp $
  - * $Revision: 1.5 $
  - * $Date: 2000/05/24 18:57:10 $
  - *
    * ====================================================================
    *
    * The Apache Software License, Version 1.1
  @@ -61,62 +57,91 @@
    *
    */ 
   
  -
   package org.apache.tomcat.util;
   
  -import java.io.OutputStream;
  -import java.io.IOException;
  -import org.apache.tomcat.core.Constants;
  +import java.text.*;
  +import java.util.*;
   
   /**
    * This class is used to represent a subarray of bytes in an HTTP message.
    *
    * @author dac@eng.sun.com
    * @author James Todd [gonzo@eng.sun.com]
  + * @author Costin Manolache
    */
  -public class MessageBytes {
  -
  -    private StringManager sm =
  -        StringManager.getManager("org.apache.tomcat.util");
  -
  -    /**
  -     * The message bytes.
  -     */
  -    protected byte[] bytes;
  -
  -    /**
  -     * The start offset of the bytes.
  -     */
  -    protected int offset;
  -
  +public final class MessageBytes implements Cloneable {
  +    public static final String DEFAULT_CHAR_ENCODING="8859_1";
  +    
  +    // primary type ( whatever is set as original value )
  +    private int type = T_NULL;
  +    
  +    public static final int T_NULL = 0;
  +    public static final int T_STR  = 1;
  +    public static final int T_BYTES = 2;
  +    public static final int T_CHARS = 3;
  +
  +    private int hashCode=0;
  +    private boolean hasHashCode=false;
  +
  +    private boolean caseSensitive=true;
  +    
  +    // byte[]
  +    private byte[] bytes;
  +    private int bytesOff;
  +    private int bytesLen;
  +    private String enc;
  +    private boolean hasByteValue=false;
  +    
  +    // Caching the result of a conversion
  +
  +    // char[]
  +    private char chars[];
  +    private int charsOff;
  +    private int charsLen;
  +    private boolean hasCharValue=false;
  +    
  +    // String
  +    private String strValue;
  +    private boolean hasStrValue=false;
  +    
       /**
  -     * The length of the bytes.
  -     */
  -    protected int length;
  -
  -    /**
        * Creates a new, uninitialized MessageBytes object.
        */
       public MessageBytes() {
       }
   
  -    /**
  -     * Creates a new MessageBytes object with the specified bytes.
  -     * @param b the bytes
  -     * @param off the start offset of the bytes
  -     * @param len the length of the bytes
  -     */
  -    public MessageBytes(byte[] b, int off, int len) {
  -	setBytes(b, off, len);
  +    public void setCaseSenitive( boolean b ) {
  +	caseSensitive=b;
       }
   
  +    public MessageBytes getClone() {
  +	try {
  +	    return (MessageBytes)this.clone();
  +	} catch( Exception ex) {
  +	    return null;
  +	}
  +    }
  +
  +    public void reset() {
  +	recycle();
  +    }
       /**
        * Resets the message bytes to an uninitialized state.
        */
  -    public void reset() {
  +    public void recycle() {
   	bytes = null;
  +	strValue=null;
  +	//	chars=null;
  +	caseSensitive=true;
  +
  +	enc=null;
  +	hasByteValue=false;
  +	hasStrValue=false;
  +	hasCharValue=false;
  +	hasHashCode=false;
       }
   
  +
       /**
        * Sets the message bytes to the specified subarray of bytes.
        * @param b the ascii bytes
  @@ -125,10 +150,78 @@
        */
       public void setBytes(byte[] b, int off, int len) {
   	bytes = b;
  -	offset = off;
  -	length = len;
  +	bytesOff = off;
  +	bytesLen = len;
  +	type=T_BYTES;
  +	hasByteValue=true;
  +    }
  +
  +    public void setEncoding( String enc ) {
  +	this.enc=enc;
  +    }
  +    
  +    public void setChars( char[] c, int off, int len ) {
  +	chars=c;
  +	charsOff=off;
  +	charsLen=len;
  +	type=T_CHARS;
  +	hasCharValue=true;
  +    }
  +
  +    public void setString( String s ) {
  +	strValue=s;
  +	hasStrValue=true;
  +	type=T_STR;
       }
   
  +    // -------------------- Conversion and getters --------------------
  +    public String toString() {
  +	if( hasStrValue ) return strValue;
  +	
  +	switch (type) {
  +	case T_CHARS:
  +	    strValue=new String( chars, charsOff, charsLen);
  +	    hasStrValue=true;
  +	    return strValue;
  +	case T_BYTES:
  +	    try {
  +		if( enc==null )
  +		    strValue=toStringUTF8();
  +		else
  +		    strValue=new String(bytes, bytesOff, bytesLen, enc);
  +		hasStrValue=true;
  +		return strValue;
  +	    } catch (java.io.UnsupportedEncodingException e) {
  +		return null;  // can't happen
  +	    }
  +	default:
  +	    return null;
  +	}
  +    }
  +
  +    private String toStringUTF8() {
  +        if (null == bytes) {
  +            return null;
  +        }
  +	if( chars==null || bytesLen > chars.length ) {
  +	    chars=new char[bytesLen];
  +	}
  +
  +	int j=bytesOff;
  +	for( int i=0; i< bytesLen; i++ ) {
  +	    chars[i]=(char)bytes[j++];
  +	}
  +	charsLen=bytesLen;
  +	charsOff=0;
  +	hasCharValue=true;
  +	return new String( chars, 0, bytesLen);
  +    }
  +
  +    //----------------------------------------
  +    public int getType() {
  +	return type;
  +    }
  +    
       /**
        * Returns the message bytes.
        */
  @@ -137,181 +230,325 @@
       }
   
       /**
  -     * Puts the message bytes in buf starting at buf_offset.
  -     * @return the number of bytes added to buf.
  -     */
  -    public int getBytes(byte buf[],
  -			int buf_offset) 
  -    {
  -	if (bytes != null) 
  -	    System.arraycopy(bytes, offset, buf, buf_offset, length);
  -	return length;
  -    }
  -
  -    /**
        * Returns the start offset of the bytes.
        */
       public int getOffset() {
  -	return offset;
  +	if(type==T_BYTES)
  +	    return bytesOff;
  +	if(type==T_CHARS)
  +	    return charsOff;
  +	return 0;
       }
   
       /**
        * Returns the length of the bytes.
        */
       public int getLength() {
  -	return length;
  +	if(type==T_BYTES)
  +	    return bytesLen;
  +	if(type==T_CHARS)
  +	    return charsLen;
  +	if(type==T_STR)
  +	    return strValue.length();
  +	return 0;
       }
   
  -    /**
  -     * Returns true if the message bytes have been set.
  -     */
  -    public boolean isSet() {
  -	return bytes != null;
  -    }
  +    // -------------------- equals --------------------
   
       /**
  -     * Returns the message bytes parsed as an unsigned integer.
  -     * @exception NumberFormatException if the integer format was invalid
  -     */
  -    public int toInteger() throws NumberFormatException {
  -	return Ascii.parseInt(bytes, offset, length);
  -    }
  -
  -    /**
  -     * Compares the message bytes to the specified subarray of bytes.
  -     * @param b the bytes to compare
  -     * @param off the start offset of the bytes
  -     * @param len the length of the bytes
  +     * Compares the message bytes to the specified String object.
  +     * @param s the String to compare
        * @return true if the comparison succeeded, false otherwise
        */
  -    public boolean equals(byte[] b, int off, int len) {
  -	byte[] b1 = bytes;
  -	if (b1 == null || len != length) {
  -	    return false;
  -	}
  -	int off1 = offset;
  -	while (len-- > 0) {
  -	    if (b[off++] != b1[off1++]) {
  +    public boolean equals(String s) {
  +	if( ! caseSensitive )
  +	    return equalsIgnoreCase( s );
  +	switch (type) {
  +	case T_STR:
  +	    return strValue.equals( s );
  +	case T_CHARS:
  +	    char[] c = chars;
  +	    int len = charsLen;
  +	    if (c == null || len != s.length()) {
  +		return false;
  +	    }
  +	    int off = charsOff;
  +	    for (int i = 0; i < len; i++) {
  +		if (c[off++] != s.charAt(i)) {
  +		    return false;
  +		}
  +	    }
  +	    return true;
  +	case T_BYTES:
  +	    byte[] b = bytes;
  +	    int blen = bytesLen;
  +	    if (b == null || blen != s.length()) {
   		return false;
   	    }
  +	    int boff = bytesOff;
  +	    for (int i = 0; i < blen; i++) {
  +		if (b[boff++] != s.charAt(i)) {
  +		    return false;
  +		}
  +	    }
  +	    return true;
  +	default:
  +	    return false;
   	}
  -	return true;
       }
   
       /**
  -     * Compares the message bytes to the specified subarray of bytes.
  -     * Case is ignored in the comparison.
  -     * @param b the bytes to compare
  -     * @param off the start offset of the bytes
  -     * @param len the length of the bytes
  +     * Compares the message bytes to the specified String object.
  +     * @param s the String to compare
        * @return true if the comparison succeeded, false otherwise
        */
  -    public boolean equalsIgnoreCase(byte[] b, int off, int len) {
  -	byte[] b1 = bytes;
  -	if (b1 == null || len != length) {
  -	    return false;
  -	}
  -	int off1 = offset;
  -	while (len-- > 0) {
  -	    if (Ascii.toLower(b[off++]) != Ascii.toLower(b1[off1++])) {
  +    public boolean equalsIgnoreCase(String s) {
  +	switch (type) {
  +	case T_STR:
  +	    return strValue.equalsIgnoreCase( s );
  +	case T_CHARS:
  +	    char[] c = chars;
  +	    int len = charsLen;
  +	    if (c == null || len != s.length()) {
   		return false;
   	    }
  +	    int off = charsOff;
  +	    for (int i = 0; i < len; i++) {
  +		if (Ascii.toLower( c[off++] ) != Ascii.toLower( s.charAt(i))) {
  +		    return false;
  +		}
  +	    }
  +	    return true;
  +	case T_BYTES:
  +	    byte[] b = bytes;
  +	    int blen = bytesLen;
  +	    if (b == null || blen != s.length()) {
  +		return false;
  +	    }
  +	    int boff = bytesOff;
  +	    for (int i = 0; i < blen; i++) {
  +		if (Ascii.toLower(b[boff++]) != Ascii.toLower(s.charAt(i))) {
  +		    return false;
  +		}
  +	    }
  +	    return true;
  +	default:
  +	    return false;
   	}
  -	return true;
       }
   
  -    /**
  -     * Writes the message bytes to the specified output stream.
  -     * @param out the output stream
  -     * @exception IOException if an I/O error has occurred
  -     */
  -    public void write(OutputStream out) throws IOException {
  -	if (bytes != null) {
  -	    out.write(bytes, offset, length);
  +    public boolean equals(MessageBytes mb) {
  +	switch (type) {
  +	case T_STR:
  +	    return mb.equals( strValue );
   	}
  -    }
   
  -    /**
  -     * Returns the length of the message bytes.
  -     */
  -    public int length() {
  -	return bytes != null ? length : 0;
  -    }
  +	if( mb.type != T_CHARS && mb.type!= T_BYTES ) {
  +	    // it's a string or int/date string value
  +	    return equals( mb.toString() );
  +	}
   
  -    // --------------------
  -    /**
  -     * Returns the message bytes as a String object.
  -     */
  -    public String toString() {
  -        if (null == bytes) {
  -            return null;
  -        }
  +	if( mb.type == T_CHARS && type==T_CHARS ) {
  +	    char b1[]=chars;
  +	    char b2[]=mb.chars;
  +	    if (b1== null || b2==null || mb.charsLen != charsLen) {
  +		return false;
  +	    }
  +	    int off1 = charsOff;
  +	    int off2 = mb.charsOff;
  +	    int len=charsLen;
  +	    while ( len-- > 0) {
  +		if (b1[off1++] != b2[off2++]) {
  +		    return false;
  +		}
  +	    }
  +	    return true;
  +	}
  +	if( mb.type==T_BYTES && type== T_BYTES ) {
  +	    byte b1[]=bytes;
  +	    byte b2[]=mb.bytes;
  +	    if (b1== null || b2==null || mb.bytesLen != bytesLen) {
  +		return false;
  +	    }
  +	    int off1 = bytesOff;
  +	    int off2 = mb.bytesOff;
  +	    int len=bytesLen;
  +	    while ( len-- > 0) {
  +		if (b1[off1++] != b2[off2++]) {
  +		    return false;
  +		}
  +	    }
  +	    return true;
  +	}
   
  -        try {
  -            return new String(bytes, offset, length, Constants.DEFAULT_CHAR_ENCODING);
  -        } catch (java.io.UnsupportedEncodingException e) {
  -            return null;        // could return something - but why?
  -        }
  -    }
  +	// char/byte or byte/char
  +	MessageBytes mbB=this;
  +	MessageBytes mbC=mb;
  +	
  +	if( type == T_CHARS && mb.type==T_BYTES  ) {
  +	    mbB=mb;
  +	    mbC=this;
  +	}
   
  -    /**
  -     * Compares the message bytes to the specified String object.
  -     * @param s the String to compare
  -     * @return true if the comparison succeeded, false otherwise
  -     */
  -    public boolean equals(String s) {
  -	byte[] b = bytes;
  -	int len = length;
  -	if (b == null || len != s.length()) {
  +	byte b1[]=mbB.bytes;
  +	char b2[]=mbC.chars;
  +	if (b1== null || b2==null || mbB.bytesLen != mbC.charsLen) {
   	    return false;
   	}
  -	int off = offset;
  -	for (int i = 0; i < len; i++) {
  -	    if (b[off++] != s.charAt(i)) {
  +	int off1 = mbB.bytesOff;
  +	int off2 = mbC.charsOff;
  +	int len=mbB.bytesLen;
  +	
  +	while ( len-- > 0) {
  +	    if ( (char)b1[off1++] != b2[off2++]) {
   		return false;
   	    }
   	}
   	return true;
       }
   
  +    
       /**
  -     * Compares the message bytes to the specified String object. Case is
  -     * ignored in the comparison.
  -     * @param s the String to compare
  -     * @return true if the comparison succeeded, false otherwise
  +     * Returns true if the message bytes starts with the specified string.
  +     * @param s the string
        */
  -    public boolean equalsIgnoreCase(String s) {
  -	byte[] b = bytes;
  -	int len = length;
  -	if (b == null || len != s.length()) {
  +    public boolean startsWith(String s) {
  +	switch (type) {
  +	case T_STR:
  +	    return strValue.startsWith( s );
  +	case T_CHARS:
  +	    char[] c = chars;
  +	    int len = s.length();
  +	    if (c == null || len > charsLen) {
  +		return false;
  +	    }
  +	    int off = charsOff;
  +	    for (int i = 0; i < len; i++) {
  +		if (c[off++] != s.charAt(i)) {
  +		    return false;
  +		}
  +	    }
  +	    return true;
  +	case T_BYTES:
  +	    byte[] b = bytes;
  +	    int blen = s.length();
  +	    if (b == null || blen > bytesLen) {
  +		return false;
  +	    }
  +	    int boff = bytesOff;
  +	    for (int i = 0; i < blen; i++) {
  +		if (b[boff++] != s.charAt(i)) {
  +		    return false;
  +		}
  +	    }
  +	    return true;
  +	default:
   	    return false;
   	}
  -	int off = offset;
  -	for (int i = 0; i < len; i++) {
  -	    if (Ascii.toLower(b[off++]) != Ascii.toLower((byte)s.charAt(i))) {
  -		return false;
  +    }
  +
  +    
  +
  +    // -------------------- Hash code  --------------------
  +    public  int hashCode() {
  +	if( hasHashCode ) return hashCode;
  +	int code = 0;
  +
  +	if( caseSensitive ) 
  +	    code=hash(); 
  +	else
  +	    code=hashIgnoreCase();
  +	hashCode=code;
  +	hasHashCode=true;
  +	return code;
  +    }
  +
  +    // normal hash. 
  +    private int hash() {
  +	int code=0;
  +	switch (type) {
  +	case T_STR:
  +	    for (int i = 0; i < strValue.length(); i++) {
  +		code = code * 37 + strValue.charAt( i );
   	    }
  +	    return code;
  +	case T_CHARS:
  +	    for (int i = charsOff; i < charsOff + charsLen; i++) {
  +		code = code * 37 + chars[i];
  +	    }
  +	    return code;
  +	case T_BYTES:
  +	    return hashBytes( bytes, bytesOff, bytesLen);
  +	default:
  +	    return 0;
   	}
  -	return true;
       }
   
  +    // hash ignoring case
  +    private int hashIgnoreCase() {
  +	int code=0;
  +	switch (type) {
  +	case T_STR:
  +	    for (int i = 0; i < strValue.length(); i++) {
  +		code = code * 37 + Ascii.toLower(strValue.charAt( i ));
  +	    }
  +	    return code;
  +	case T_CHARS:
  +	    for (int i = charsOff; i < charsOff + charsLen; i++) {
  +		code = code * 37 + Ascii.toLower(chars[i]);
  +	    }
  +	    return code;
  +	case T_BYTES:
  +	    return hashBytesIC( bytes, bytesOff, bytesLen );
  +	default:
  +	    return 0;
  +	}
  +    }
  +
  +    private static int hashBytes( byte bytes[], int bytesOff, int bytesLen ) {
  +	int max=bytesOff+bytesLen;
  +	byte bb[]=bytes;
  +	int code=0;
  +	for (int i = bytesOff; i < max ; i++) {
  +	    code = code * 37 + bb[i];
  +	}
  +	return code;
  +    }
  +
  +    private static int hashBytesIC( byte bytes[], int bytesOff, int bytesLen ) {
  +	int max=bytesOff+bytesLen;
  +	byte bb[]=bytes;
  +	int code=0;
  +	for (int i = bytesOff; i < max ; i++) {
  +	    code = code * 37 + Ascii.toLower(bb[i]);
  +	}
  +	return code;
  +    }
  +
       /**
        * Returns true if the message bytes starts with the specified string.
        * @param s the string
        */
  -    public boolean startsWith(String s) {
  -	byte[] b = bytes;
  -	int len = s.length();
  -	if (b == null || len > length) {
  -	    return false;
  -	}
  -	int off = offset;
  -	for (int i = 0; i < len; i++) {
  -	    if (b[off++] != s.charAt(i)) {
  -		return false;
  +    public int indexOf(char c) {
  +	switch (type) {
  +	case T_STR:
  +	    return strValue.indexOf( c );
  +	case T_CHARS:
  +	    for (int i = charsOff; i < charsOff + charsLen; i++) {
  +		if( c == chars[i] ) return i;
  +	    }
  +	    return -1;
  +	case T_BYTES:
  +	    int max=bytesOff+bytesLen;
  +	    byte bb[]=bytes;
  +	    for (int i = bytesOff; i < max ; i++) {
  +		if( (byte)c == bb[i]) return i;
   	    }
  +	    return -1;
  +	default:
  +	    return -1;
   	}
  -	return true;
       }
  +
   
   }
  
  
  
  1.11      +8 -5      jakarta-tomcat/src/share/org/apache/tomcat/util/MimeHeaderField.java
  
  Index: MimeHeaderField.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/MimeHeaderField.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- MimeHeaderField.java	2000/06/23 02:16:29	1.10
  +++ MimeHeaderField.java	2000/08/11 06:14:19	1.11
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/MimeHeaderField.java,v 1.10 2000/06/23 02:16:29 costin Exp $
  - * $Revision: 1.10 $
  - * $Date: 2000/06/23 02:16:29 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/MimeHeaderField.java,v 1.11 2000/08/11 06:14:19 costin Exp $
  + * $Revision: 1.11 $
  + * $Date: 2000/08/11 06:14:19 $
    *
    * ====================================================================
    *
  @@ -291,7 +291,10 @@
   	case T_CHARS:
   	    return valueC.toInteger();
   	case T_BYTES:
  -	    return valueB.toInteger();
  +	    if(valueB.getType() == MessageBytes.T_BYTES )
  +		return Ascii.parseInt(valueB.getBytes(), valueB.getOffset(),
  +				      valueB.getLength());
  +	    return  Integer.parseInt(valueB.toString());
   	default:
               String msg = sm.getString("mimeHeaderField.int.nfe");
   
  @@ -370,7 +373,7 @@
   	case T_CHARS:
   	    return nameC.equalsIgnoreCase(s);
   	case T_BYTES:
  -	    return Ascii.equalsIgnoreCase( s, nameB );
  +	    return nameB.equalsIgnoreCase( s );
   	default:
   	    return false;
   	}