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/11/30 18:42:50 UTC
cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/util/http Cookies.java Headers.java Parameters.java ServerCookie.java package.html
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 apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.tomcat.util.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 apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.tomcat.util.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 dac@eng.sun.com
* @author James Todd [gonzo@eng.sun.com]
* @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 apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.tomcat.util.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 apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* ====================================================================
*/
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>