Author: remm
Date: Tue Sep 25 08:22:40 2007
New Revision: 579298
URL: http://svn.apache.org/viewvc?rev=579298&view=rev
Log:
- Patch update.
Modified:
tomcat/tc6.0.x/trunk/STATUS
Modified: tomcat/tc6.0.x/trunk/STATUS
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS?rev=579298&r1=579297&r2=579298&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/STATUS (original)
+++ tomcat/tc6.0.x/trunk/STATUS Tue Sep 25 08:22:40 2007
@@ -15,7 +15,7 @@
limitations under the License.
================================================================================
-$Id: BUILDING.txt 562769 2007-08-04 22:08:32Z markt $
+$Revision: $ $Date: $
=================================
Apache Tomcat 6.0 Patch Proposals
@@ -26,7 +26,551 @@
[ New proposals should be added at the end of the list ]
* New cookie parser (third party contribution)
- http://people.apache.org/~jfclere/patches/Cookies.java.patch
+1: -1: jfclere: The tests must done another way.
+
+Index: java/org/apache/tomcat/util/http/Cookies.java
+===================================================================
+--- java/org/apache/tomcat/util/http/Cookies.java (revision 579106)
++++ java/org/apache/tomcat/util/http/Cookies.java (working copy)
+@@ -45,7 +45,28 @@
+ boolean unprocessed=true;
+ + MimeHeaders headers;
+- ++
++ /*
++ List of Separator Characters (see isSeparator())
++ Excluding the '/' char violates the RFC, but ++ it looks
like a lot of people put '/'
++ in unquoted values: '/': ; //47 ++ '\t':9 ' ':32 '\"':34
'\'':39 '(':40 ')':41 ',':44 ':':58 ';':59 '<':60 ++ '=':61 '>':62
'?':63 '@':64 '[':91 '\\':92 ']':93 '{':123 '}':125
++ */
++ public static final char SEPARATORS[] = { '\t', ' ', '\"',
'\'', '(', ')', ',', ++ ':', ';', '<', '=', '>', '?', '@',
'[', '\\', ']', '{', '}' };
++
++ protected static final boolean separators[] = new boolean[128];
++ static {
++ for (int i = 0; i < 128; i++) {
++ separators[i] = false;
++ }
++ for (int i = 0; i < SEPARATORS.length; i++) {
++ separators[SEPARATORS[i]] = true;
++ }
++ }
++
+ /**
+ * Construct a new cookie collection, that will extract
+ * the information from headers.
+@@ -182,181 +203,6 @@
+ }
+ }
+ +- /** Process a byte[] header - allowing fast processing of the
+- * raw data
+- */
+- void processCookieHeader( byte bytes[], int off, int len )
+- {
+- 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 );
+- }
+- }
+- }
+-
+- // -------------------- 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==',' )
+- return off;
+- off++;
+- }
+- return off;
+- }
+-
+- /*
+- * search for cc but skip \cc as required by rfc2616
+- * (according to rfc2616 cc should be ")
+- */
+- 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;
+- }
+-
+ // XXX will be refactored soon!
+ public static boolean equals( String s, byte b[], int start,
int end) {
+ int blen = end-start;
+@@ -440,42 +286,294 @@
+ log.debug("Cookies: " + s);
+ }
+ +- /*
+- public static void main( String args[] ) {
+- test("foo=bar; a=b");
+- test("foo=bar;a=b");
+- test("foo=bar;a=b;");
+- test("foo=bar;a=b; ");
+- test("foo=bar;a=b; ;");
+- test("foo=;a=b; ;");
+- test("foo;a=b; ;");
+- // v1 +- test("$Version=1; foo=bar;a=b"); +-
test("$Version=\"1\"; foo='bar'; $Path=/path; $Domain=\"localhost\"");
+- test("$Version=1;foo=bar;a=b; ; ");
+- test("$Version=1;foo=;a=b; ; ");
+- test("$Version=1;foo= ;a=b; ; ");
+- test("$Version=1;foo;a=b; ; ");
+- test("$Version=1;foo=\"bar\";a=b; ; ");
+- test("$Version=1;foo=\"bar\";$Path=/examples;a=b; ; ");
+- test("$Version=1;foo=\"bar\";$Domain=apache.org;a=b");
+-
test("$Version=1;foo=\"bar\";$Domain=apache.org;a=b;$Domain=yahoo.com");
+- // rfc2965
+-
test("$Version=1;foo=\"bar\";$Domain=apache.org;$Port=8080;a=b");
++
++ /**
++ * Returns true if the byte is a separator character as
++ * defined in RFC2619. Since this is called often, this
++ * function should be organized with the most probable
++ * outcomes first.
++ * JVK
++ */
++ public static final boolean isSeparator(final byte c) {
++ if (c > 0 && c < 126)
++ return separators[c];
++ else
++ return false;
++ }
++ ++ /**
++ * Returns true if the byte is a whitespace character as
++ * defined in RFC2619
++ * JVK
++ */
++ public static final boolean isWhiteSpace(final byte c) {
++ // This switch statement is slightly slower
++ // for my vm than the if statement.
++ // Java(TM) 2 Runtime Environment, Standard Edition (build
1.5.0_07-164)
++ /* ++ switch (c) {
++ case ' ':;
++ case '\t':;
++ case '\n':;
++ case '\r':;
++ case '\f':;
++ return true;
++ default:;
++ return false;
++ }
++ */
++ if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c ==
'\f')
++ return true;
++ else
++ return false;
++ }
++
++ /**
++ * Parses a cookie header after the initial "Cookie:"
++ * [WS][$]token[WS]=[WS](token|QV)[;|,]
++ * RFC 2965
++ * JVK
++ */
++ public final void processCookieHeader(byte bytes[], int off,
int len){
++ if( len<=0 || bytes==null ) return;
++ int end=off+len;
++ int pos=off;
++ int nameStart=0;
++ int nameEnd=0;
++ int valueStart=0;
++ int valueEnd=0;
++ int version = 0;
++ ServerCookie sc=null;
++ boolean isSpecial;
++
++ while (pos < end) {
++ isSpecial = false;
++
++ // Skip whitespace and non-token characters (separators)
++ while (pos < end && ++
(isSeparator(bytes[pos]) || isWhiteSpace(bytes[pos])))
++ {pos++; } ++
++ if (pos >= end)
++ return;
++
++ // Detect Special cookies
++ if (bytes[pos] == '$') {
++ isSpecial = true;
++ pos++;
++ }
++
++ // Get the cookie name. This must be a token
++ valueEnd = valueStart = nameStart = pos; ++
pos = nameEnd = getTokenEndPosition(bytes,pos,end);
++
++ // Skip whitespace
++ while (pos < end && isWhiteSpace(bytes[pos])) {pos++;
}; ++ ++
++ // Check for an '=' -- This could also be a name-only
++ // cookie at the end of the cookie header, so if we
++ // are past the end of the header, but we have a name
++ // skip to the name-only part.
++ if (pos < end && bytes[pos] == '=') { ++
++ // Skip whitespace
++ do {
++ pos++;
++ } while (pos < end && isWhiteSpace(bytes[pos])); ++
++ if (pos >= end)
++ return;
++
++ // Determine what type of value this is, quoted value,
++ // token, name-only with an '=', or other (bad)
++ switch (bytes[pos]) {
++ case '"':; // Quoted Value
++ valueStart=pos + 1; // strip "
++ // getQuotedValue returns the position before
++ // at the last qoute. This must be dealt with
++ // when the bytes are copied into the cookie
++ valueEnd=getQuotedValueEndPosition(bytes,
++ valueStart,
end);
++ // We need pos to advance
++ pos = valueEnd; ++ //
Handles cases where the quoted value is ++ //
unterminated and at the end of the header, ++ //
e.g. [myname="value]
++ if (pos >= end)
++ return;
++ break;
++ case ';':
++ case ',':
++ // Name-only cookie with an '=' after the name
token
++ // This may not be RFC compliant
++ valueStart = valueEnd = -1;
++ // The position is OK (On a delimiter)
++ break;
++ default:;
++ if (!isSeparator(bytes[pos])) {
++ // Token
++ valueStart=pos;
++ // getToken returns the position at the
delimeter
++ // or other non-token character
++ valueEnd=getTokenEndPosition(bytes,
valueStart, end);
++ // We need pos to advance
++ pos = valueEnd;
++ } else {
++ // INVALID COOKIE, advance to next delimiter
++ // The starting character of the cookie
value was
++ // not valid.
++ log("Invalid cookie. Value not a token or
quoted value");
++ while (pos < end && bytes[pos] != ';' &&
++ bytes[pos] != ',')
++ {pos++; };
++ pos++;
++ // Make sure no special avpairs can be
attributed to ++ // the previous cookie by
setting the current cookie
++ // to null
++ sc = null;
++ continue;
++ }
++ }
++ } else {
++ // Name only cookie
++ valueStart = valueEnd = -1;
++ pos = nameEnd;
++
++ }
++ ++ // We should have an avpair or name-only
cookie at this
++ // point. Perform some basic checks to make sure we are
++ // in a good state.
++ ++ // Skip whitespace
++ while (pos < end && isWhiteSpace(bytes[pos])) {pos++;
}; ++
++
++ // Make sure that after the cookie we have a separator.
This
++ // is only important if this is not the last cookie pair
++ while (pos < end && bytes[pos] != ';' && bytes[pos] !=
',') { ++ pos++;
++ }
++ ++ pos++;
++
++ /*
++ if (nameEnd <= nameStart || valueEnd < valueStart ) {
++ // Something is wrong, but this may be a case
++ // of having two ';' characters in a row.
++ // log("Cookie name/value does not conform to RFC
2965");
++ // Advance to next delimiter (ignoring everything
else)
++ while (pos < end && bytes[pos] != ';' && bytes[pos]
!= ',') ++ { pos++; };
++ pos++;
++ // Make sure no special cookies can be attributed
to ++ // the previous cookie by setting the current
cookie
++ // to null
++ sc = null;
++ continue;
++ }
++ */
++
++ // All checks passed. Add the cookie, start with the
++ // special avpairs first
++ if (isSpecial) {
++ isSpecial = false;
++ // $Version must be the first avpair in the cookie
header
++ // (sc must be null)
++ if (equals( "Version", bytes, nameStart, nameEnd)
&& ++ sc == null) {
++ // Set version
++ if( bytes[valueStart] =='1' && valueEnd ==
valueStart) {
++ version=1;
++ } else {
++ // unknown version (Versioning is not very
strict)
++ }
++ continue;
++ } ++ ++ // We need an
active cookie for Path/Port/etc.
++ if (sc == null) {
++ continue;
++ }
++
++ // Domain is more common, so it goes first
++ if (equals( "Domain", bytes, nameStart, nameEnd)) {
++ sc.getDomain().setBytes( bytes,
++ valueStart,
++ valueEnd-valueStart);
++ continue;
++ } ++
++ if (equals( "Path", bytes, nameStart, nameEnd)) {
++ sc.getPath().setBytes( bytes,
++ valueStart,
++ valueEnd-valueStart);
++ continue;
++ } ++
++
++ if (equals( "Port", bytes, nameStart, nameEnd)) {
++ // sc.getPort is not currently implemented.
++ // sc.getPort().setBytes( bytes,
++ // valueStart,
++ // valueEnd-valueStart );
++ continue;
++ } ++
++ // Unknown cookie, complain
++ log("Unknown Special Cookie");
+ +- // wrong
+-
test("$Version=1;foo=\"bar\";$Domain=apache.org;$Port=8080;a=b");
++ } else { // Normal Cookie
++ sc = addCookie();
++ sc.setVersion( version );
++ sc.getName().setBytes( bytes, nameStart,
++ nameEnd-nameStart);
++ ++ if (valueStart != -1) { // Normal
AVPair
++ sc.getValue().setBytes( bytes, valueStart,
++ valueEnd-valueStart);
++ } else {
++ // Name Only
++ sc.getValue().setString(""); ++ }
++ continue;
++ }
++ }
+ }
+ +- public static void test( String s ) {
+- System.out.println("Processing " + s );
+- Cookies cs=new Cookies(null);
+- cs.processCookieHeader( s.getBytes(), 0, s.length());
+- for( int i=0; i< cs.getCookieCount() ; i++ ) {
+- System.out.println("Cookie: " + cs.getCookie( i ));
++ /**
++ * Given the starting position of a token, this gets the end of
the
++ * token, with no separator characters in between.
++ * JVK
++ */
++ public static final int getTokenEndPosition(byte bytes[], int
off, int end){
++ int pos = off;
++ while (pos < end && !isSeparator(bytes[pos])) {pos++; };
++ ++ if (pos > end)
++ return end;
++ return pos;
++ }
++
++ /** ++ * Given a starting position after an initial quote
chracter, this gets
++ * the position of the end quote. This escapes anything after a
'\' char
++ * JVK RFC 2616
++ */
++ public static final int getQuotedValueEndPosition(byte bytes[],
int off, int end){
++ int pos = off;
++ while (pos < end) {
++ if (bytes[pos] == '"') {
++ return pos; ++ } else if
(bytes[pos] == '\\' && pos < (end - 1)) {
++ pos+=2;
++ } else {
++ pos++;
++ }
+ }
+- ++ // Error, we have reached the end of the
header w/o a end quote
++ return end;
+ }
+- */
+ + }
+
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]