costin      00/11/30 09:42:49

  Added:       src/share/org/apache/tomcat/util/http Cookies.java
                        Headers.java Parameters.java ServerCookie.java
                        package.html
  Log:
  Start work on Cookies, Parameters, Headers.
  
  The code in Cookies is almost ready, all cookie processing was re-done
  from scratch - and will support the full spec, not only name/values.
  It'll also be much faster, and the object model is better ( no need
  for artificial "helpers").
  
  Parameter parsing is also rewritten ( and more efficient ).
  
  Both Parameters and Cookies are now (almost) GC-free. The code will be more
  eficient if there are only few cookies/parameters (2..10 ?), for requests
  with many params we'll add the optimizations later.
  
  The code is not used right now - it'll gradually move in.
  
  Revision  Changes    Path
  1.1                  
jakarta-tomcat/src/share/org/apache/tomcat/util/http/Cookies.java
  
  Index: Cookies.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 [EMAIL PROTECTED]
   *
   * 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.http;
  
  import org.apache.tomcat.util.collections.*;
  import org.apache.tomcat.util.MessageBytes;
  import org.apache.tomcat.util.MimeHeaders;
  import org.apache.tomcat.util.ServerCookie;
  import org.apache.tomcat.util.DateTool;
  
  import java.io.*;
  import java.util.*;
  import java.text.*;
  
  /**
   * A collection of cookies - reusable and tuned for server side performance.
   * 
   * @author Costin Manolache
   */
  public final class Cookies { // extends MultiMap {
  
      // expected average number of cookies per request
      public static final int INITIAL_SIZE=4; 
      ServerCookie scookies[]=new ServerCookie[INITIAL_SIZE];
      int cookieCount=-1; // -1 = cookies not processed yet
  
      MimeHeaders headers;
      
      /**
       * 
       */
      public Cookies() {
      }
  
      public void recycle() {
        for( int i=0; i< cookieCount; i++ ) {
            if( scookies[i]!=null )
                scookies[i].recycle();
        }
        cookieCount=-1;
      }
  
      public ServerCookie getCookie( int idx ) {
        if( cookieCount == -1 ) {
            getCookieCount(); // will also update the cookies
        }
        return scookies[idx];
      }
  
      public int getCookieCount() {
        if( cookieCount == -1 ) {
            cookieCount=0;
            // compute cookies
            processCookies(headers);
        }
        return cookieCount;
      }
  
      public ServerCookie addCookie() {
        if( cookieCount >= scookies.length  ) {
            ServerCookie scookiesTmp[]=new ServerCookie[2*cookieCount];
            System.arraycopy( scookies, 0, scookiesTmp, 0, cookieCount);
            scookies=scookiesTmp;
        }
        
        ServerCookie c = scookies[cookieCount];
        if( c==null ) {
            c= new ServerCookie();
            scookies[cookieCount]=c;
        }
        cookieCount++;
        return c;
      }
  
  
      // -------------------- Static methods ( used to be CookieTools )
  
      /** Process all Cookie headers of a request, setting them
       *  in a cookie vector
       */
      public  void processCookies( MimeHeaders headers ) {
        // process each "cookie" header
        int pos=0;
        while( pos>=0 ) {
            pos=headers.findHeader( "Cookie", pos );
            // no more cookie headers headers
            if( pos<0 ) break;
  
            MessageBytes cookieValue=headers.getValue( pos );
            if( cookieValue==null || cookieValue.isNull() ) continue;
            if( cookieValue.getType() == MessageBytes.T_BYTES ) {
                processCookieHeader( cookieValue.getBytes(),
                                     cookieValue.getOffset(),
                                     cookieValue.getLength());
            } else {
                processCookieHeader( cookieValue.toString() );
            }
        }
      }
  
      private  void processCookieHeader(  byte bytes[], int off, int len )
      {
        if( len<=0 || bytes==null ) return;
        int end=off+len;
        int pos=off;
  
        while( true ) {
            // [ skip_spaces name skip_spaces "=" skip_spaces value EXTRA ; ] *
            
            int startName=skipSpaces(bytes, pos, end);
            if( pos>=end )
                return; // only spaces
            
            boolean isSpecial=false;
            if(bytes[pos]=='$') { pos++; isSpecial=true; }
            
            int endName= findDelim1( bytes, startName, end); // " =;,"
            if(endName >= end )
                return; // invalid
        
            // current = "=" or " " 
            pos= skipSpaces( bytes, endName, end );
            if(endName >= end )
                return; // invalid
  
            // cookie without value
            if( bytes[pos] == ';' || bytes[pos]==',' ) {
                // add cookie
  
                // we may have more cookies
                continue;
            }
  
            if( bytes[pos] != '=' ) {
                // syntax error - ignore the rest
                // ( we could also skip to the next ';' )
                return;
            }
        
            // we must have "="
            pos++;
            int startValue=skipSpaces( bytes, pos, end);
            int endValue=startValue;
            if( bytes[pos]== '\'' || bytes[pos]=='"' ) {
                startValue++;
                endValue=indexOf( bytes, startValue, end, bytes[startValue] );
            } else {
                endValue=findDelim2( bytes, startValue, end );
            }
  
            // process $Version, etc
            if( ! isSpecial ) {
                ServerCookie sc=addCookie();
                sc.getName().setBytes( bytes, startName, endName );
                sc.getValue().setBytes( bytes, startValue, endValue );
                continue;
            }
            // special - Path, Version, Domain
            // XXX TODO
        }
      }
  
      // -------------------- Utils --------------------
      public static int skipSpaces(  byte bytes[], int off, int end ) {
        while( off < end ) {
            byte b=bytes[off];
            if( b!= ' ' ) return off;
            off ++;
        }
        return off;
      }
  
      public static int findDelim1( byte bytes[], int off, int end )
      {
        while( off < end ) {
            byte b=bytes[off];
            if( b==' ' || b=='=' || b==';' || b==',' )
                return off;
            off++;
        }
        return off;
      }
  
      public static int findDelim2( byte bytes[], int off, int end )
      {
        while( off < end ) {
            byte b=bytes[off];
            if( b==' ' || b==';' || b==',' )
                return off;
            off++;
        }
        return off;
      }
  
      public static int indexOf( byte bytes[], int off, int end, byte qq )
      {
        while( off < end ) {
            byte b=bytes[off];
            if( b==qq )
                return off;
            off++;
        }
        return off;
      }
  
      public static int indexOf( byte bytes[], int off, int end, char qq )
      {
        while( off < end ) {
            byte b=bytes[off];
            if( b==qq )
                return off;
            off++;
        }
        return off;
      }
      
  
      // ---------------------------------------------------------
      // -------------------- DEPRECATED, OLD --------------------
      
      private void processCookieHeader(  String cookieString )
      {
        
        // normal cookie, with a string value.
        // This is the original code, un-optimized - it shouldn't
        // happen in normal case
  
        StringTokenizer tok = new StringTokenizer(cookieString,
                                                  ";", false);
        while (tok.hasMoreTokens()) {
            String token = tok.nextToken();
            int i = token.indexOf("=");
            if (i > -1) {
                
                // XXX
                // the trims here are a *hack* -- this should
                // be more properly fixed to be spec compliant
                
                String name = token.substring(0, i).trim();
                String value = token.substring(i+1, token.length()).trim();
                // RFC 2109 and bug 
                value=stripQuote( value );
                ServerCookie cookie = addCookie();
                
                cookie.getName().setString(name);
                cookie.getValue().setString(value);
            } else {
                // we have a bad cookie.... just let it go
            }
        }
      }
  
      /**
       *
       * Strips quotes from the start and end of the cookie string
       * This conforms to RFC 2109
       * 
       * @param value            a <code>String</code> specifying the cookie 
       *                         value (possibly quoted).
       *
       * @see #setValue
       *
       */
      private static String stripQuote( String value )
      {
        //      log("Strip quote from " + value );
        if (((value.startsWith("\"")) && (value.endsWith("\""))) ||
            ((value.startsWith("'") && (value.endsWith("'"))))) {
            try {
                return value.substring(1,value.length()-1);
            } catch (Exception ex) { 
            }
        }
        return value;
      }  
  
  
  
  }
  
  
  
  1.1                  
jakarta-tomcat/src/share/org/apache/tomcat/util/http/Headers.java
  
  Index: Headers.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 [EMAIL PROTECTED]
   *
   * 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.http;
  
  import org.apache.tomcat.util.collections.*;
  import org.apache.tomcat.util.MessageBytes;
  
  import java.io.*;
  import java.util.*;
  import java.text.*;
  
  // XXX many methods should be deprecated and removed after
  // the core is changed. 
  
  /**
   * 
   * @author [EMAIL PROTECTED]
   * @author James Todd [[EMAIL PROTECTED]]
   * @author Costin Manolache
   */
  public class Headers extends MultiMap {
      
      /** 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;
      
      /**
       * Creates a new MimeHeaders object using a default buffer size.
       */
      public Headers() {
        super( DEFAULT_HEADER_SIZE );
      }
  
      // Old names
      
      /**
       * Clears all header fields.
       */
      public void clear() {
        super.recycle();
      }
  
      /** Find the index of a header with the given name.
       */
      public int findHeader( String name, int starting ) {
        return super.findIgnoreCase( name, starting );
      }
      
      // -------------------- --------------------
  
      /**
       * 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 NamesEnumerator(this);
      }
  
      public Enumeration values(String name) {
        return new ValuesEnumerator(this, name);
      }
  
      // -------------------- Adding headers --------------------
      
      /** Create a new named header , return the MessageBytes
       *  container for the new value
       */
      public MessageBytes addValue( String name ) {
        int pos=addField();
        getName(pos).setString(name);
        return getValue(pos);
      }
  
      /** Create a new named header using un-translated byte[].
        The conversion to chars can be delayed until
        encoding is known.
       */
      public MessageBytes addValue(byte b[], int startN, int endN)
      {
        int pos=addField();
        getName(pos).setBytes(b, startN, endN);
        return getValue(pos);
      }
  
      /** Allow "set" operations - 
          return a MessageBytes container for the
        header value ( existing header or new
        if this .
      */
      public MessageBytes setValue( String name ) {
        MessageBytes value=getValue(name);
        if( value == null ) {
            value=addValue( name );
        }
        return value;
      }
  
      //-------------------- Getting headers --------------------
      /**
       * 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 MessageBytes getValue(String name) {
          int pos=findIgnoreCase( name, 0 );
          if( pos <0 ) return null;
        return getValue( pos );
      }
  
      // bad shortcut - it'll convert to string ( too early probably,
      // encoding is guessed very late )
      public String getHeader(String name) {
        int pos=findIgnoreCase( name, 0 );
        if( pos <0 ) return null;
        MessageBytes mh = getValue(pos);
        return mh.toString();
      }
  
      /**
       * 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) {
        int pos=0;
        while( pos>=0 ) {
            // next header with this name
            pos=findIgnoreCase( name, pos );
            remove( pos );
        }
      }
  }
  
  /** Enumerate the distinct header names.
      Each nextElement() is O(n) ( a comparation is
      done with all previous elements ).
  
      This is less frequesnt than add() -
      we want to keep add O(1).
  */
  class NamesEnumerator implements Enumeration {
      int pos;
      int size;
      String next;
      MultiMap headers;
  
      NamesEnumerator(MultiMap headers) {
        this.headers=headers;
        pos=0;
        size = headers.size();
        findNext();
      }
  
      private void findNext() {
        next=null;
        for(  ; pos< size; pos++ ) {
            next=headers.getName( pos ).toString();
            for( int j=0; j<pos ; j++ ) {
                if( headers.getName( j ).equalsIgnoreCase( next )) {
                    // duplicate.
                    next=null;
                    break;
                }
            }
            if( next!=null ) {
                // it's not a duplicate
                break;
            }
        }
        // next time findNext is called it will try the
        // next element
        pos++;
      }
      
      public boolean hasMoreElements() {
        return next!=null;
      }
  
      public Object nextElement() {
        String current=next;
        findNext();
        return current;
      }
  }
  
  /** Enumerate the values for a (possibly ) multiple
      value element.
  */
  class ValuesEnumerator implements Enumeration {
      int pos;
      int size;
      MessageBytes next;
      MultiMap headers;
      String name;
  
      ValuesEnumerator(MultiMap headers, String name) {
          this.name=name;
        this.headers=headers;
        pos=0;
        size = headers.size();
        findNext();
      }
  
      private void findNext() {
        next=null;
        for( ; pos< size; pos++ ) {
            MessageBytes n1=headers.getName( pos );
            if( n1.equalsIgnoreCase( name )) {
                next=headers.getValue( pos );
                break;
            }
        }
        pos++;
      }
      
      public boolean hasMoreElements() {
        return next!=null;
      }
  
      public Object nextElement() {
        MessageBytes current=next;
        findNext();
        return current.toString();
      }
  }
  
  class MimeHeaderField {
      // multiple headers with same name - a linked list will
      // speed up name enumerations and search ( both cpu and
      // GC)
      MimeHeaderField next;
      MimeHeaderField prev; 
      
      protected final MessageBytes nameB = new MessageBytes();
      protected final MessageBytes valueB = new MessageBytes();
  
      /**
       * Creates a new, uninitialized header field.
       */
      public MimeHeaderField() {
      }
  
      public void recycle() {
        nameB.recycle();
        valueB.recycle();
        next=null;
      }
  
      public MessageBytes getName() {
        return nameB;
      }
  
      public MessageBytes getValue() {
        return valueB;
      }
  }
  
  
  
  1.1                  
jakarta-tomcat/src/share/org/apache/tomcat/util/http/Parameters.java
  
  Index: Parameters.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 [EMAIL PROTECTED]
   *
   * 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.http;
  
  import  org.apache.tomcat.util.*;
  import  org.apache.tomcat.util.collections.*;
  import java.io.*;
  import java.util.*;
  import java.text.*;
  
  /**
   * 
   * @author Costin Manolache
   */
  public final class Parameters extends MultiMap {
      public static final int INITIAL_SIZE=4;
  
      private boolean isSet=false;
      private boolean isFormBased=false;
      
      /**
       * 
       */
      public Parameters() {
        super( INITIAL_SIZE );
      }
  
      public void recycle() {
        super.recycle();
        isSet=false;
        isFormBased=false;
      }
  
      // duplicated
      public static int indexOf( byte bytes[], int off, int end, char qq )
      {
        while( off < end ) {
            byte b=bytes[off];
            if( b==qq )
                return off;
            off++;
        }
        return off;
      }
  
      public static int indexOf( char chars[], int off, int end, char qq )
      {
        while( off < end ) {
            char b=chars[off];
            if( b==qq )
                return off;
            off++;
        }
        return off;
      }
  
      public void processParameters( byte bytes[], int start, int len ) {
        int end=start+len;
        int pos=start;
        
          do {
            int nameStart=pos;
            int nameEnd=indexOf(bytes, nameStart, end, '=' );
            int valStart=nameEnd+1;
            int valEnd=indexOf(bytes, valStart, end, '&');
            
            pos=valEnd+1;
            
            if( nameEnd<=nameStart ) {
                continue;
                // invalid chunk - it's better to ignore
                // XXX log it ?
            }
            
            int field=this.addField();
            this.getName( field ).setBytes( bytes,
                                            nameStart, nameEnd );
            this.getValue( field ).setBytes( bytes,
                                             valStart, valEnd );
        } while( pos<end );
      }
  
      public void processParameters( char chars[], int start, int len ) {
        int end=start+len;
        int pos=start;
        
          do {
            int nameStart=pos;
            int nameEnd=indexOf(chars, nameStart, end, '=' );
            int valStart=nameEnd+1;
            int valEnd=indexOf(chars, valStart, end, '&');
            
            pos=valEnd+1;
            
            if( nameEnd<=nameStart ) {
                continue;
                // invalid chunk - it's better to ignore
                // XXX log it ?
            }
            
            int field=this.addField();
            this.getName( field ).setChars( chars,
                                            nameStart, nameEnd );
            this.getValue( field ).setChars( chars,
                                             valStart, valEnd );
        } while( pos<end );
      }
  
      
      public void processParameters( MessageBytes data ) {
        if( data==null || data.getLength() <= 0 ) return;
  
        if( data.getType() == MessageBytes.T_BYTES ) {
            processParameters( data.getBytes(), data.getOffset(),
                               data.getLength());
        } else {
            processParameters( data.getChars(), data.getOffset(),
                               data.getLength());
        }
      }
  
  
      public void mergeParameters( Parameters extra ) {
        
      }
      
  }
  
  
  
  1.1                  
jakarta-tomcat/src/share/org/apache/tomcat/util/http/ServerCookie.java
  
  Index: ServerCookie.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 [EMAIL PROTECTED]
   *
   * 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/>.
   *
   * ====================================================================
   */
  package org.apache.tomcat.util.http;
  
  import org.apache.tomcat.util.*;
  import java.text.*;
  import java.io.*;
  import java.util.*;
  
  
  /**
   *  Server-side cookie representation.
   *   Allows recycling and uses MessageBytes as low-level
   *  representation ( and thus the byte-> char conversion can be delayed
   *  until we know the charset ).
   *
   *  Tomcat.core uses this recyclable object to represent cookies,
   *  and the facade will convert it to the external representation.
   */
  public class ServerCookie implements Serializable {
      private MessageBytes name=new MessageBytes();
      private MessageBytes value=new MessageBytes();
  
      private MessageBytes comment=new MessageBytes();    // ;Comment=VALUE
      private MessageBytes domain=new MessageBytes();    // ;Domain=VALUE ...
  
      private int maxAge = -1;  // ;Max-Age=VALUE
                                // ;Discard ... implied by maxAge < 0
      private MessageBytes path=new MessageBytes();     // ;Path=VALUE .
      private boolean secure;   // ;Secure
      private int version = 0;  // ;Version=1
  
  
      public ServerCookie() {
  
      }
  
      public void recycle() {
          path.recycle();
        name.recycle();
        value.recycle();
        comment.recycle();
        maxAge=-1;
        path.recycle();
          domain.recycle();
        version=0;
        secure=false;
      }
  
      public MessageBytes getComment() {
        return comment;
      }
  
      public MessageBytes getDomain() {
        return domain;
      }
  
      public void setMaxAge(int expiry) {
        maxAge = expiry;
      }
  
      public int getMaxAge() {
        return maxAge;
      }
  
  
      public MessageBytes getPath() {
        return path;
      }
  
      public void setSecure(boolean flag) {
        secure = flag;
      }
  
      public boolean getSecure() {
        return secure;
      }
  
      public MessageBytes getName() {
        return name;
      }
  
      public MessageBytes getValue() {
        return value;
      }
  
      public int getVersion() {
        return version;
      }
  
  
      public void setVersion(int v) {
        version = v;
      }
  
  
      // -------------------- utils --------------------
      
      // Note -- disabled for now to allow full Netscape compatibility
      // from RFC 2068, token special case characters
      //
      // private static final String tspecials = "()<>@,;:\\\"/[]?={} \t";
      private static final String tspecials = ",;";
  
      /*
       * Tests a string and returns true if the string counts as a
       * reserved token in the Java language.
       *
       * @param value           the <code>String</code> to be tested
       *
       * @return                        <code>true</code> if the <code>String</code> is
       *                                a reserved token; <code>false</code>
       *                                if it is not
       */
      public static boolean isToken(String value) {
        int len = value.length();
  
        for (int i = 0; i < len; i++) {
            char c = value.charAt(i);
  
            if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1)
                return false;
        }
        return true;
      }
  
      public static boolean checkName( String name ) {
        if (!isToken(name)
                || name.equalsIgnoreCase("Comment")     // rfc2019
                || name.equalsIgnoreCase("Discard")     // 2019++
                || name.equalsIgnoreCase("Domain")
                || name.equalsIgnoreCase("Expires")     // (old cookies)
                || name.equalsIgnoreCase("Max-Age")     // rfc2019
                || name.equalsIgnoreCase("Path")
                || name.equalsIgnoreCase("Secure")
                || name.equalsIgnoreCase("Version")
            ) {
            return false;
        }
        return true;
      }
  
      // -------------------- Cookie parsing tools
  
      
      /** Return the header name to set the cookie, based on cookie
       *  version
       */
      public String getCookieHeaderName() {
          if (version == 1) {
            return "Set-Cookie2";
          } else {
              return "Set-Cookie";
          }
      }
  
      /** Return the header value used to set this cookie
       *  @deprecated Use StringBuffer version
       */
      public String getCookieHeaderValue() {
          StringBuffer buf = new StringBuffer();
        getCookieHeaderValue( buf );
        return buf.toString();
      }
  
      /** Return the header value used to set this cookie
       */
      public void getCookieHeaderValue(StringBuffer buf) {
        ServerCookie cookie=this; 
        
          // this part is the same for all cookies
          buf.append(cookie.getName());
          buf.append("=");
          maybeQuote(version, buf, cookie.getValue().toString());
  
        // add version 1 specific information
        if (version == 1) {
            // Version=1 ... required
            buf.append (";Version=1");
  
            // Comment=comment
            if (cookie.getComment() != null) {
                buf.append (";Comment=");
                maybeQuote (version, buf, cookie.getComment().toString());
            }
        }
  
        // add domain information, if present
  
        if (cookie.getDomain().isNull()) {
            buf.append(";Domain=");
            maybeQuote (version, buf, cookie.getDomain().toString());
        }
  
        // Max-Age=secs/Discard ... or use old "Expires" format
        if (cookie.getMaxAge() >= 0) {
            if (version == 0) {
                buf.append (";Expires=");
                DateTool.oldCookieFormat.
                    format(new Date( System.currentTimeMillis() +
                                     cookie.getMaxAge() *1000L) ,buf,
                           new FieldPosition(0));
  
            } else {
                buf.append (";Max-Age=");
                buf.append (cookie.getMaxAge());
            }
        } else if (version == 1)
          buf.append (";Discard");
  
        // Path=path
        if (cookie.getPath().isNull()) {
            buf.append (";Path=");
            maybeQuote (version, buf, cookie.getPath().toString());
        }
  
        // Secure
        if (cookie.getSecure()) {
          buf.append (";Secure");
        }
      }
  
      public static void maybeQuote (int version, StringBuffer buf,
                                      String value)
      {
        if (version == 0 || isToken (value))
          buf.append (value);
        else {
            buf.append ('"');
            buf.append (value);
            buf.append ('"');
        }
      }
  
  }
  
  
  
  
  1.1                  
jakarta-tomcat/src/share/org/apache/tomcat/util/http/package.html
  
  Index: package.html
  ===================================================================
  <html>
  <head>
  <title>util.http</title>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
  </head>
  
  <body bgcolor="#FFFFFF">
  Special utils for handling HTTP-specific entities - headers, parameters,
  cookies, etc.
  
  The utils are not specific to tomcat, but use util.MessageBytes.
  
  </body>
  </html>
  
  
  

Reply via email to