Cookiespublic final class Cookies extends Object A collection of cookies - reusable and tuned for server side performance.
Based on RFC2965 ( and 2109 )
This class is not synchronized. |
Fields Summary |
---|
private static org.apache.juli.logging.Log | log | public static final int | INITIAL_SIZE | ServerCookie[] | scookies | int | cookieCount | boolean | unprocessed | MimeHeaders | headers | static final int | dbg |
Constructors Summary |
---|
public Cookies(MimeHeaders headers)Construct a new cookie collection, that will extract
the information from headers.
this.headers=headers;
| public Cookies()Construct a new uninitialized cookie collection.
Use {@link #setHeaders} to initialize.
|
Methods Summary |
---|
public ServerCookie | addCookie()Register a new, unitialized cookie. Cookies are recycled, and
most of the time an existing ServerCookie object is returned.
The caller can set the name/value and attributes for the cookie
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;
| public static boolean | equals(java.lang.String s, byte[] b, int start, int end)
int blen = end-start;
if (b == null || blen != s.length()) {
return false;
}
int boff = start;
for (int i = 0; i < blen; i++) {
if (b[boff++] != s.charAt(i)) {
return false;
}
}
return true;
| 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=='," )
return off;
off++;
}
return off;
| public static int | findDelim3(byte[] bytes, int off, int end, byte cc)
while( off < end ) {
byte b=bytes[off];
if ( b== '\\" ) {
off++;
off++;
continue;
}
if( b==cc )
return off;
off++;
}
return -1;
| public ServerCookie | getCookie(int idx)
if( unprocessed ) {
getCookieCount(); // will also update the cookies
}
return scookies[idx];
| public int | getCookieCount()
if( unprocessed ) {
unprocessed=false;
processCookies(headers);
}
return cookieCount;
| public void | log(java.lang.String s)
if (log.isDebugEnabled())
log.debug("Cookies: " + s);
| void | processCookieHeader(byte[] bytes, int off, int len)Process a byte[] header - allowing fast processing of the
raw data
if( len<=0 || bytes==null ) return;
int end=off+len;
int pos=off;
int version=0; //sticky
ServerCookie sc=null;
while( pos<end ) {
byte cc;
// [ skip_spaces name skip_spaces "=" skip_spaces value EXTRA ; ] *
if( dbg>0 ) log( "Start: " + pos + " " + end );
pos=skipSpaces(bytes, pos, end);
if( pos>=end )
return; // only spaces
int startName=pos;
if( dbg>0 ) log( "SN: " + pos );
// Version should be the first token
boolean isSpecial=false;
if(bytes[pos]=='$") { pos++; isSpecial=true; }
pos= findDelim1( bytes, startName, end); // " =;,"
int endName=pos;
// current = "=" or " " or DELIM
pos= skipSpaces( bytes, endName, end );
if( dbg>0 ) log( "DELIM: " + endName + " " + (char)bytes[pos]);
if(pos >= end ) {
// it's a name-only cookie ( valid in RFC2109 )
if( ! isSpecial ) {
sc=addCookie();
sc.getName().setBytes( bytes, startName,
endName-startName );
sc.getValue().setString("");
sc.setVersion( version );
if( dbg>0 ) log( "Name only, end: " + startName + " " +
endName);
}
return;
}
cc=bytes[pos];
pos++;
if( cc==';" || cc=='," || pos>=end ) {
if( ! isSpecial && startName!= endName ) {
sc=addCookie();
sc.getName().setBytes( bytes, startName,
endName-startName );
sc.getValue().setString("");
sc.setVersion( version );
if( dbg>0 ) log( "Name only: " + startName + " " + endName);
}
continue;
}
// we should have "=" ( tested all other alternatives )
int startValue=skipSpaces( bytes, pos, end);
int endValue=startValue;
cc=bytes[pos];
if( cc=='"" ) {
endValue=findDelim3( bytes, startValue+1, end, cc );
if (endValue == -1) {
endValue=findDelim2( bytes, startValue+1, end );
} else startValue++;
pos=endValue+1; // to skip to next cookie
} else {
endValue=findDelim2( bytes, startValue, end );
pos=endValue+1;
}
// if not $Version, etc
if( ! isSpecial ) {
sc=addCookie();
sc.getName().setBytes( bytes, startName, endName-startName );
sc.getValue().setBytes( bytes, startValue, endValue-startValue);
sc.setVersion( version );
if( dbg>0 ) {
log( "New: " + sc.getName() + "X=X" + sc.getValue());
}
continue;
}
// special - Path, Version, Domain, Port
if( dbg>0 ) log( "Special: " + startName + " " + endName);
// XXX TODO
if( equals( "$Version", bytes, startName, endName ) ) {
if(dbg>0 ) log( "Found version " );
if( bytes[startValue]=='1" && endValue==startValue+1 ) {
version=1;
if(dbg>0 ) log( "Found version=1" );
}
continue;
}
if( sc==null ) {
// Path, etc without a previous cookie
continue;
}
if( equals( "$Path", bytes, startName, endName ) ) {
sc.getPath().setBytes( bytes,
startValue,
endValue-startValue );
}
if( equals( "$Domain", bytes, startName, endName ) ) {
sc.getDomain().setBytes( bytes,
startValue,
endValue-startValue );
}
if( equals( "$Port", bytes, startName, endName ) ) {
// sc.getPort().setBytes( bytes,
// startValue,
// endValue-startValue );
}
}
| private void | processCookieHeader(java.lang.String cookieString)
if( dbg>0 ) log( "Parsing cookie header " + 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);
if( dbg > 0 ) log( "Add cookie " + name + "=" + value);
} else {
// we have a bad cookie.... just let it go
}
}
| public void | processCookies(MimeHeaders headers)Add all Cookie found in the headers of a request.
if( headers==null )
return;// nothing to process
// process each "cookie" header
int pos=0;
while( pos>=0 ) {
// Cookie2: version ? not needed
pos=headers.findHeader( "Cookie", pos );
// no more cookie headers headers
if( pos<0 ) break;
MessageBytes cookieValue=headers.getValue( pos );
if( cookieValue==null || cookieValue.isNull() ) {
pos++;
continue;
}
// Uncomment to test the new parsing code
if( cookieValue.getType() == MessageBytes.T_BYTES ) {
if( dbg>0 ) log( "Parsing b[]: " + cookieValue.toString());
ByteChunk bc=cookieValue.getByteChunk();
processCookieHeader( bc.getBytes(),
bc.getOffset(),
bc.getLength());
} else {
if( dbg>0 ) log( "Parsing S: " + cookieValue.toString());
processCookieHeader( cookieValue.toString() );
}
pos++;// search from the next position
}
| public void | recycle()Recycle.
for( int i=0; i< cookieCount; i++ ) {
if( scookies[i]!=null )
scookies[i].recycle();
}
cookieCount=0;
unprocessed=true;
| public void | setHeaders(MimeHeaders headers)Set the headers from which cookies will be pulled.
This has the side effect of recycling the object.
recycle();
this.headers=headers;
| public static int | skipSpaces(byte[] bytes, int off, int end)
while( off < end ) {
byte b=bytes[off];
if( b!= ' " ) return off;
off ++;
}
return off;
| private static java.lang.String | stripQuote(java.lang.String value)Strips quotes from the start and end of the cookie string
This conforms to RFC 2965
// log("Strip quote from " + value );
if (value.startsWith("\"") && value.endsWith("\"")) {
try {
return value.substring(1,value.length()-1);
} catch (Exception ex) {
}
}
return value;
| public java.lang.String | toString()EXPENSIVE!!! only for debugging.
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println("=== Cookies ===");
int count = getCookieCount();
for (int i = 0; i < count; ++i) {
pw.println(getCookie(i).toString());
}
return sw.toString();
|
|