tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cos...@locus.apache.org
Subject cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/util RecycleBufferedInputStream.java BuffTool.java ByteBuffer.java RequestUtil.java
Date Tue, 30 May 2000 06:16:56 GMT
costin      00/05/29 23:16:55

  Modified:    src/share/org/apache/tomcat/core
                        BufferedServletOutputStream.java
                        ContextManager.java Request.java RequestImpl.java
                        Response.java ResponseImpl.java
               src/share/org/apache/tomcat/facade
                        HttpServletRequestFacade.java
                        HttpServletResponseFacade.java
                        ServletOutputStreamFacade.java
                        ServletWriterFacade.java
               src/share/org/apache/tomcat/service PoolTcpEndpoint.java
               src/share/org/apache/tomcat/service/connector
                        Ajp13ConnectorResponse.java
               src/share/org/apache/tomcat/service/http
                        HttpRequestAdapter.java
               src/share/org/apache/tomcat/util BuffTool.java
                        ByteBuffer.java RequestUtil.java
  Added:       src/share/org/apache/tomcat/adapter AdapterHandler.java
                        HttpAdapter.java
               src/share/org/apache/tomcat/util
                        RecycleBufferedInputStream.java
  Log:
  I was offline - many changes, but most of them are
  just moving some code and small evolutionary changes..
  
  Everything that worked before should still work, I just
  added few more methods and hooks, preparing for 2 bigger
  changes.
  
  - added support for explicit in/out buffers using ByteBuffer.
  The only change in core is adding the property to Request/Response.
  
  This will be very important for:
    - performance - we can minimize and control the flow, probably
  save 2-3 copies.
    - character encoding - this is the first step in allowing
  modules to control the byte<->char and fix the wrong code
  that assumes ascii ( that also means javax.servlet, but we
  can override the methods ).
    - performance - enable faster character encoders
    - protocol adapters - all existing adapters implement only
  the read/write operations.
  
  - added hooks for buffer - if a buffer is present, it will be used
  instead of BufferedServletInput/Output stream.
  
  - the code in buffer is the same as in BufferedOutputStream.
  BufferedInputStream was just a stub, added the buffering
  ( a bit better, not complete yet )
  
  - started moving the adapters to the new model ( event callbacks
  instead of extending request/response). The old model still works,
  but I think we should deprecate it soon.
  
  - Ajp13ConnectorResponse: no longer extend BufferedOS, just
  override write. It's a first step in moving to ByteBuffer.
  
  - added various utils to BuffTool - scan a byte[] directly.
  
  - reorganized the http code to use buffers - see HttpAdapter
  
  - small change in PoolTcpConnectionHandler - replaced
  the Vector with a SimplePool ( lighter ) and also added the
  option to not use a pool, just per thread data ( less sync in
  critical path )
  
  - moved "commited" from BufferedServletOS to Response, where
  it should be  (since BSOS is just a facade).
  
  - added missing setPort method in request
  
  - small fixes in facades - if request processing fails, default
  context's facade will be used. This will be important after we
  fix the security and implement webapp isolation.
  
  Revision  Changes    Path
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/adapter/AdapterHandler.java
  
  Index: AdapterHandler.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/adapter/AdapterHandler.java,v 1.1 2000/05/30 06:16:45 costin Exp $
   * $Revision: 1.1 $
   * $Date: 2000/05/30 06:16:45 $
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  package org.apache.tomcat.adapter;
  
  import org.apache.tomcat.service.*;
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.util.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  
  public class AdapterHandler  implements  TcpConnectionHandler {
      
      ContextManager contextM;
      SimplePool pool = new SimplePool(60);
      public static boolean usePool=true;
  
      
      public AdapterHandler() {
  	super();
      }
  
      public void setAttribute(String name, Object value ) {
  	if("context.manager".equals(name) ) {
  	    contextM=(ContextManager)value;
  	}
      }
      
      public void setServer( Object  contextM ) {
  	this.contextM=(ContextManager)contextM;
      }
  
      public Object[] init() {
  	if( usePool ) return null;
          Object thData[]=new Object[1];
  	thData[0]=createAdapter();
          return  thData;
      }
  
      HttpAdapter createAdapter() {
  	//System.out.println("XXX REQUEST_IMPL new " + pool.size());
  	HttpAdapter httpA=new HttpAdapter();
  	httpA.init(contextM);
  	return httpA;
      }
      
      public void processConnection(TcpConnection connection, Object thData[]) {
  	Socket socket=null;
  	Request reqA=null;
  	Response resA=null;
  	HttpAdapter httpA=null;
  
  	//	System.out.println("New Connection");
  	try {
  	    if (connection == null)
  		return;
  	    socket=connection.getSocket();
  	    if (socket == null)
  		return;
  
  	    if( usePool || thData==null || thData[0]==null) {
  		httpA=(HttpAdapter)pool.get();
  		if( httpA==null ) httpA=createAdapter();
  	    } else {
  		httpA =(HttpAdapter)thData[0];
  	    }
  
  	    httpA.setSocket( socket );
  
  	    httpA.readNextRequest();
  
  	    contextM.service( httpA.getRequest(), httpA.getResponse() );
  
  	    httpA.recycle();
  	    
  	    try {
                 InputStream is = socket.getInputStream();
                 int available = is.available ();
  	       
                 // XXX on JDK 1.3 just socket.shutdownInput () which
                 // was added just to deal with such issues.
  
                 // skip any unread (bogus) bytes
                 if (available > 1) {
                     is.skip (available);
                 }
  	    }catch(NullPointerException npe) {
  		// do nothing - we are just cleaning up, this is
  		// a workaround for Netscape \n\r in POST - it is supposed
  		// to be ignored
  	    } catch(java.net.SocketException ex) {
  		// do nothing - same
  	    }
  	    //	    System.out.print("5");
  	} catch (Exception e) {
  	    contextM.log( "Error reading request " + e.getMessage());
  	    e.printStackTrace();
  	} finally {
  	    // recycle kernel sockets ASAP
  	    try { if (socket != null) socket.close (); }
  	    catch (IOException e) { /* ignore */ }
          }
  	if( usePool || thData==null || thData[0]==null ) {
  	    pool.put( httpA );
  	}
  
  	//	System.out.print("6");
      }
  
  
  }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/adapter/HttpAdapter.java
  
  Index: HttpAdapter.java
  ===================================================================
  /*
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  package org.apache.tomcat.adapter;
  
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.util.*;
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  // We implement Response part of the adapter first, Request will be next
  
  /**
   */
  public final class HttpAdapter implements BufferListener {
      protected OutputStream sout;
      static int debug=0;
      ContextManager contextM;
  
      // hack - quick solution to keep only one object in pool
      RequestImpl req;
      ResponseImpl res;
  
      RecycleBufferedInputStream in;
      
  
      public static final int MAX_HEAD_LEN = 8 * 1024;
      byte buf[]=new byte[ MAX_HEAD_LEN ];
      int off=0;
      int count=0;
  
      // input stream
      int readLimit=-1;
      int readCount=0;
      
      private Socket socket;
  
      public static final String DEFAULT_CHARACTER_ENCODING = "8859_1";
      
      
      public HttpAdapter() {
          super();
      }
  
      // -------------------- Methods used by ConnectionHandler
      public void init(ContextManager contextM) {
  	ByteBuffer ob=new ByteBuffer();
  	ByteBuffer ib=new ByteBuffer();
  	ob.addBufferListener( this );
  	ib.addBufferListener( this );
  
  	req=new RequestImpl();
  	res=new ResponseImpl();
  	res.setOutputBuffer( ob );
  	req.setInputBuffer( ib );
  	this.contextM=contextM;
  	contextM.initRequest( req, res );
      }
      
      public void readNextRequest() throws IOException {
  	readNextRequest( req, res );
  	int contentLength = req.getContentLength();
  	if (contentLength != -1) {
  	    readLimit=contentLength;
  	}
      }
  
      public void setSocket(Socket socket) throws IOException {
  	if( in == null )
  	    in =  new RecycleBufferedInputStream( socket.getInputStream());
  	else
  	    in.setInputStream( socket.getInputStream() );
  	sout= socket.getOutputStream();
          this.socket = socket;
      }
  
      public Request getRequest() {
  	return req;
      }
  
      public Response getResponse() {
  	return res;
      }
      
      // -------------------- Other util methods
  
      public void recycle() {
   	bufferCount=0;
  	readLimit=-1;
  	readCount=0;
      }
  
      void log( String s ) {
  	System.out.println("HttpAdapter: " + s );
      }
  
      public void setDebug(int debug) {
  	this.debug=debug;
      }
  
  
      // -------------------- Buffer listener - implement IN/OUT
      
      /** Read from the input stream to fill a buffer.
       *  We read _once_ ( it may be a partial read, if not enough
       *  data available). Note that we read at least on byte -
       *  it's blocking IO.
       */
      public void bufferEmpty( BufferEvent ev ) {
  	try {
  	    // Find if this is the first chunk , if so do send head 
  	    if( debug > 0 ) log( "Buffer empty event ");
  	    
  	    ByteBuffer bb=(ByteBuffer)ev.getSource();
  	    ResponseImpl resp=(ResponseImpl)bb.getParent();
  	    int len=ev.getLength();
  	    if( readLimit >=0 ) {
  		if( readCount + len >= readLimit ) {
  		    len = readLimit - readCount;
  		}
  	    }
  	    int n=0;
  	    if( len >= 0 )
  		n=in.read( ev.getByteBuffer(), ev.getOffset(), len );
  	    ev.setLength( n );
  	    readCount +=n;
  	    if( debug > 0 ) log( "Read: " + readLimit + " " + readCount + " " + n + " " + len + " " + ev.getLength());
  	} catch( IOException ex ) {
  	    ex.printStackTrace();
  	}
      }
  
      // Called when  we need to send  data
      public void bufferFull( BufferEvent ev ) {
  	try {
  	    // Find if this is the first chunk , if so do send head 
  	    if( debug > 0 ) log( "Buffer full event ");
  	    
  	    ByteBuffer bb=(ByteBuffer)ev.getSource();
  	    ResponseImpl resp=(ResponseImpl)bb.getParent();
  	    
  	    if( ! resp.isBufferCommitted() ) {
  		// notify -
  		resp.notifyEndHeaders();
  		sendHead( resp );
  		resp.setBufferCommitted( true );
  	    }
  	    sout.write( ev.getByteBuffer(), ev.getOffset(), ev.getLength() );
  	} catch( IOException ex ) {
  	    ex.printStackTrace();
  	}
      }
  
  
      // -------------------- Implementation methods--------------------
      // Response - sending the head
      
      protected static final int DEFAULT_HEAD_BUFFER_SIZE = 1024;
      protected byte[] headBuffer = new byte[DEFAULT_HEAD_BUFFER_SIZE];
      protected int bufferCount = 0;
      
      private void sendHead( ResponseImpl resp )  throws IOException {
  	//	super.endHeaders(); // CM will notify endHeaders(), we just need to
  	// do our job
  	if( debug > 0 ) log( "Sending head ");
  
  	Request request=resp.getRequest();
  	int status= resp.getStatus();
  	// XXX inefficient - will create 2 strings and a hashtable lookup
  	String message=	ResponseImpl.getMessage( status );
  	
  	MimeHeaders headers=resp.getMimeHeaders();
  	
  	headAppend("HTTP/1.0 ");
  	headAppend(String.valueOf(status));
  	if(message!=null) {
  	    headAppend(" ");
  	    headAppend(message);
  	}
  	headAppend("\r\n");
  
  	// Hack: set Date header. We need to implement append(date)
  	MimeHeaderField dateH= headers.find( "Date" );
  	if( false && dateH == null ) {
  	    // no date header set by user
  	    dateH=headers.putHeader();
  	    dateH.setName("Date");
  	    dateH.setDateValue(System.currentTimeMillis());
  	    // will reuse the HttpDate instance
  	}
  	
  	// Servlet Engine header will be set per/adapter - smarter adapters will
  	// not send it every time ( have it in C side ), and we may also want
  	// to add informations about the adapter used 
  	if( request.getContext() != null) {
  	    headAppend( "Servlet-Engine: ");
  	    headAppend( request.getContext().getEngineHeader());
  	}
  
  	int count=headers.size();
  	for( int i=0; i<count; i++ ) {
  	    MimeHeaderField field=headers.getField( i );
  	    // response headers are set by the servlet, so probably we have only
  	    // Strings.
  	    // XXX date, cookies, etc shoud be extracted from response
  	    headAppend( field.getName() );
  	    headAppend(": ");
  	    headAppend( field.getValue() );
  	    headAppend("\r\n");
  	}
  	
  	headAppend( "\r\n" );
  
  	sout.write( headBuffer, 0, bufferCount );
  	sout.flush();
      }
  
      // From BufferedServletOutputStream
      // XXX will be moved in a new in/out system, temp. code
      // Right now it's not worse than BOS
      protected void headAppend( String s ) {
  	if (s==null) s="null";
  
  	int len = s.length();
  	for (int i = 0; i < len; i++) {
  	    char c = s.charAt (i);
  	    
  	    //
  	    // XXX NOTE:  This is clearly incorrect for many strings,
  	    // but is the only consistent approach within the current
  	    // servlet framework.  It must suffice until servlet output
  	    // streams properly encode their output.
  	    //
  	    if ((c & 0xff00) != 0) {	// high order byte must be zero
  		// XXX will go away after we change the I/O system
  		System.out.println("Header character is not iso8859_1, not supported yet: " + c ) ;
  	    }
  	    if( bufferCount >= headBuffer.length ) {
  		byte bufferNew[]=new byte[ headBuffer.length * 2 ];
  		System.arraycopy( headBuffer,0, bufferNew, 0, headBuffer.length );
  		headBuffer=bufferNew;
  	    }
  	    headBuffer[bufferCount] = (byte)c;
  	    bufferCount++;
  	}	
      }
  
      // -------------------- Request Methods --------------------
  
      private void readNextRequest(Request req, Response response) throws IOException {
  	// Read the full buffer - this should mean the full request
  	// and maybe part of the body or next request
  
  	count = BuffTool.readLine(in, buf, 0, buf.length);
  	
  	if (count < 0  ) {
  	    System.out.println("No request");
  	    // 	    System.out.println("Request too long ");
  	    response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
  	    return;
  	}
  	
  	int status=processRequestLine(req);
  	if( status != 0 ) {
  	    response.setStatus( status );
  	    return;
  	}
  
  	// for 0.9, we don't have headers!
  	if (req.getProtocol() !=null) { // all HTTP versions with protocol also have headers ( 0.9 has no HTTP/0.9 !)
  	    status=readHeaders( req );
  	    if( status!= 0 ) {
  		response.setStatus( status );
  		return;
  	    }
  	}
  
  	
  	//req.setServerPort( socket.getLocalPort() );
  	//req.setLocalHost( socket.getLocalAddress().getHostName() );
  	// req.setRemoteAddr( socket.getInetAddress().getHostAddress());
  	// req.setRemoteHost( socket.getInetAddress().getHostName());
      }
  
  
      /**
       * Reads header fields from the specified servlet input stream until
       * a blank line is encountered.
       * @param in the servlet input stream
       * @exception IllegalArgumentException if the header format was invalid 
       * @exception IOException if an I/O error has occurred
       */
      public int readHeaders( Request req )  throws IOException {
  	MimeHeaders headers = req.getMimeHeaders();
  	
  	// use pre-allocated buffer if possible
  	off = count; // where the request line ended
  	
  	while (true) {
  	    int start = off;
  
  	    while (true) {
  		int len = buf.length - off;
  
  		if (len > 0) {
  		    len = BuffTool.readLine(in, buf, off, len);
  
  		    if (len == -1) {
  			return HttpServletResponse.SC_BAD_REQUEST;
  		    }
  		}
  
  		off += len;
  
  		if (len == 0 || buf[off-1] == '\n') {
  		    break;
  		}
  
  		// overflowed buffer, so temporarily expand and continue
  		byte[] tmp = new byte[buf.length * 2];
  		System.arraycopy(buf, 0, tmp, 0, buf.length);
  		buf = tmp;
  	    }
  
  	    // strip off trailing "\r\n"
  	    if (--off > start && buf[off-1] == '\r') {
  		--off;
  	    }
  
  	    if (off == start) {
  		break;
  	    }
  	    
  	    // XXX this does not currently handle headers which
  	    // are folded to take more than one line.
  
  	    MimeHeaderField mhf=headers.putHeader();
  
  	    int status= parseHeaderFiled(mhf, buf, start, off - start);
  	    if( status != 0 ) {
  		// error parsing header
  		return status;
  	    }
  	}
  	return 0;
      }
  
      /**
       * Parses a header field from a subarray of bytes.
       * @param b the bytes to parse
       * @param off the start offset of the bytes
       * @param len the length of the bytes
       * @exception IllegalArgumentException if the header format was invalid
       */
      public int parseHeaderFiled(MimeHeaderField mhf, byte[] b, int off, int len)
      {
  	int start = off;
  	byte c;
  	int end=off+len;
  
  	int nameEnd= BuffTool.findChars( b, start, end, NAME_DELIMS );
  	if( nameEnd < 0 || b[nameEnd]=='\r' || b[nameEnd]=='\n' ) {
  	    System.out.println("Parse error, empty line: " + new String( b, off, len ));
  	    return HttpServletResponse.SC_BAD_REQUEST;
  	}
  	
  	mhf.setName(b, start, nameEnd - start);
  
  	// skip spaces. We should find ":" after the spaces
  	int sepIdx= BuffTool.findNotChars( b, nameEnd, end, SPACE_DELIMS );
  
  	if (b[sepIdx] != ':') {
  	    System.out.println("Parse error, missing : in  " + new String( b, off, len ));
  	    System.out.println("Full  " + new String( b, 0, b.length ));
  	    return  HttpServletResponse.SC_BAD_REQUEST;
  	}
  
  	// skip spaces
  	int valueStart= BuffTool.findNotChars( b, sepIdx + 1, end, SPACE_DELIMS);
  	if( valueStart < 0 ) {
  	    System.out.println("Parse error, no value after : " + new String( b, off, len ));
  	    System.out.println("Full  " + new String( b, 0, b.length ));
  	    return  HttpServletResponse.SC_BAD_REQUEST;
  	}
  
  	mhf.setValue(b, valueStart, end - valueStart );
  	return 0;
      }
  
      static final byte NAME_DELIMS[]={ (byte)':', (byte)' ', (byte)'\t', (byte)'\r', (byte)'\n' };
      static final byte SPACE_DELIMS[]={ (byte)' ', (byte)'\t'};
      
      /** Parse the request line and set the fields of req
       */
      private int processRequestLine(Request req)
  	throws IOException
      {
  	off=0;
  	
  	// if end of line is reached before we scan all 3 components -
  	// we're fine, off=count and remain unchanged
  	
  	if( buf[count-1]!= '\r' && buf[count-1]!= '\n' ) {
  	    return HttpServletResponse.SC_REQUEST_URI_TOO_LONG;
  	}	    
  	
  	int startMethod = BuffTool.findNotChars( buf, 0, count, SPACE_DELIMS);
  	if( startMethod == -1 ) return HttpServletResponse.SC_BAD_REQUEST;
  	int endMethod = BuffTool.findChars( buf, startMethod, count, SPACE_DELIMS );
  	if( endMethod == -1 ) return HttpServletResponse.SC_BAD_REQUEST;
  	
  	req.setMethod( new String( buf, startMethod, endMethod - startMethod ));
  
  	int startReq= BuffTool.findNotChars( buf, endMethod, count, SPACE_DELIMS);
  	if( startReq == -1 ) return  HttpServletResponse.SC_BAD_REQUEST;
  	int endReq= BuffTool.findChars( buf, startReq, count, SPACE_DELIMS);
  	if( endReq != -1 ) {
  	    // we have a space after query string, we might have protocol
  
  	    int startProto= BuffTool.findNotChars(buf, endReq, count, SPACE_DELIMS);
  	    if( startProto != -1 ) {
  		// yes, we do have protocol
  		int endProto=BuffTool.findChars( buf, startProto, count, SPACE_DELIMS);
  		// no ' ' found after end, that's ok
  		if( endProto == -1 ) endProto = count;
  		req.setProtocol( new String( buf, startProto, endProto-startProto ));
  	    } else {
  		req.setProtocol(null);
  	    }
  	} else {
  	    // no protocol
  	    req.setProtocol(null);
  	    endReq=count;
  	}
  	
  	int qryIdx= BuffTool.findChar( buf, startReq, endReq, '?' );
  	if( qryIdx <0 ) {
  	    req.setRequestURI( new String( buf, startReq, endReq - startReq ));
  	} else {
  	    req.setRequestURI( new String( buf, startReq, qryIdx - startReq ));
  	    req.setQueryString( new String( buf, qryIdx+1, endReq - qryIdx -1 ));
  	}
  
  	return 0;
      }
  
      
  }
  
  
  
  1.12      +9 -11     jakarta-tomcat/src/share/org/apache/tomcat/core/BufferedServletOutputStream.java
  
  Index: BufferedServletOutputStream.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/BufferedServletOutputStream.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- BufferedServletOutputStream.java	2000/04/26 17:24:05	1.11
  +++ BufferedServletOutputStream.java	2000/05/30 06:16:45	1.12
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/BufferedServletOutputStream.java,v 1.11 2000/04/26 17:24:05 craigmcc Exp $
  - * $Revision: 1.11 $
  - * $Date: 2000/04/26 17:24:05 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/BufferedServletOutputStream.java,v 1.12 2000/05/30 06:16:45 costin Exp $
  + * $Revision: 1.12 $
  + * $Date: 2000/05/30 06:16:45 $
    *
    * ====================================================================
    * 
  @@ -101,7 +101,6 @@
       protected int bufferSize = DEFAULT_BUFFER_SIZE;
       protected int bufferCount = 0;
       protected int totalCount = 0;
  -    protected boolean committed = false;
       protected boolean closed = false;
       ResponseImpl resA;
       
  @@ -234,10 +233,10 @@
       public void reallyFlush() throws IOException {
   	// 	System.out.println("x " + bufferCount+ " " + closed);
   	try {
  -	    if (!committed) {
  +	    if (!resA.isBufferCommitted()) {
   		//	        response.writeHeaders(out);
   		sendHeaders();
  -	        committed = true;
  +	        resA.setBufferCommitted(true);
   	    }
   
   	    if (bufferCount > 0) {
  @@ -264,9 +263,9 @@
   	return totalCount > 0 ? true : false;
       }
   
  -    public boolean isCommitted() {
  -	return this.committed;
  -    }
  +//     public boolean isCommitted() {
  +// 	return res.isCommited();
  +//     }
       
       public int getBufferSize() {
   	return buffer.length;
  @@ -294,7 +293,7 @@
       public void reset() throws IllegalStateException {
   
   	// If buffer is already commited, throw IllegalStateException.
  -	if (isCommitted()) {
  +	if (resA.isBufferCommitted()) {
   	    String msg = sm.getString("servletOutputStreamImpl.reset.ise"); 
   	    throw new IllegalStateException(msg);
   	}
  @@ -310,7 +309,6 @@
   	// 	System.out.println("Recycle BOS " );
   	bufferCount = 0;
   	totalCount = 0;
  -	committed = false;
   	closed = false;
       }
   
  
  
  
  1.83      +2 -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.82
  retrieving revision 1.83
  diff -u -r1.82 -r1.83
  --- ContextManager.java	2000/05/26 18:55:23	1.82
  +++ ContextManager.java	2000/05/30 06:16:45	1.83
  @@ -799,7 +799,8 @@
   	    if( ctx.getDebug() > 0 ) ctx.log( "Calling auth servlet " + errorServlet );
   	}
   	req.setAttribute("javax.servlet.error.status_code",new Integer( code));
  -	
  +
  +	//	System.out.println("XXX " + req + " " + res + " " + ctx );
   	callInternalError( req, res, ctx, errorServlet, errorPath );
       }
   
  
  
  
  1.43      +8 -1      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.42
  retrieving revision 1.43
  diff -u -r1.42 -r1.43
  --- Request.java	2000/05/26 17:32:05	1.42
  +++ Request.java	2000/05/30 06:16:45	1.43
  @@ -103,6 +103,8 @@
   
       public int getServerPort() ;
   
  +    public void setServerPort( int i );
  +
       public String getRemoteAddr() ;
   
       public void setRemoteAddr(String remote) ;
  @@ -258,7 +260,7 @@
       public ServletInputStream getInputStream() 	throws IOException;
   
       public  int doRead( byte b[], int off, int len ) throws IOException;
  -    
  +
       // -------------------- Internal methods --------------------
       /** Support for "pools"
        */
  @@ -300,6 +302,11 @@
        *  @deprecated - use Container instead
        */
       public void setWrapper(ServletWrapper handler) ;
  +    // -------------------- Buffers --------------------
  +
  +    public ByteBuffer getInputBuffer();
  +
  +    public void setInputBuffer(ByteBuffer buf);
   
       // -------------------- Notes --------------------
       /** Add a per/request internal attribute.
  
  
  
  1.45      +11 -0     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.44
  retrieving revision 1.45
  diff -u -r1.44 -r1.45
  --- RequestImpl.java	2000/05/29 23:59:27	1.44
  +++ RequestImpl.java	2000/05/30 06:16:45	1.45
  @@ -152,6 +152,7 @@
       protected String remoteAddr;
       protected String remoteHost;
       protected String localHost;
  +    protected ByteBuffer bBuffer;
   
       protected static StringManager sm =
           StringManager.getManager("org.apache.tomcat.core");
  @@ -636,6 +637,7 @@
           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;
       }
  @@ -652,6 +654,15 @@
           return headers.names();
       }
   
  +    public ByteBuffer getInputBuffer() {
  +	return bBuffer;
  +    }
  +
  +    public void setInputBuffer(ByteBuffer buf) {
  +	bBuffer=buf;
  +    }
  +
  +    
       public ServletInputStream getInputStream() throws IOException {
       	return in;
       }
  
  
  
  1.22      +7 -0      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.21
  retrieving revision 1.22
  diff -u -r1.21 -r1.22
  --- Response.java	2000/05/26 18:55:23	1.21
  +++ Response.java	2000/05/30 06:16:46	1.22
  @@ -201,6 +201,13 @@
       public void setSessionId(String sId );
       
       public String getSessionId( );
  +
  +    // -------------------- Buffers --------------------
  +
  +    public ByteBuffer getOutputBuffer();
  +
  +    public void  setOutputBuffer(ByteBuffer buf);
  +
       
       // -------------------- Internal methods --------------------
       /** One-to-one with Facade.
  
  
  
  1.29      +72 -32    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.28
  retrieving revision 1.29
  diff -u -r1.28 -r1.29
  --- ResponseImpl.java	2000/05/24 01:58:14	1.28
  +++ ResponseImpl.java	2000/05/30 06:16:46	1.29
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ResponseImpl.java,v 1.28 2000/05/24 01:58:14 costin Exp $
  - * $Revision: 1.28 $
  - * $Date: 2000/05/24 01:58:14 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ResponseImpl.java,v 1.29 2000/05/30 06:16:46 costin Exp $
  + * $Revision: 1.29 $
  + * $Date: 2000/05/30 06:16:46 $
    *
    * ====================================================================
    *
  @@ -100,11 +100,12 @@
   
       protected BufferedServletOutputStream out;
       protected PrintWriter writer;
  +    protected ByteBuffer bBuffer;
   
       protected boolean usingStream = false;
       protected boolean usingWriter = false;
       protected boolean started = false;
  -    protected boolean committed = false;
  +    protected boolean commited = false;
       
       boolean notIncluded=true;
   
  @@ -117,8 +118,13 @@
       }
   
       public HttpServletResponse getFacade() {
  -        if( responseFacade==null )
  -	    responseFacade = request.getContext().getFacadeManager().createHttpServletResponseFacade(this);
  +        if( responseFacade==null ) {
  +	    Context ctx= request.getContext();
  +	    if( ctx == null ) {
  +		ctx=request.getContextManager().getContext("");
  +	    }
  +	    responseFacade = ctx.getFacadeManager().createHttpServletResponseFacade(this);
  +	}
   	return responseFacade;
       }
   
  @@ -167,18 +173,13 @@
   	sessionId=null;
   	writer=null;
   	started = false;
  -	committed = false;
  +	commited = false;
   	notIncluded=true;
   	// adapter
   	body=null;
   	if( out != null ) out.recycle();
  -
  -
  -	out.recycle(); //=new BufferedServletOutputStream();
  -	//	out.setResponse(this);
  -
  +	if( bBuffer != null ) bBuffer.recycle();
   	headers.clear();
  -	//headers = new MimeHeaders();
       }
   
       public void finish() throws IOException {
  @@ -187,6 +188,11 @@
   	        writer.flush();
   		writer.close();
   	    }
  +	    if( bBuffer != null) {
  +		bBuffer.flush();
  +		request.getContextManager().doAfterBody(request, this);
  +		return;
  +	    }
   	    out.reallyFlush();
   	    request.getContextManager().doAfterBody(request, this);
   	    out.close();
  @@ -225,35 +231,49 @@
   	usingWriter=writer;
   	out.setUsingWriter (true);
       }
  -    
  +
       public PrintWriter getWriter() throws IOException {
  +	return getWriter( out );
  +    }
  +
  +    public PrintWriter getWriter(ServletOutputStream outs) throws IOException {
   	if(writer!=null) return writer;
   	// it already did all the checkings
   	
   	started = true;
   
   	
  -	// XXX - EBCDIC issue here?
  +	writer = new ServletWriterFacade( getConverter(outs), this);
  +	return writer;
  +    }
  +
  +    public Writer getConverter( ServletOutputStream outs ) throws IOException {
   	String encoding = getCharacterEncoding();
  -	if ((encoding == null) || Constants.DEFAULT_CHAR_ENCODING.equals(encoding) )
  -	    writer = new ServletWriterFacade( new OutputStreamWriter(out), this);
  -	else
  +
  +	if (encoding == null) {
  +	    // use default platform encoding - is this correct ? 
  +	    return  new OutputStreamWriter(outs);
  +        }  else {
   	    try {
  -		writer = new ServletWriterFacade( new OutputStreamWriter(out, encoding), this);
  +		return  new OutputStreamWriter(outs, encoding);
   	    } catch (java.io.UnsupportedEncodingException ex) {
  -		// if we don't do that, the runtime exception will propagate
  -		// and we'll try to send an error page - but surprise, we
  -		// still can't get the Writer to send the error page...
  -		writer = new ServletWriterFacade( new OutputStreamWriter(out), this);
  -		
  -		// Deal with strange encodings - webmaster should see a message
  -		// and install encoding classes - n new, unknown language was discovered,
  -		// and they read our site!
  +		// XXX log it
   		System.out.println("Unsuported encoding: " + encoding );
  +
  +		return new OutputStreamWriter(outs);
   	    }
  -	return writer;
  +	}
  +    }
  +
  +    public ByteBuffer getOutputBuffer() {
  +	return bBuffer;
       }
   
  +    public void setOutputBuffer(ByteBuffer buf) {
  +	bBuffer=buf;
  +	if( buf!= null) buf.setParent( this );
  +    }
  +    
       /** Either implement ServletOutputStream or return BufferedServletOutputStream(this)
   	and implement doWrite();
   	@deprecated 
  @@ -316,17 +336,24 @@
       }
   
       public int getBufferSize() {
  +	if( bBuffer != null ) return bBuffer.getBufferSize();
   	return out.getBufferSize();
       }
   
       public void setBufferSize(int size) throws IllegalStateException {
  -
   	// Force the PrintWriter to flush the data to the OutputStream.
   	if (usingWriter == true && writer != null ) writer.flush();
   
  +	if( bBuffer != null ) {
  +	    if( bBuffer.isContentWritten() ) {
  +		throw new IllegalStateException ( sm.getString("servletOutputStreamImpl.setbuffer.ise"));
  +	    }
  +	    bBuffer.setBufferSize(size);
  +	    return;
  +	}
  +	
   	if (out.isContentWritten() == true) {
  -	    String msg = sm.getString("servletOutputStreamImpl.setbuffer.ise");
  -	    throw new IllegalStateException (msg);
  +	    throw new IllegalStateException ( sm.getString("servletOutputStreamImpl.setbuffer.ise"));
   	}
   	out.setBufferSize(size);
       }
  @@ -335,9 +362,14 @@
        * Methodname "isCommitted" already taken by Response class.
        */
       public boolean isBufferCommitted() {
  -	return out.isCommitted();
  +	return commited;
  +	//	return out.isCommitted();
       }
   
  +    public void setBufferCommitted( boolean v ) {
  +	this.commited=v;
  +    }
  +    
       public void reset() throws IllegalStateException {
   	// Force the PrintWriter to flush its data to the output
           // stream before resetting the output stream
  @@ -384,6 +416,14 @@
        *  interceptors to fix headers.
        */
       public void endHeaders() throws IOException {
  +	notifyEndHeaders();
  +    }
  +
  +    /** Signal that we're done with the headers, and body will follow.
  +     *  Any implementation needs to notify ContextManager, to allow
  +     *  interceptors to fix headers.
  +     */
  +    public void notifyEndHeaders() throws IOException {
   	if(request.getProtocol()==null) // HTTP/0.9 
   	    return;
   
  
  
  
  1.4       +36 -1     jakarta-tomcat/src/share/org/apache/tomcat/facade/HttpServletRequestFacade.java
  
  Index: HttpServletRequestFacade.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/facade/HttpServletRequestFacade.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- HttpServletRequestFacade.java	2000/05/24 16:34:09	1.3
  +++ HttpServletRequestFacade.java	2000/05/30 06:16:47	1.4
  @@ -86,6 +86,8 @@
       private Request request;
   
       HttpSessionFacade sessionFacade;
  +    ServletInputStreamFacade isFacade=null;
  +    BufferedReader reader;
       
       private boolean usingStream = false;
       private boolean usingReader = false;
  @@ -102,6 +104,7 @@
   	usingReader=false;
   	usingStream=false;
   	if( sessionFacade!=null) sessionFacade.recycle();
  +	if( isFacade != null ) isFacade.recycle();
       }
   
       /** Not public - is called only from FacadeManager
  @@ -185,6 +188,15 @@
   	    throw new IllegalStateException(msg);
   	}
   	usingStream = true;
  +
  +	if( isFacade!=null) return isFacade;
  +	if( request.getInputBuffer() != null ) {
  +	    isFacade=new ServletInputStreamFacade();
  +	    isFacade.setRequest( request );
  +	    return isFacade;
  +	}
  +
  +	// old mechanism
   	return request.getInputStream();
       }
   
  @@ -262,7 +274,30 @@
   	    throw new IllegalStateException(msg);
   	}
   	usingReader = true;
  -	return request.getReader();
  +
  +	// old mechanism
  +	if( isFacade==null && request.getInputBuffer() == null )
  +	    return request.getReader();
  +
  +	// New mechanism, based on exposed Buffers
  +	if(  isFacade == null ) {
  +	    isFacade=new ServletInputStreamFacade();
  +	}
  +
  +	isFacade.setRequest( request );
  +	if( reader != null ) return reader; // method already called 
  +
  +	// from RequestUtil.
  +	// XXX  provide recycleable objects
  +	String encoding = request.getCharacterEncoding();
  +        if (encoding == null) {
  +            encoding = Constants.DEFAULT_CHAR_ENCODING;
  +        }
  +	
  +	InputStreamReader r =
  +            new InputStreamReader(isFacade, encoding);
  +	reader= new BufferedReader(r);
  +	return reader;
       }
       
       public String getRemoteAddr() {
  
  
  
  1.4       +28 -6     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.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- HttpServletResponseFacade.java	2000/05/26 17:32:10	1.3
  +++ HttpServletResponseFacade.java	2000/05/30 06:16:47	1.4
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/facade/HttpServletResponseFacade.java,v 1.3 2000/05/26 17:32:10 costin Exp $
  - * $Revision: 1.3 $
  - * $Date: 2000/05/26 17:32:10 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/facade/HttpServletResponseFacade.java,v 1.4 2000/05/30 06:16:47 costin Exp $
  + * $Revision: 1.4 $
  + * $Date: 2000/05/30 06:16:47 $
    *
    * ====================================================================
    *
  @@ -88,7 +88,9 @@
       private Response response;
       private boolean usingStream = false;
       private boolean usingWriter = false;
  -
  +    ServletOutputStreamFacade osFacade=null;
  +    PrintWriter writer = null; // XXX will go away when we add the convertor
  +    
       /** Package
        */
       HttpServletResponseFacade(Response response) {
  @@ -98,6 +100,8 @@
       void recycle() {
   	usingStream = false;
   	usingWriter= false;
  +	writer=null;
  +	if( osFacade != null ) osFacade.recycle();
       }
       
       // -------------------- Public methods -------------------- 
  @@ -154,6 +158,14 @@
   	}
   	usingStream=true;
   	response.setUsingStream( true );
  +
  +	if( osFacade!=null) return osFacade;
  +	if( response.getOutputBuffer() != null ) {
  +	    osFacade=new ServletOutputStreamFacade(response);
  +	    return osFacade;
  +	}
  +
  +	// old mechanism
   	return response.getOutputStream();
   	// response.getBufferedOutputStream().getServletOutputStreamFacade();
       }
  @@ -165,8 +177,18 @@
   	}
   	usingWriter= true ;
   	response.setUsingWriter( true );
  -	return response.getWriter();
  -	//	return new ServletWriterFacade( coreW, this);
  +
  +	// old mechanism
  +	if( osFacade==null && response.getOutputBuffer() == null )
  +	    return response.getWriter();
  +
  +	if(  osFacade == null ) {
  +	    osFacade=new ServletOutputStreamFacade(response);
  +	}
  +
  +	if( writer != null ) return writer;
  +	writer=((ResponseImpl)response).getWriter( osFacade );
  +	return writer;
       }
   
       public void sendError(int sc) throws IOException {
  
  
  
  1.3       +12 -21    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.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ServletOutputStreamFacade.java	2000/05/26 17:32:10	1.2
  +++ ServletOutputStreamFacade.java	2000/05/30 06:16:47	1.3
  @@ -61,34 +61,25 @@
   package org.apache.tomcat.facade;
   
   import org.apache.tomcat.core.*;
  -import org.apache.tomcat.util.StringManager;
  +import org.apache.tomcat.util.*;
   import java.io.*;
   import javax.servlet.ServletOutputStream;
   
   /**
  - *  Facade to BufferedServletOutputStream - we need that to prevent any
  - *  uncontroled access to public methods internal to tomcat and
  - *  to isolate the servlet semantics from the internal implementation.
  - *  ( and make sure the API is respected even if the internal objects
  - *    have different behavior - for performance or integration )
  - *
  - * @author James Duncan Davidson [duncan@eng.sun.com]
  - * @author Jason Hunter [jch@eng.sun.com]
  - * @author James Todd [gonzo@eng.sun.com]
  - * @author Mandar Raje [mandar@eng.sun.com]
  - * @author Costin Manolache [costin@eng.sun.com]
  + * 
    */
   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;
  -    BufferedServletOutputStream bos;
  -
  +    ByteBuffer bb;
  +    
       /** Encoding - first time print() is used.
   	IMPORTANT: print() is _bad_, if you want to write Strings and mix
   	bytes you'd better use a real writer ( it's faster ).
  @@ -99,23 +90,23 @@
       /** True if we already called getEncoding() - cache result */
       boolean gotEnc=false;
       
  -    protected ServletOutputStreamFacade( BufferedServletOutputStream bos, Response resA) {
  +    protected ServletOutputStreamFacade( Response resA) {
   	this.resA=resA;
  -	this.bos=bos;
  +	bb=resA.getOutputBuffer();
       }
   
       // -------------------- Write methods --------------------
       
       public void write(int i) throws IOException {
  -	bos.write(i);
  +	bb.write(i);
       }
   
       public void write(byte[] b) throws IOException {
  -	bos.write(b,0,b.length);
  +	write(b,0,b.length);
       }
       
       public void write(byte[] b, int off, int len) throws IOException {
  -	bos.write( b, off, len );
  +	bb.write( b, off, len );
       }
   
       // -------------------- Servlet Output Stream methods --------------------
  @@ -154,11 +145,11 @@
       /** Will send the buffer to the client.
        */
       public void flush() throws IOException {
  -	bos.reallyFlush();
  +	bb.flush(); // send it now !
       }
   
       public void close() throws IOException {
  -	bos.reallyFlush();
  +	bb.flush(); // send it now !
   	closed = true;
       }
   
  
  
  
  1.2       +1 -1      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.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ServletWriterFacade.java	2000/05/26 17:32:10	1.1
  +++ ServletWriterFacade.java	2000/05/30 06:16:47	1.2
  @@ -77,7 +77,7 @@
    *
    * @author Costin Manolache [costin@eng.sun.com]
    */
  -//XXX
  +// 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;
  
  
  
  1.5       +49 -39    jakarta-tomcat/src/share/org/apache/tomcat/service/PoolTcpEndpoint.java
  
  Index: PoolTcpEndpoint.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/PoolTcpEndpoint.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- PoolTcpEndpoint.java	2000/05/26 23:06:37	1.4
  +++ PoolTcpEndpoint.java	2000/05/30 06:16:48	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/PoolTcpEndpoint.java,v 1.4 2000/05/26 23:06:37 costin Exp $
  - * $Revision: 1.4 $
  - * $Date: 2000/05/26 23:06:37 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/PoolTcpEndpoint.java,v 1.5 2000/05/30 06:16:48 costin Exp $
  + * $Revision: 1.5 $
  + * $Date: 2000/05/30 06:16:48 $
    *
    * ====================================================================
    *
  @@ -114,6 +114,7 @@
   
       ThreadPoolRunnable listener;
       boolean running = true;
  +    static final int debug=0;
   
       ThreadPool tp;
   
  @@ -121,6 +122,10 @@
   	tp = new ThreadPool();
       }
   
  +    void log( String s ) {
  +	System.out.println("PoolTcpEndpoint: " + s );
  +    }
  +    
       // -------------------- Configuration --------------------
   
       public void setPoolOn(boolean isPool) {
  @@ -305,10 +310,7 @@
   }
   
   // -------------------- Threads --------------------
  -// XXX add a more efficient model - use thread pools, use a Queue, etc
   
  -// Keep the thread model in one place !
  -
   /*
    * I switched the threading model here.
    *
  @@ -327,56 +329,64 @@
          We also want to use per/thread data and avoid sync wherever possible.
       */
       PoolTcpEndpoint endpoint;
  -    Vector connectionCache;
  -
  +    SimplePool connectionCache;
  +    static final boolean usePool=true;
  +    
       public TcpWorkerThread(PoolTcpEndpoint endpoint) {
  -	    this.endpoint = endpoint;
  -	    connectionCache = new Vector(endpoint.getMaxThreads());
  +	this.endpoint = endpoint;
  +	if( usePool ) {
  +	    connectionCache = new SimplePool(endpoint.getMaxThreads());
   	    for(int i = 0 ; i < endpoint.getMaxThreads()/2 ; i++) {
  -	        connectionCache.addElement(new TcpConnection());
  +		connectionCache.put(new TcpConnection());
   	    }
  +	}
       }
   
       public Object[] getInitData() {
  -	return endpoint.getConnectionHandler().init();
  +	if( usePool ) {
  +	    return endpoint.getConnectionHandler().init();
  +	} else {
  +	    // no synchronization overhead, but 2 array access 
  +	    Object obj[]=new Object[2];
  +	    obj[1]= endpoint.getConnectionHandler().init();
  +	    obj[0]=new TcpConnection();
  +	    return obj;
  +	}
       }
       
       public void runIt(Object perThrData[]) {
  +	TcpConnection con=null;
  +	if( ! usePool ) {
  +	    // extract the original.
  +	    con=(TcpConnection) perThrData[0];
  +	    perThrData = (Object []) perThrData[1];
  +	}
  +	
   	// Create per-thread cache
   	while(endpoint.running) {
  +	    Socket s = endpoint.acceptSocket();
  +
  +	    if(null != s) {
  +		// Continue accepting on another thread...
  +		
  +		endpoint.tp.runIt(this);
   		
  -		//		System.out.println("XXX accept socket");
  -	        Socket s = endpoint.acceptSocket();
  -		//		System.out.print("Ac");
  -		//		System.out.println("XXX accepted " + s );
  -	        if(null != s) {
  -	            // Continue accepting on another thread...
  -		    //		    System.out.print("Ar");
  -	            endpoint.tp.runIt(this);
  -		    //  System.out.print("Ri");
  -	            TcpConnection con = null;
  -	            try {
  -                	// XXX set socket options
  -                	// 	s.setSoLinger( true, 100);
  -                	//	s.setSoTimeout( 1000 );
  -			try {
  -			    con = (TcpConnection)connectionCache.lastElement();
  -			    connectionCache.removeElementAt(connectionCache.size() - 1);
  -			} catch(Throwable t) {
  +		try {
  +		    if( usePool ) {
  +			con=(TcpConnection)connectionCache.get();
  +			if( con == null ) 
   			    con = new TcpConnection();
  -			}
  -
  -                	con.setEndpoint(endpoint);
  -                	con.setSocket(s);
  -                	endpoint.getConnectionHandler().processConnection(con, perThrData);
  +		    }
  +		    
  +		    con.setEndpoint(endpoint);
  +		    con.setSocket(s);
  +		    endpoint.getConnectionHandler().processConnection(con, perThrData);
                   } finally {
                       con.recycle();
  -                    connectionCache.addElement(con);
  +                    if( usePool && con != null ) connectionCache.put(con);
                   }
  -		    //		System.out.println("XXX done " + s  );
                   break;
  -	        }
   	    }
  -	    //	    System.out.println("End thread "   );
  +	}
       }
   }
  
  
  
  1.4       +19 -42    jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp13ConnectorResponse.java
  
  Index: Ajp13ConnectorResponse.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp13ConnectorResponse.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- Ajp13ConnectorResponse.java	2000/05/25 14:18:23	1.3
  +++ Ajp13ConnectorResponse.java	2000/05/30 06:16:48	1.4
  @@ -1,8 +1,8 @@
   
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp13ConnectorResponse.java,v 1.3 2000/05/25 14:18:23 shachor Exp $
  - * $Revision: 1.3 $
  - * $Date: 2000/05/25 14:18:23 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp13ConnectorResponse.java,v 1.4 2000/05/30 06:16:48 costin Exp $
  + * $Revision: 1.4 $
  + * $Date: 2000/05/30 06:16:48 $
    *
    * ====================================================================
    *
  @@ -96,11 +96,10 @@
       public static final int SC_RESP_WWW_AUTHENTICATE    = 0xA00B;
       
       MsgConnector con;
  -    Ajp13OutputStream rout;
   
       public Ajp13ConnectorResponse() 
       {
  -	}
  +    }
   
       // XXX if more headers that MAX_SIZE, send 2 packets!   
       public void endHeaders() throws IOException 
  @@ -211,49 +210,27 @@
       public void recycle() 
       {
           super.recycle();
  -        if(rout!=null) {
  -            rout.recycle();
  -        }
  -        out = rout;
       }
       
       public void setConnector(MsgConnector con) 
       {
           this.con = con;
  -        rout = new Ajp13OutputStream(con);
  -        rout.setResponse(this);
  -        this.out = rout;
       }
           
  -	class Ajp13OutputStream extends BufferedServletOutputStream  
  -	{     
  -    	MsgConnector con;
  -    
  -    	// XXX clean up
  -    	Ajp13OutputStream(MsgConnector con) 
  -    	{
  -        	this.con = con;
  -    	}
  -
  -    	public void doWrite(  byte b[], int off, int len) throws IOException 
  -    	{
  -        	int sent = 0;
  -        	while(sent < len) {
  -        		int to_send = len - sent;
  -        		to_send = to_send > MAX_SEND_SIZE ? MAX_SEND_SIZE : to_send;
  -        		
  -	        	MsgBuffer buf = con.getMsgBuffer();
  -	        	buf.reset();
  -	        	buf.appendByte(Ajp13ConnectorResponse.JK_AJP13_SEND_BODY_CHUNK);	        	
  -	        	buf.appendBytes(b, off + sent, to_send);	        
  -	        	con.send(buf);
  -	        	sent += to_send;
  -	        }
  -    	}
  -
  -    	protected void endResponse() throws IOException 
  -    	{
  -    	}
  -}
  +    public void doWrite(  byte b[], int off, int len) throws IOException 
  +    {
  +	int sent = 0;
  +	while(sent < len) {
  +	    int to_send = len - sent;
  +	    to_send = to_send > MAX_SEND_SIZE ? MAX_SEND_SIZE : to_send;
  +	    
  +	    MsgBuffer buf = con.getMsgBuffer();
  +	    buf.reset();
  +	    buf.appendByte(Ajp13ConnectorResponse.JK_AJP13_SEND_BODY_CHUNK);	        	
  +	    buf.appendBytes(b, off + sent, to_send);	        
  +	    con.send(buf);
  +	    sent += to_send;
  +	}
  +    }
       
   }
  
  
  
  1.16      +3 -21     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.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- HttpRequestAdapter.java	2000/05/26 17:32:16	1.15
  +++ HttpRequestAdapter.java	2000/05/30 06:16:51	1.16
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpRequestAdapter.java,v 1.15 2000/05/26 17:32:16 costin Exp $
  - * $Revision: 1.15 $
  - * $Date: 2000/05/26 17:32:16 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpRequestAdapter.java,v 1.16 2000/05/30 06:16:51 costin Exp $
  + * $Revision: 1.16 $
  + * $Date: 2000/05/30 06:16:51 $
    *
    * ====================================================================
    *
  @@ -71,24 +71,6 @@
   import java.util.*;
   import javax.servlet.*;
   import javax.servlet.http.*;
  -
  -class RecycleBufferedInputStream extends BufferedInputStream {
  -    RecycleBufferedInputStream( InputStream is ) {
  -	super( is );
  -    }
  -
  -    void setInputStream( InputStream is ) {
  -	this.count=0;
  -	this.in=is;
  -    }
  -
  -    void recycle() {
  -	this.in=null;
  -	this.count=0;
  -    }
  -
  -    
  -}
   
   public class HttpRequestAdapter extends RequestImpl {
       private Socket socket;
  
  
  
  1.6       +84 -3     jakarta-tomcat/src/share/org/apache/tomcat/util/BuffTool.java
  
  Index: BuffTool.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/BuffTool.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- BuffTool.java	2000/04/21 20:45:11	1.5
  +++ BuffTool.java	2000/05/30 06:16:54	1.6
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/BuffTool.java,v 1.5 2000/04/21 20:45:11 costin Exp $
  - * $Revision: 1.5 $
  - * $Date: 2000/04/21 20:45:11 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/BuffTool.java,v 1.6 2000/05/30 06:16:54 costin Exp $
  + * $Revision: 1.6 $
  + * $Date: 2000/05/30 06:16:54 $
    *
    * ====================================================================
    *
  @@ -128,5 +128,86 @@
   	System.out.println();
       }
   
  +    // Various byte[] utils, used in parsing request and protocols
  +
  +    /** Find a character, no side effects.
  +     *  @returns index of char if found, -1 if not
  +     */
  +    public static int findChar( byte buf[], int start, int end, char c ) {
  +	byte b=(byte)c;
  +	int offset = start;
  +	while (offset < end) {
  +	    if (buf[offset] == b) {
  +		return offset;
  +	    }
  +	    offset++;
  +	}
  +	return -1;
  +    }
  +
  +    /** Find a character, no side effects.
  +     *  @returns index of char if found, -1 if not
  +     */
  +    public static int findChars( byte buf[], int start, int end, byte c[] ) {
  +	int clen=c.length;
  +	int offset = start;
  +	while (offset < end) {
  +	    for( int i=0; i<clen; i++ ) 
  +		if (buf[offset] == c[i]) {
  +		    return offset;
  +		}
  +	    offset++;
  +	}
  +	return -1;
  +    }
  +
  +    /** Find the first character != c 
  +     *  @returns index of char if found, -1 if not
  +     */
  +    public static int findNotChars( byte buf[], int start, int end, byte c[] ) {
  +	int clen=c.length;
  +	int offset = start;
  +	boolean found;
  +		
  +	while (offset < end) {
  +	    found=true;
  +	    for( int i=0; i<clen; i++ ) {
  +		if (buf[offset] == c[i]) {
  +		    found=false;
  +		    break;
  +		}
  +	    }
  +	    if( found ) { // buf[offset] != c[0..len]
  +		return offset;
  +	    }
  +	    offset++;
  +	}
  +	return -1;
  +    }
  +
  +
  +    /** Read a line from input to buf.
  +     *  Hope that in is buffered !!
  +     *  @returns The number of bytes read, of -1 if end of stream
  +     */
  +    public static int readLine(InputStream in, byte[] b, int off, int len)
  +	throws IOException
  +    {
  +
  +	if (len <= 0) {
  +	    return 0;
  +	}
  +	int count = 0;
  +	int c;
  +
  +	while ((c = in.read()) != -1) {
  +	    b[off++] = (byte)c;
  +	    count++;
  +	    if (c == '\n' || count == len) {
  +		break;
  +	    }
  +	}
  +	return count > 0 ? count : -1;
  +    }
   
   }
  
  
  
  1.2       +82 -11    jakarta-tomcat/src/share/org/apache/tomcat/util/ByteBuffer.java
  
  Index: ByteBuffer.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/ByteBuffer.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ByteBuffer.java	2000/05/26 23:55:55	1.1
  +++ ByteBuffer.java	2000/05/30 06:16:55	1.2
  @@ -80,16 +80,23 @@
    * @author Costin Manolache
    */
   public class ByteBuffer {
  +    // everything happens inside one thread !!!
   
       BufferEvent bufferEvent=new BufferEvent(this);
   
  -    BufferListener listeners[];
  +    BufferListener listeners[]=new BufferListener[10];
  +    int listenerCount=0;
       
  -    int defaultBufferSize = 2048;
  +    protected static final int DEFAULT_BUFFER_SIZE = 8*1024;
  +    int defaultBufferSize = DEFAULT_BUFFER_SIZE;
  +    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 
  @@ -97,41 +104,80 @@
        */
       public int count;
       // count==-1 for end of stream
  -
  +    
  +    Object parent; // Who "owns" this buffer
  +    
       /**
        * The current position in the buffer. This is the index of the next 
        * character to be read from the buf. 
        */
       public int pos;
   
  +    final static int debug=0;
  +    
       public ByteBuffer() {
  +	buf=new byte[defaultBufferSize];
  +    }
  +
  +    public void recycle() {
  +	bytesWritten=0;
  +	count=0;
  +    }
  +
  +    public Object getParent() {
  +	return parent;
  +    }
  +
  +    public void setParent( Object o ) {
  +	parent=o;
  +    }
  +    
  +    public void addBufferListener( BufferListener l ) {
  +	listeners[listenerCount]=l;
  +	listenerCount++;
       }
       
       public void doWrite( byte buf[], int off, int count ) {
  -	
  +	bufferEvent.setByteBuffer( buf );
  +	bufferEvent.setOffset( off );
  +	bufferEvent.setLength( count );
  +	for( int i=0; i< listenerCount; i++ )
  +	    listeners[i].bufferFull( bufferEvent );
       }
   
       public int doRead( byte buf[], int off, int count ) {
  -	return 0;
  +	if( debug > 1 ) log("doRead " + off + " " + count);
  +	bufferEvent.setByteBuffer( buf );
  +	bufferEvent.setOffset( off );
  +	bufferEvent.setLength( count );
  +	for( int i=0; i< listenerCount; i++ )
  +	    listeners[i].bufferEmpty( bufferEvent );
  +	return bufferEvent.getLength();
       }
       
       // -------------------- Adding to the buffer -------------------- 
       // Like BufferedOutputStream, without sync
   
       public void write(int b) throws IOException {
  +	if( debug>0 ) log( "write(b)");
  +	if( debug>1 )System.out.write( b );
   	if (count >= buf.length) {
  -	    flushBuffer();
  +	    flush();
   	}
   	buf[count++] = (byte)b;
  +	bytesWritten++;
       }
   
  -    public synchronized void write(byte b[], int off, int len) throws IOException {
  +    public void write(byte b[], int off, int len) throws IOException {
  +	if( debug>0 ) log( "write(b[])" );
  +	if( debug>1 ) System.out.write( b, off, len );
   	int avail=buf.length - count;
   
   	// fit in buffer, great.
   	if( len <= avail ) {
   	    System.arraycopy(b, off, buf, count, len);
   	    count += len;
  +	    bytesWritten += len;
   	    return;
   	}
   
  @@ -149,21 +195,23 @@
   	    */
   	    System.arraycopy(b, off, buf, count, avail);
   	    count += avail;
  -	    flushBuffer(); // count will be 0
  +	    flush(); // count will be 0
   
   	    System.arraycopy(b, off+avail, buf, count, len - avail);
   	    count+= len - avail;
  +	    bytesWritten += len - avail;
   	    return;
   	}
   
   	// len > buf.length + avail
  -	flushBuffer();
  +	flush();
   	doWrite( b, off, len );
   
   	return;
       }
   
  -    private void flushBuffer() {
  +    public void flush() {
  +	if( debug > 0 ) log("Flush");
   	if (count > 0) {
   	    doWrite(buf, 0, count);
   	    count = 0;
  @@ -220,7 +268,7 @@
   	
   	// copy the remaining
   	int cnt = (avail < len - n ) ? avail : len - n ;
  -	System.arraycopy(buf, pos, b, off+len, cnt);
  +	System.arraycopy(buf, pos, b, off+n, cnt);
   	pos += cnt;
   	n+=cnt;
   
  @@ -230,8 +278,31 @@
       private  void fill() {
   	pos=0;
   	count = doRead( buf, 0, buf.length );
  +	if( count==0) count=-1; // end of stream
  +    }
  +
  +
  +    // --------------------  BufferedOutputStream compatibility
  +
  +    public boolean isContentWritten() {
  +	return bytesWritten!=0;
  +    }
  +    
  +    public void setBufferSize(int size) {
  +	if( size > buf.length ) {
  +	    buf=new byte[size];
  +	}
  +    }
  +
  +    public int getBufferSize() {
  +	return buf.length;
       }
   
   
  +    // -------------------- Utils
  +
  +    void log( String s ) {
  +	System.out.println("ByteBuffer: " + s );
  +    }
       
   }
  
  
  
  1.11      +1 -1      jakarta-tomcat/src/share/org/apache/tomcat/util/RequestUtil.java
  
  Index: RequestUtil.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/RequestUtil.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- RequestUtil.java	2000/03/30 22:22:18	1.10
  +++ RequestUtil.java	2000/05/30 06:16:55	1.11
  @@ -95,7 +95,7 @@
   	if (contentType != null &&
               contentType.startsWith("application/x-www-form-urlencoded")) {
   	    try {
  -		ServletInputStream is=request.getInputStream();
  +		ServletInputStream is=request.getFacade().getInputStream();
                   Hashtable postParameters =  HttpUtils.parsePostData(contentLength, is);
   		return postParameters;
   	    }
  
  
  
  1.1                  jakarta-tomcat/src/share/org/apache/tomcat/util/RecycleBufferedInputStream.java
  
  Index: RecycleBufferedInputStream.java
  ===================================================================
  /*
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */ 
  package org.apache.tomcat.util;
  
  import org.apache.tomcat.core.*;
  import org.apache.tomcat.core.Constants;
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  import java.text.*;
  
  public class RecycleBufferedInputStream extends BufferedInputStream {
      public RecycleBufferedInputStream( InputStream is ) {
  	super( is );
      }
  
      public void setInputStream( InputStream is ) {
  	this.count=0;
  	this.in=is;
      }
  
      public void recycle() {
  	this.in=null;
  	this.count=0;
      }
  
      
  }
  
  
  

Mime
View raw message