Return-Path: Delivered-To: apmail-tomcat-dev-archive@www.apache.org Received: (qmail 21004 invoked from network); 25 Sep 2007 18:13:25 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 25 Sep 2007 18:13:25 -0000 Received: (qmail 67056 invoked by uid 500); 25 Sep 2007 18:13:11 -0000 Delivered-To: apmail-tomcat-dev-archive@tomcat.apache.org Received: (qmail 67015 invoked by uid 500); 25 Sep 2007 18:13:11 -0000 Mailing-List: contact dev-help@tomcat.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Tomcat Developers List" Delivered-To: mailing list dev@tomcat.apache.org Received: (qmail 67004 invoked by uid 99); 25 Sep 2007 18:13:11 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 25 Sep 2007 11:13:11 -0700 X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: local policy) Received: from [72.22.94.67] (HELO virtual.halosg.com) (72.22.94.67) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 25 Sep 2007 18:13:09 +0000 Received: (qmail 1961 invoked from network); 25 Sep 2007 13:10:38 -0500 Received: from unknown (HELO ?10.21.65.205?) (208.17.34.25) by halosg.com with SMTP; 25 Sep 2007 13:10:38 -0500 Message-ID: <46F94F89.1050709@hanik.com> Date: Tue, 25 Sep 2007 12:12:25 -0600 From: Filip Hanik - Dev Lists User-Agent: Thunderbird 2.0.0.6 (Windows/20070728) MIME-Version: 1.0 To: Tomcat Developers List Subject: Re: svn commit: r579298 - /tomcat/tc6.0.x/trunk/STATUS References: <20070925152242.52E611A9832@eris.apache.org> In-Reply-To: <20070925152242.52E611A9832@eris.apache.org> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Virus-Checked: Checked by ClamAV on apache.org are we really gonna put each patch (the contents of it) in the STATUS file, this will make the status file unusable pretty quick, wont it? Filip remm@apache.org wrote: > 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 +- 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: dev-unsubscribe@tomcat.apache.org > For additional commands, e-mail: dev-help@tomcat.apache.org > > > > --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org For additional commands, e-mail: dev-help@tomcat.apache.org