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/05/23 22:58:30 UTC

cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/util MessageString.java MimeHeaderField.java MimeHeaders.java

costin      00/05/23 13:58:28

  Modified:    src/share/org/apache/tomcat/context
                        LoadOnStartupInterceptor.java
               src/share/org/apache/tomcat/core Context.java
                        ContextManager.java
               src/share/org/apache/tomcat/facade
                        HttpServletRequestFacade.java
                        ServletContextFacade.java
               src/share/org/apache/tomcat/service
                        Ajp11ConnectionHandler.java
               src/share/org/apache/tomcat/service/connector
                        Ajp12ConnectionHandler.java
               src/share/org/apache/tomcat/service/http
                        HttpResponseAdapter.java
               src/share/org/apache/tomcat/util MessageString.java
                        MimeHeaderField.java MimeHeaders.java
  Log:
  - Fix Facade problem ( RequestDispatcher )
  - start working on MimeHeader
  - remove gross garbage generation in HttpResponse ( and Ajp11, Ajp12 adapters that extend it)
  StringBuffer.setLength(0) is _wrong_
  
  Note that the code is still bad - changing the I/O system to support other charsets and
  avoid multiple buffers is probably the most important thing ( both I18N and performance).
  
  Revision  Changes    Path
  1.10      +1 -1      jakarta-tomcat/src/share/org/apache/tomcat/context/LoadOnStartupInterceptor.java
  
  Index: LoadOnStartupInterceptor.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/context/LoadOnStartupInterceptor.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- LoadOnStartupInterceptor.java	2000/02/17 07:52:18	1.9
  +++ LoadOnStartupInterceptor.java	2000/05/23 20:58:18	1.10
  @@ -177,7 +177,7 @@
   	request.setContext(context);
   	request.getSession(true);
   	
  -	RequestDispatcher rd = context.getRequestDispatcher(requestURI);
  +	RequestDispatcher rd = context.getFacade().getRequestDispatcher(requestURI);
   	
   	try {
   	    rd.forward(request.getFacade(), response.getFacade());
  
  
  
  1.88      +0 -25     jakarta-tomcat/src/share/org/apache/tomcat/core/Context.java
  
  Index: Context.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/Context.java,v
  retrieving revision 1.87
  retrieving revision 1.88
  diff -u -r1.87 -r1.88
  --- Context.java	2000/05/23 16:56:41	1.87
  +++ Context.java	2000/05/23 20:58:21	1.88
  @@ -730,31 +730,6 @@
   
       // -------------------- Facade methods --------------------
   
  -    public RequestDispatcher getRequestDispatcher(String path) {
  -	if ( path == null  || ! path.startsWith("/")) {
  -	    return null; // spec say "return null if we can't return a dispather
  -	}
  -	RequestDispatcherImpl rD=new RequestDispatcherImpl( this );
  -	rD.setPath( path );
  -
  -	return rD;
  -    }
  -
  -    public RequestDispatcher getNamedDispatcher(String name) {
  -        if (name == null)
  -	    return null;
  -
  -	// We need to do the checks
  -	ServletWrapper wrapper = getServletByName( name );
  -	if (wrapper == null)
  -	    return null;
  -	RequestDispatcherImpl rD=new RequestDispatcherImpl( this );
  -	rD.setName( name );
  -
  -	return rD;
  -    }
  -
  -
       public Context getContext(String path) {
   	if (! path.startsWith("/")) {
   	    return null; // according to spec, null is returned
  
  
  
  1.80      +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.79
  retrieving revision 1.80
  diff -u -r1.79 -r1.80
  --- ContextManager.java	2000/05/23 16:56:42	1.79
  +++ ContextManager.java	2000/05/23 20:58:21	1.80
  @@ -832,7 +832,7 @@
   	// Try a normal "error page" ( path based )
   	if( errorServlet==null && errorPath != null ) {
   	    try {
  -		RequestDispatcher rd = ctx.getRequestDispatcher(errorPath);
  +		RequestDispatcher rd = ctx.getFacade().getRequestDispatcher(errorPath);
   		// reset the response, keeping the status code if necessary
   		// try a forward if possible, otherwise an include
   		if (res.isBufferCommitted()) {
  
  
  
  1.2       +1 -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.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- HttpServletRequestFacade.java	2000/05/23 16:56:51	1.1
  +++ HttpServletRequestFacade.java	2000/05/23 20:58:22	1.2
  @@ -288,7 +288,7 @@
   	    if( path==null) return null;
   	}
   
  -	return request.getContext().getRequestDispatcher(path);
  +	return request.getContext().getFacade().getRequestDispatcher(path);
       }
   
       /** Adapter: first elelment
  
  
  
  1.2       +18 -2     jakarta-tomcat/src/share/org/apache/tomcat/facade/ServletContextFacade.java
  
  Index: ServletContextFacade.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/facade/ServletContextFacade.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ServletContextFacade.java	2000/05/23 16:56:52	1.1
  +++ ServletContextFacade.java	2000/05/23 20:58:22	1.2
  @@ -150,11 +150,27 @@
       }
   
       public RequestDispatcher getRequestDispatcher(String path) {
  -	return context.getRequestDispatcher( path );
  +	if ( path == null  || ! path.startsWith("/")) {
  +	    return null; // spec say "return null if we can't return a dispather
  +	}
  +	RequestDispatcherImpl rD=new RequestDispatcherImpl( context );
  +	rD.setPath( path );
  +	
  +	return rD;
       }
   
       public RequestDispatcher getNamedDispatcher(String name) {
  -	return context.getNamedDispatcher( name );
  +        if (name == null)
  +	    return null;
  +
  +	// We need to do the checks
  +	ServletWrapper wrapper = context.getServletByName( name );
  +	if (wrapper == null)
  +	    return null;
  +	RequestDispatcherImpl rD=new RequestDispatcherImpl( context );
  +	rD.setName( name );
  +
  +	return rD;
       }
   
       public String getServerInfo() {
  
  
  
  1.18      +6 -6      jakarta-tomcat/src/share/org/apache/tomcat/service/Ajp11ConnectionHandler.java
  
  Index: Ajp11ConnectionHandler.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/Ajp11ConnectionHandler.java,v
  retrieving revision 1.17
  retrieving revision 1.18
  diff -u -r1.17 -r1.18
  --- Ajp11ConnectionHandler.java	2000/04/25 17:54:20	1.17
  +++ Ajp11ConnectionHandler.java	2000/05/23 20:58:23	1.18
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/Ajp11ConnectionHandler.java,v 1.17 2000/04/25 17:54:20 costin Exp $
  - * $Revision: 1.17 $
  - * $Date: 2000/04/25 17:54:20 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/Ajp11ConnectionHandler.java,v 1.18 2000/05/23 20:58:23 costin Exp $
  + * $Revision: 1.18 $
  + * $Date: 2000/05/23 20:58:23 $
    *
    * ====================================================================
    *
  @@ -312,9 +312,9 @@
       /** Override setStatus
        */
       public void sendStatus( int status, String message) throws IOException {
  -	statusSB.setLength(0);
  -	statusSB.append("Status: " ).append( status ).append("\r\n");
  -	sout.write(statusSB.toString().getBytes());
  +	printHead("Status: " );
  +	printHead( String.valueOf( status ));
  +	printHead("\r\n");
       }
   }
   
  
  
  
  1.25      +5 -5      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.24
  retrieving revision 1.25
  diff -u -r1.24 -r1.25
  --- Ajp12ConnectionHandler.java	2000/04/25 17:54:23	1.24
  +++ Ajp12ConnectionHandler.java	2000/05/23 20:58:24	1.25
  @@ -496,11 +496,11 @@
       /** Override setStatus
        */
       protected void sendStatus( int status, String message)  throws IOException {
  -	///*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();}
  -	statusSB.setLength(0);
  -	statusSB.append("Status: " ).append( status ).append(" ").append(message).append("\r\n");
  -	sout.write(statusSB.toString().getBytes());
  -	statusSB.setLength(0);
  +	printHead("Status: " );
  +	printHead( String.valueOf( status ));
  +	printHead( " " );
  +	printHead( message );
  +	printHead("\r\n");
       }
   }
   
  
  
  
  1.9       +60 -34    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.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- HttpResponseAdapter.java	2000/04/25 17:54:26	1.8
  +++ HttpResponseAdapter.java	2000/05/23 20:58:25	1.9
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpResponseAdapter.java,v 1.8 2000/04/25 17:54:26 costin Exp $
  - * $Revision: 1.8 $
  - * $Date: 2000/04/25 17:54:26 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpResponseAdapter.java,v 1.9 2000/05/23 20:58:25 costin Exp $
  + * $Revision: 1.9 $
  + * $Date: 2000/05/23 20:58:25 $
    *
    * ====================================================================
    *
  @@ -82,21 +82,17 @@
   public class HttpResponseAdapter extends  ResponseImpl {
       protected OutputStream sout;
   
  -    // no need to create new objects/request,
  -    // avoid extra String creation
  -    protected StringBuffer statusSB;
  -    protected StringBuffer headersSB;
  -
  +    protected static final int DEFAULT_HEAD_BUFFER_SIZE = 1024;
  +    protected byte[] buffer = new byte[DEFAULT_HEAD_BUFFER_SIZE];
  +    protected int bufferCount = 0;
  +    
       public HttpResponseAdapter() {
           super();
  -	statusSB=new StringBuffer();
  -	headersSB=new StringBuffer();
       }
   
       public void recycle() {
   	super.recycle();
  -	statusSB.setLength(0);
  -	headersSB.setLength(0);
  +	bufferCount=0;
       }
   
       public void setOutputStream(OutputStream os) {
  @@ -110,23 +106,21 @@
   	
   	sendStatus( status, ResponseImpl.getMessage( status ));
   
  -	Enumeration e = headers.names();
  -	while (e.hasMoreElements()) {
  -	    String name = (String)e.nextElement();
  -	    String values[] = headers.getHeaders(name);
  -	    for( int i=0; i< values.length; i++ ) {
  -		String value=values[i];
  -		headersSB.setLength(0);
  -		headersSB.append(name).append(": ").append(value).append("\r\n");
  -		//		try {
  -		sout.write( headersSB.toString().getBytes(Constants.CharacterEncoding.Default) );
  -		//		} catch( IOException ex ) {
  -		//		    ex.printStackTrace();
  -		//XXX mark the error - should abandon everything 
  -		//}
  -	    }
  +	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
  +	    printHead( field.getName() );
  +	    printHead(": ");
  +	    printHead( field.getValue() );
  +	    printHead("\r\n");
   	}
  -	sout.write( CRLF, 0, 2 );
  +	
  +	printHead( "\r\n" );
  +
  +	sout.write( buffer, 0, bufferCount );
   	sout.flush();
       }
   
  @@ -134,15 +128,47 @@
   	HTTP response is the status line
       */
       protected void sendStatus( int status, String message ) throws IOException {
  -	// statusSB.reset();
  -	statusSB.append("HTTP/1.0 ").append(status);
  -	if(message!=null) statusSB.append(" ").append(message);
  -	statusSB.append("\r\n");
  -	sout.write(statusSB.toString().getBytes(Constants.CharacterEncoding.Default));
  -	statusSB.setLength(0);
  +	printHead("HTTP/1.0 ");
  +	printHead(String.valueOf(status));
  +	if(message!=null) {
  +	    printHead(" ");
  +	    printHead(message);
  +	}
  +	printHead("\r\n");
       }
   
       public void doWrite( byte buffer[], int pos, int count) throws IOException {
   	sout.write( buffer, pos, count);
       }
  +
  +    // From BufferedServletOutputStream
  +    // XXX will be moved in a new in/out system, temp. code
  +    // Right now it's not worse than BOS
  +    protected void printHead( 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 >= buffer.length ) {
  +		byte bufferNew[]=new byte[ buffer.length * 2 ];
  +		System.arraycopy( buffer,0, bufferNew, 0, buffer.length );
  +		buffer=bufferNew;
  +	    }
  +	    buffer[bufferCount] = (byte)c;
  +	    bufferCount++;
  +	}	
  +    }
  +					
   }
  
  
  
  1.2       +3 -4      jakarta-tomcat/src/share/org/apache/tomcat/util/MessageString.java
  
  Index: MessageString.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/MessageString.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- MessageString.java	1999/10/09 00:20:56	1.1
  +++ MessageString.java	2000/05/23 20:58:26	1.2
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/MessageString.java,v 1.1 1999/10/09 00:20:56 duncan Exp $
  - * $Revision: 1.1 $
  - * $Date: 1999/10/09 00:20:56 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/MessageString.java,v 1.2 2000/05/23 20:58:26 costin Exp $
  + * $Revision: 1.2 $
  + * $Date: 2000/05/23 20:58:26 $
    *
    * ====================================================================
    *
  @@ -75,7 +75,6 @@
    *
    * @author dac@eng.sun.com
    */
  -
   public class MessageString extends MessageBytes {
       /**
        * The message String.
  
  
  
  1.5       +14 -34    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.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- MimeHeaderField.java	2000/05/02 19:58:41	1.4
  +++ MimeHeaderField.java	2000/05/23 20:58:27	1.5
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/MimeHeaderField.java,v 1.4 2000/05/02 19:58:41 costin Exp $
  - * $Revision: 1.4 $
  - * $Date: 2000/05/02 19:58:41 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/MimeHeaderField.java,v 1.5 2000/05/23 20:58:27 costin Exp $
  + * $Revision: 1.5 $
  + * $Date: 2000/05/23 20:58:27 $
    *
    * ====================================================================
    *
  @@ -70,11 +70,18 @@
   
   /**
    * This class is used to represent a MIME header field.
  + * It uses MessageString, and can be used in 0-GC mode ( no
  + * garbage generated unless toString() is called )
    *
  + *
    * @author dac@eng.sun.com
    * @author James Todd [gonzo@eng.sun.com]
    */
   public class MimeHeaderField {
  +    public static final byte[] charval = { 
  +	(byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4',
  +	(byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9' 
  +    };
   
       private StringManager sm =
           StringManager.getManager("org.apache.tomcat.util");
  @@ -82,31 +89,26 @@
       /**
        * The header field name.
        */
  -
       protected final MessageString name = new MessageString();
   
       /**
        * The header field value.
        */
  -
       protected final MessageString value = new MessageString();
   
       /**
        * The header field integer value.
        */
  -
       protected int intValue;
   
       /**
        * The header field Date value.
        */
  -    
       protected final HttpDate dateValue = new HttpDate(0);
   
       /**
        * The header field value type.
        */
  -
       protected int type = T_NULL;
   
       protected static final int T_NULL = 0;
  @@ -114,22 +116,15 @@
       protected static final int T_INT  = 2;
       protected static final int T_DATE = 3;
   
  -    private static final byte[] charval = { 
  -	(byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4',
  -	(byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9' 
  -    };
  -
       /**
        * Creates a new, uninitialized header field.
        */
  -
       public MimeHeaderField() {
       }
   
       /**
        * Resets the header field to an uninitialized state.
        */
  -
       public void reset() {
   	name.reset();
   	value.reset();
  @@ -140,7 +135,6 @@
        * Sets the header field name to the specified string.
        * @param s the header field name String
        */
  -
       public void setName(String s) {
   	name.setString(s);
       }
  @@ -151,7 +145,6 @@
        * @param off the start offset of the bytes
        * @param len the length of the bytes
        */
  -
       public void setName(byte[] b, int off, int len) {
   	name.setBytes(b, off, len);
       }
  @@ -160,7 +153,6 @@
        * Sets the header field value to the specified string.
        * @param s the header field value String
        */
  -
       public void setValue(String s) {
   	value.setString(s);
   	type = T_STR;
  @@ -172,7 +164,6 @@
        * @param off the start offset of the bytes
        * @param len the length of the bytes
        */
  -
       public void setValue(byte[] b, int off, int len) {
   	value.setBytes(b, off, len);
   	type = T_STR;
  @@ -182,7 +173,6 @@
        * Sets the header field to the specified integer value.
        * @param i the header field integer value
        */
  -
       public void setIntValue(int i) {
   	intValue = i;
   	type = T_INT;
  @@ -192,7 +182,6 @@
        * Sets the header field date value to the specified time.
        * @param t the time in milliseconds since the epoch
        */
  -
       public void setDateValue(long t) {
   	dateValue.setTime(t);
   	type = T_DATE;
  @@ -201,7 +190,6 @@
       /**
        * Sets the header field date value to the current time.
        */
  -
       public void setDateValue() {
   	dateValue.setTime();
   	type = T_DATE;
  @@ -210,7 +198,6 @@
       /**
        * Returns the header field name as a String.
        */
  -
       public String getName() {
   	return name.toString();
       }
  @@ -218,7 +205,6 @@
       /**
        * Returns the header field value as a String, or null if not set.
        */
  -
       public String getValue() {
   	switch (type) {
   	case T_STR:
  @@ -238,7 +224,8 @@
        */
   
       public int getIntValue()
  -    throws NumberFormatException {
  +	throws NumberFormatException
  +    {
   	switch (type) {
   	case T_INT:
   	    return intValue;
  @@ -256,9 +243,9 @@
        * @return the header date value in number of milliseconds since the epoch
        * @exception IllegalArgumentException if the date format was invalid
        */
  -
       public long getDateValue()
  -    throws IllegalArgumentException {
  +	throws IllegalArgumentException
  +    {
   	switch (type) {
   	case T_DATE:
   	    return dateValue.getTime();
  @@ -276,7 +263,6 @@
        * @param target - the integer to convert.  Must be in the range [0..2^31].
        * @return the number of bytes added to buf
        */
  -
       private int intGetBytes(int target, byte buf[], int offset) {
   	int power = 1000000000;  // magnitude of highest digit we can handle
   	int this_digit;
  @@ -309,7 +295,6 @@
        * Put the bytes for this header into buf starting at offset buf_offset.
        * @return the length of what was added
        */
  -
       public int getBytes(byte buf[], int buf_offset) {
   	int len;
   	int start_pt = buf_offset;
  @@ -356,7 +341,6 @@
        * @param len the length of the bytes
        * @exception IllegalArgumentException if the header format was invalid
        */
  -
       public boolean parse(byte[] b, int off, int len)
       {
   	int start = off;
  @@ -389,7 +373,6 @@
       /**
        * Writes this header field to the specified servlet output stream.
        */
  -
       public void write(ServletOutputStream out)
       throws IOException {
   	name.write(out);
  @@ -417,7 +400,6 @@
        * case is ignored in the comparison.
        * @param s the string to compare
        */
  -
       public boolean nameEquals(String s) {
   	return name.equalsIgnoreCase(s);
       }
  @@ -429,7 +411,6 @@
        * @param off the start offset of the bytes
        * @param len the length of the bytes
        */
  -
       public boolean nameEquals(byte[] b, int off, int len) {
   	return name.equalsIgnoreCase(b, off, len);
       }
  @@ -437,7 +418,6 @@
       /**
        * Returns a string representation of the header field.
        */
  -
       public String toString() {
   	StringBuffer sb = new StringBuffer();
   
  
  
  
  1.6       +164 -163  jakarta-tomcat/src/share/org/apache/tomcat/util/MimeHeaders.java
  
  Index: MimeHeaders.java
  ===================================================================
  RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/MimeHeaders.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- MimeHeaders.java	2000/05/23 16:57:08	1.5
  +++ MimeHeaders.java	2000/05/23 20:58:27	1.6
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/MimeHeaders.java,v 1.5 2000/05/23 16:57:08 costin Exp $
  - * $Revision: 1.5 $
  - * $Date: 2000/05/23 16:57:08 $
  + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/MimeHeaders.java,v 1.6 2000/05/23 20:58:27 costin Exp $
  + * $Revision: 1.6 $
  + * $Date: 2000/05/23 20:58:27 $
    *
    * ====================================================================
    *
  @@ -96,48 +96,51 @@
    * only available as strings.  They may be accessed by index (treating
    * the header as an array of fields), or by name (returning an array
    * of string values).
  + */
  +
  +/**
  + *  Memory-efficient repository for Mime Headers. When the object is recycled, it
  + *  will keep the allocated headers[] and all the MimeHeaderField - no GC is generated.
    *
  + *  For input headers it is possible to use the MessageByte for Fileds - so no GC
  + *  will be generated.
  + *
  + *  The only garbage is generated when using the String for header names/values -
  + *  this can't be avoided when the servlet calls header methods, but is easy
  + *  to avoid inside tomcat. The goal is to use _only_ MessageByte-based Fields,
  + *  and reduce to 0 the memory overhead of tomcat.
  + *
  + *  TODO:
  + *  XXX one-buffer parsing - for http ( other protocols don't need that )
  + *  XXX remove unused methods
  + *  XXX External enumerations, with 0 GC.
  + *  XXX use HeaderName ID
  + *  
  + * 
    * @author dac@eng.sun.com
    * @author James Todd [gonzo@eng.sun.com]
  + * @author Costin Manolache
    */
  -
   public class MimeHeaders {
  -
  -    private StringManager sm =
  -        StringManager.getManager("org.apache.tomcat.util");
  -
  +    /** Initial size - should be == average number of headers per request
  +     *  XXX  make it configurable ( fine-tuning of web-apps )
  +     */
  +    public static final int DEFAULT_HEADER_SIZE=8;
  +    
       /**
        * The header fields.
        */
  -
  -    private MimeHeaderField[] headers = new MimeHeaderField[8];
  +    private MimeHeaderField[] headers = new MimeHeaderField[DEFAULT_HEADER_SIZE];
   
       /**
        * The current number of header fields.
        */
  -
       private int count;
   
       /**
  -     * A buffer used when parsing headers.
  -     */
  -
  -    private byte[] buf;
  -
  -    /**
  -     * Creates a new MimeHeaders object using the specified buffer size.
  -     * @param len the buffer size initially used for parsing headers
  -     */
  -
  -    public MimeHeaders(int len) {
  -	buf = new byte[len];
  -    }
  -
  -    /**
        * Creates a new MimeHeaders object using a default buffer size.
        */
       public MimeHeaders() {
  -	this(512);
       }
   
       /**
  @@ -153,17 +156,83 @@
       /**
        * Returns the current number of header fields.
        */
  -
       public int size() {
   	return count;
       }
   
       /**
  +     * Returns the Nth header field, or null if there is no such header.
  +     * This may be used to iterate through all header fields.
  +     */
  +    public MimeHeaderField getField(int n) {
  +	return n >= 0 && n < count ? headers[n] : null;
  +    }
  +
  +    
  +    /**
  +     * Finds and returns a header field with the given name.  If no such
  +     * field exists, null is returned.  If more than one such field is
  +     * in the header, an arbitrary one is returned.
  +     */
  +    public MimeHeaderField find(String name) {
  +        for (int i = 0; i < count; i++) {
  +	    if (headers[i].nameEquals(name)) {
  +                return headers[i];
  +            }
  +        }
  +        return null;
  +    }
  +
  +    /**
  +     * Adds a partially constructed field to the header.  This
  +     * field has not had its name or value initialized.
  +     */
  +    public MimeHeaderField putHeader() {
  +	MimeHeaderField mh;
  +	int len = headers.length;
  +	if (count >= len) {
  +	    // expand header list array
  +	    MimeHeaderField tmp[] = new MimeHeaderField[count * 2];
  +	    System.arraycopy(headers, 0, tmp, 0, len);
  +	    headers = tmp;
  +	}
  +	if ((mh = headers[count]) == null) {
  +	    headers[count] = mh = new MimeHeaderField();
  +	}
  +	count++;
  +	return mh;
  +    }
  +
  +
  +    
  +    
  +    // -------------------- 
  +    // Please avoid using any of the methods following this line. 
  +    // ( most of them will generate GC, or are http sepecific )
  +    // ------------------------------------------------------------
  +    private StringManager sm =
  +        StringManager.getManager("org.apache.tomcat.util");
  +    int bufSize=512; // default
  +    /**
  +     * A buffer used when parsing headers.
  +     */
  +    private byte[] buf=null;
  +
  +    
  +    /**
  +     * Creates a new MimeHeaders object using the specified buffer size.
  +     * @param len the buffer size initially used for parsing headers
  +     */
  +    public MimeHeaders(int len) {
  +	bufSize=len;
  +	// buf = new byte[len];
  +    }
  +
  +    /**
        * Returns an enumeration of strings representing the header field names.
        * Field names may appear multiple times in this enumeration, indicating
        * that multiple fields with that name exist in this header.
        */
  -
       public Enumeration names() {
   	return new MimeHeadersEnumerator(this);
       }
  @@ -177,7 +246,6 @@
        * @param name the header name
        * @param s the header field string value
        */
  -
       public void putHeader(String name, String s) {
   	putHeader(name).setValue(s);
       }
  @@ -191,7 +259,6 @@
        * @param name the header name
        * @param i the header field integer value
        */
  -
       public void putIntHeader(String name, int i) {
   	putHeader(name).setIntValue(i);
       }
  @@ -206,7 +273,6 @@
        * @param name the header name
        * @param t the time in number of milliseconds since the epoch
        */
  -
       public void putDateHeader(String name, long t) {
   	putHeader(name).setDateValue(t);
       }
  @@ -219,7 +285,6 @@
        * Creates a new header field whose value is the current date and time.
        * @param name the header name
        */
  -
       public void putDateHeader(String name) {
   	putHeader(name).setDateValue();
       }
  @@ -235,7 +300,6 @@
        * @param name the header field name
        * @return the string value of the field, or null if none found
        */
  -
       public String getHeader(String name) {
   	MimeHeaderField mh = find(name);
   
  @@ -249,7 +313,6 @@
        * @param name the header field name
        * @return array values of the fields, or null if none found
        */
  -
       public String[] getHeaders(String name) {
   	Vector values = getHeadersVector(name);
   
  @@ -297,7 +360,6 @@
        *	       since the epoch, or -1 if the header was not found
        * @exception IllegalArgumentException if the date format was invalid
        */
  -
       public long getDateHeader(String name) throws IllegalArgumentException {
   	MimeHeaderField mh = find(name);
   
  @@ -309,7 +371,6 @@
        * if there were fewer than (n + 1) fields. This can be used to iterate
        * through all the fields in the header.
        */
  -
       public String getHeaderName(int n) {
   	return n >= 0 && n < count ? headers[n].getName() : null;
       }
  @@ -319,24 +380,13 @@
        * if there were fewer than (n + 1) fields. This can be used along
        * with getHeaderName to iterate through all the fields in the header.
        */
  -
       public String getHeader(int n) {
   	return n >= 0 && n < count ? headers[n].getValue() : null;
       }
   
       /**
  -     * Returns the Nth header field, or null if there is no such header.
  -     * This may be used to iterate through all header fields.
  -     */
  -
  -    public MimeHeaderField getField(int n) {
  -	return n >= 0 && n < count ? headers[n] : null;
  -    }
  -
  -    /**
        * Returns the number of fields using a given field name.
        */
  -
       public int getFieldCount (String name) {
   	int retval = 0;
   
  @@ -348,27 +398,10 @@
       }
   
       /**
  -     * Finds and returns a header field with the given name.  If no such
  -     * field exists, null is returned.  If more than one such field is
  -     * in the header, an arbitrary one is returned.
  -     */
  -
  -    protected MimeHeaderField find(String name) {
  -        for (int i = 0; i < count; i++) {
  -	    if (headers[i].nameEquals(name)) {
  -                return headers[i];
  -            }
  -        }
  -
  -        return null;
  -    }
  -
  -    /**
        * Removes a header field with the specified name.  Does nothing
        * if such a field could not be found.
        * @param name the name of the header field to be removed
        */
  -
       public void removeHeader(String name) {
           // XXX
           // warning: rather sticky code; heavily tuned
  @@ -393,24 +426,87 @@
        * otherwise returns false.
        * @param name the field name
        */
  -
       public boolean containsHeader(String name) {
   	return find(name) != null;
       }
   
       /**
  +     * Writes out header fields to the specified servlet output stream.
  +     * @param out the servlet output stream
  +     * @exception IOException if an I/O error has occurred
  +     */
  +    public void write(ServletOutputStream out) throws IOException {
  +	for (int i = 0; i < count; i++) {
  +	    headers[i].write(out);
  +	}
  +
  +	out.println();
  +    }
  +
  +    /**
  +     * Finds a header field given name.  If the header doesn't exist,
  +     * it will create a new one.
  +     * @param name the header field name
  +     * @return the new field
  +     */
  +    protected MimeHeaderField putHeader(String name) {
  +        if (containsHeader(name)) {
  +	    removeHeader(name);
  +	}
  +
  +	return addHeader(name);
  +    }
  +
  +    protected MimeHeaderField addHeader(String name) {
  + 	MimeHeaderField mh = putHeader();
  +
  +	mh.setName(name);
  +
  +	return mh;
  +    }
  +    
  +    /**
  +     * Creates a new header with given name, and add it to the headers.
  +     * @param name the header field name
  +     * @param s the header value
  +     * @return the new field
  +     */
  +    public void appendHeader(String name, String s) {
  +	MimeHeaderField mh = putHeader();
  +
  +	mh.setName(name);
  +	mh.setValue(s);
  +    }
  +    
  +    /** 
  +     * Get the current header fields in the byte array buf.  The headers
  +     * fields are placed starting at offset buf_offset.  
  +     * @return the number of bytes written into buf.
  +     */
  +    public int getAll(byte buf[], int buf_offset) {
  +	int start_pt = buf_offset;
  +
  +	for (int i = 0; i < count; i++) {
  +	    buf_offset += headers[i].getBytes(buf, buf_offset);
  +	}
  +
  +	return buf_offset - start_pt;
  +    }
  +
  +    
  +    /**
        * 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 void read(ServletInputStream in) throws IOException {
   	// use pre-allocated buffer if possible
   	byte[] b;
   
   	if (count == 0) {
  +	    if( buf==null ) buf=new byte[bufSize];
   	    b = buf;
   	} else {
   	    b = new byte[buf.length];
  @@ -459,113 +555,17 @@
   	    
   	    // XXX this does not currently handle headers which
   	    // are folded to take more than one line.
  -	    
   	    MimeHeaderField mhf=putHeader();
   	    if( ! mhf.parse(b, start, off - start) ) {
   		// error parsing header
   		return;
   	    }
  -	    
   	}
       }
   
       /**
  -     * Writes out header fields to the specified servlet output stream.
  -     * @param out the servlet output stream
  -     * @exception IOException if an I/O error has occurred
  -     */
  -
  -    public void write(ServletOutputStream out) throws IOException {
  -	for (int i = 0; i < count; i++) {
  -	    headers[i].write(out);
  -	}
  -
  -	out.println();
  -    }
  -
  -    /**
  -     * Finds a header field given name.  If the header doesn't exist,
  -     * it will create a new one.
  -     * @param name the header field name
  -     * @return the new field
  -     */
  -
  -    protected MimeHeaderField putHeader(String name) {
  -        if (containsHeader(name)) {
  -	    removeHeader(name);
  -	}
  -
  -	return addHeader(name);
  -    }
  -
  -    protected MimeHeaderField addHeader(String name) {
  - 	MimeHeaderField mh = putHeader();
  -
  -	mh.setName(name);
  -
  -	return mh;
  -    }
  -    
  -    /**
  -     * Creates a new header with given name, and add it to the headers.
  -     * @param name the header field name
  -     * @param s the header value
  -     * @return the new field
  -     */
  -
  -    public void appendHeader(String name, String s) {
  -	MimeHeaderField mh = putHeader();
  -
  -	mh.setName(name);
  -	mh.setValue(s);
  -    }
  -    
  -    /**
  -     * Adds a partially constructed field to the header.  This
  -     * field has not had its name or value initialized.
  -     */
  -
  -    protected MimeHeaderField putHeader() {
  -	MimeHeaderField mh;
  -	int len = headers.length;
  -
  -	if (count >= len) {
  -	    // expand header list array
  -	    MimeHeaderField tmp[] = new MimeHeaderField[count * 2];
  -
  -	    System.arraycopy(headers, 0, tmp, 0, len);
  -	    headers = tmp;
  -	}
  -
  -	if ((mh = headers[count]) == null) {
  -	    headers[count] = mh = new MimeHeaderField();
  -	}
  -
  -	count++;
  -
  -	return mh;
  -    }
  -
  -    /** 
  -     * Get the current header fields in the byte array buf.  The headers
  -     * fields are placed starting at offset buf_offset.  
  -     * @return the number of bytes written into buf.
  -     */
  -
  -    public int getAll(byte buf[], int buf_offset) {
  -	int start_pt = buf_offset;
  -
  -	for (int i = 0; i < count; i++) {
  -	    buf_offset += headers[i].getBytes(buf, buf_offset);
  -	}
  -
  -	return buf_offset - start_pt;
  -    }
  -
  -    /**
        * Returns a lengthly string representation of the current header fields.
        */
  -
       public String toString() {
   	StringBuffer sb = new StringBuffer();
   
  @@ -628,3 +628,4 @@
   	}
       }
   }
  +