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>