You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2007/10/21 00:52:49 UTC
svn commit: r586818 - in /tomcat/tc6.0.x/trunk: STATUS
java/org/apache/tomcat/util/http/Cookies.java
java/org/apache/tomcat/util/http/ServerCookie.java webapps/docs/changelog.xml
Author: markt
Date: Sat Oct 20 15:52:47 2007
New Revision: 586818
URL: http://svn.apache.org/viewvc?rev=586818&view=rev
Log:
Make unescaping the exact reverse of escaping.
Code clean up.
Modified:
tomcat/tc6.0.x/trunk/STATUS
tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/http/Cookies.java
tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/http/ServerCookie.java
tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
Modified: tomcat/tc6.0.x/trunk/STATUS
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS?rev=586818&r1=586817&r2=586818&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/STATUS (original)
+++ tomcat/tc6.0.x/trunk/STATUS Sat Oct 20 15:52:47 2007
@@ -57,15 +57,6 @@
Comment by rjung: Maybe switching "then" and "else" cases by using "-x" instead of "! -x".
This way the error exit stays the last case which seems more natural.
-
-* Final fixes to the Cookie handling. This makes sure that we unescape any value
- that has been quoted and ensures the unescaping is the exact reverse of the
- escaping. This patch also tidies up ServerCookie to make it clearer what
- applies to which particular cookie spec.
- http://people.apache.org/~markt/patches/2007-10-18-cookies.patch
- +1: markt, fhanik,funkman
- -1:
-
* Fix MD5 files for distribution
http://issues.apache.org/bugzilla/attachment.cgi?id=21009&action=view
+1: fhanik,funkman
Modified: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/http/Cookies.java
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/http/Cookies.java?rev=586818&r1=586817&r2=586818&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/http/Cookies.java (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/http/Cookies.java Sat Oct 20 15:52:47 2007
@@ -345,9 +345,11 @@
int version = 0;
ServerCookie sc=null;
boolean isSpecial;
+ boolean isQuoted;
while (pos < end) {
isSpecial = false;
+ isQuoted = false;
// Skip whitespace and non-token characters (separators)
while (pos < end &&
@@ -389,6 +391,7 @@
// token, name-only with an '=', or other (bad)
switch (bytes[pos]) {
case '"':; // Quoted Value
+ isQuoted = true;
valueStart=pos + 1; // strip "
// getQuotedValue returns the position before
// at the last qoute. This must be dealt with
@@ -532,7 +535,12 @@
if (valueStart != -1) { // Normal AVPair
sc.getValue().setBytes( bytes, valueStart,
- valueEnd-valueStart);
+ valueEnd-valueStart);
+ if (isQuoted) {
+ // We know this is a byte value so this is safe
+ ServerCookie.unescapeDoubleQuotes(
+ sc.getValue().getByteChunk());
+ }
} else {
// Name Only
sc.getValue().setString("");
Modified: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/http/ServerCookie.java
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/http/ServerCookie.java?rev=586818&r1=586817&r2=586818&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/http/ServerCookie.java (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/http/ServerCookie.java Sat Oct 20 15:52:47 2007
@@ -21,13 +21,14 @@
import java.text.FieldPosition;
import java.util.Date;
+import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.DateTool;
import org.apache.tomcat.util.buf.MessageBytes;
/**
* Server-side cookie representation.
- * Allows recycling and uses MessageBytes as low-level
+ * Allows recycling and uses MessageBytes as low-level
* representation ( and thus the byte-> char conversion can be delayed
* until we know the charset ).
*
@@ -37,38 +38,43 @@
public class ServerCookie implements Serializable {
- private static org.apache.juli.logging.Log log=
- org.apache.juli.logging.LogFactory.getLog(ServerCookie.class );
-
+ private static org.apache.juli.logging.Log log =
+ org.apache.juli.logging.LogFactory.getLog(ServerCookie.class);
+
+ // Version 0 (Netscape) attributes
private MessageBytes name=MessageBytes.newInstance();
private MessageBytes value=MessageBytes.newInstance();
-
- private MessageBytes comment=MessageBytes.newInstance(); // ;Comment=VALUE
- private MessageBytes domain=MessageBytes.newInstance(); // ;Domain=VALUE
-
- private int maxAge = -1; // ;Max-Age=VALUE
- // ;Discard ... implied by maxAge < 0
- // RFC2109: maxAge=0 will end a session
- private MessageBytes path=MessageBytes.newInstance(); // ;Path=VALUE
- private boolean secure; // ;Secure
- private int version = 0; // ;Version=1
-
- //XXX CommentURL, Port -> use notes ?
+ // Expires - Not stored explicitly. Generated from Max-Age (see V1)
+ private MessageBytes path=MessageBytes.newInstance();
+ private MessageBytes domain=MessageBytes.newInstance();
+ private boolean secure;
- public ServerCookie() {
+ // Version 1 (RFC2109) attributes
+ private MessageBytes comment=MessageBytes.newInstance();
+ private int maxAge = -1;
+ private int version = 0;
+
+ // Note: Servlet Spec =< 2.5 only refers to Netscape and RFC2109,
+ // not RFC2965
+
+ // Version 1 (RFC2965) attributes
+ // TODO Add support for CommentURL
+ // Discard - implied by maxAge <0
+ // TODO Add support for Port
+ public ServerCookie() {
}
public void recycle() {
path.recycle();
- name.recycle();
- value.recycle();
- comment.recycle();
- maxAge=-1;
- path.recycle();
+ name.recycle();
+ value.recycle();
+ comment.recycle();
+ maxAge=-1;
+ path.recycle();
domain.recycle();
- version=0;
- secure=false;
+ version=0;
+ secure=false;
}
public MessageBytes getComment() {
@@ -87,7 +93,6 @@
return maxAge;
}
-
public MessageBytes getPath() {
return path;
}
@@ -112,7 +117,6 @@
return version;
}
-
public void setVersion(int v) {
version = v;
}
@@ -120,17 +124,18 @@
// -------------------- utils --------------------
+ public static void log(String s ) {
+ if (log.isDebugEnabled())
+ log.debug("ServerCookie: " + s);
+ }
+
public String toString() {
return "Cookie " + getName() + "=" + getValue() + " ; "
+ getVersion() + " " + getPath() + " " + getDomain();
}
- // 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 = ",; ";
- private static final String tspecials2 = ",; \"";
+ private static final String tspecials2 = "()<>@,;:\\\"/[]?={} \t";
/*
* Tests a string and returns true if the string counts as a
@@ -167,16 +172,20 @@
return true;
}
+ /**
+ * @deprecated - Not used
+ */
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")
+ || name.equalsIgnoreCase("Comment") // rfc2019
+ || name.equalsIgnoreCase("Discard") // rfc2965
+ || name.equalsIgnoreCase("Domain") // rfc2019
+ || name.equalsIgnoreCase("Expires") // Netscape
+ || name.equalsIgnoreCase("Max-Age") // rfc2019
+ || name.equalsIgnoreCase("Path") // rfc2019
+ || name.equalsIgnoreCase("Secure") // rfc2019
+ || name.equalsIgnoreCase("Version") // rfc2019
+ // TODO remaining RFC2965 attributes
) {
return false;
}
@@ -186,25 +195,27 @@
// -------------------- Cookie parsing tools
- /** Return the header name to set the cookie, based on cookie
- * version
+ /**
+ * Return the header name to set the cookie, based on cookie version.
*/
public String getCookieHeaderName() {
return getCookieHeaderName(version);
}
- /** Return the header name to set the cookie, based on cookie
- * version
+ /**
+ * Return the header name to set the cookie, based on cookie version.
*/
public static String getCookieHeaderName(int version) {
- if( dbg>0 ) log( (version==1) ? "Set-Cookie2" : "Set-Cookie");
+ // TODO Re-enable logging when RFC2965 is implemented
+ // log( (version==1) ? "Set-Cookie2" : "Set-Cookie");
if (version == 1) {
+ // XXX RFC2965 not referenced in Servlet Spec
+ // Set-Cookie2 is not supported by Netscape 4, 6, IE 3, 5
+ // Set-Cookie2 is supported by Lynx and Opera
+ // Need to check on later IE and FF releases but for now...
// RFC2109
return "Set-Cookie";
- // XXX RFC2965 is not standard yet, and Set-Cookie2
- // is not supported by Netscape 4, 6, IE 3, 5 .
- // It is supported by Lynx, and there is hope
- // return "Set-Cookie2";
+ // return "Set-Cookie2";
} else {
// Old Netscape
return "Set-Cookie";
@@ -214,6 +225,7 @@
private static final String ancientDate =
DateTool.formatOldCookie(new Date(10000));
+ // TODO RFC2965 fields also need to be passed
public static void appendCookieValue( StringBuffer buf,
int version,
String name,
@@ -224,13 +236,14 @@
int maxAge,
boolean isSecure )
{
- // this part is the same for all cookies
+ // Servlet implementation checks name
buf.append( name );
buf.append("=");
+ // Servlet implementation does not check anything else
+
maybeQuote2(version, buf, value);
- // XXX Netscape cookie: "; "
- // add version 1 specific information
+ // Add version 1 specific information
if (version == 1) {
// Version=1 ... required
buf.append ("; Version=1");
@@ -238,26 +251,23 @@
// Comment=comment
if ( comment!=null ) {
buf.append ("; Comment=");
- maybeQuote (version, buf, comment);
+ maybeQuote2(version, buf, comment);
}
}
- // add domain information, if present
-
+ // Add domain information, if present
if (domain!=null) {
buf.append("; Domain=");
- maybeQuote (version, buf, domain);
+ maybeQuote2(version, buf, domain);
}
- // Max-Age=secs/Discard ... or use old "Expires" format
+ // Max-Age=secs ... or use old "Expires" format
+ // TODO RFC2965 Discard
if (maxAge >= 0) {
if (version == 0) {
- // XXX XXX XXX We need to send both, for
- // interoperatibility (long word )
+ // Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires Netscape format )
buf.append ("; Expires=");
- // Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires netscape format )
- // To expire we need to set the time back in future
- // ( pfrieden@dChain.com )
+ // To expire immediately we need to set the time in past
if (maxAge == 0)
buf.append( ancientDate );
else
@@ -275,7 +285,7 @@
// Path=path
if (path!=null) {
buf.append ("; Path=");
- maybeQuote (version, buf, path);
+ maybeQuote2(version, buf, path);
}
// Secure
@@ -286,6 +296,9 @@
}
+ /**
+ * @deprecated - Not used
+ */
public static void maybeQuote (int version, StringBuffer buf,
String value) {
// special case - a \n or \r shouldn't happen in any case
@@ -297,10 +310,17 @@
buf.append('"');
}
}
+
+ /**
+ * Quotes values using rules that vary depending on Cookie version.
+ * @param version
+ * @param buf
+ * @param value
+ */
public static void maybeQuote2 (int version, StringBuffer buf,
String value) {
// special case - a \n or \r shouldn't happen in any case
- if (isToken2(value)) {
+ if (version == 0 && isToken(value) || version == 1 && isToken2(value)) {
buf.append(value);
} else {
buf.append('"');
@@ -309,13 +329,6 @@
}
}
- // log
- static final int dbg=1;
- public static void log(String s ) {
- if (log.isDebugEnabled())
- log.debug("ServerCookie: " + s);
- }
-
/**
* Escapes any double quotes in the given string.
@@ -331,18 +344,42 @@
}
StringBuffer b = new StringBuffer();
- char p = s.charAt(0);
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
- if (c == '"' && p != '\\')
+ if (c == '"')
b.append('\\').append('"');
else
b.append(c);
- p = c;
}
return b.toString();
}
+ /**
+ * Unescapes any double quotes in the given cookie value.
+ *
+ * @param bc The cookie value to modify
+ */
+ public static void unescapeDoubleQuotes(ByteChunk bc) {
+
+ if (bc == null || bc.getLength() == 0 || bc.indexOf('"', 0) == -1) {
+ return;
+ }
+
+ int src = bc.getStart();
+ int end = bc.getEnd();
+ int dest = src;
+ byte[] buffer = bc.getBuffer();
+
+ while (src < end) {
+ if (buffer[src] == '\\' && src < end && buffer[src+1] == '"') {
+ src++;
+ }
+ buffer[dest] = buffer[src];
+ dest ++;
+ src ++;
+ }
+ bc.setEnd(dest);
+ }
}
Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=586818&r1=586817&r2=586818&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Sat Oct 20 15:52:47 2007
@@ -38,9 +38,9 @@
<update>
Add ANT script to be able to publish signed Tomcat JAR's to ASF Maven repo (fhanik)
</update>
- <fix>
+ <update>
Use Eclipse JDT 3.3.1. (pero)
- </fix>
+ </update>
</changelog>
</subsection>
<subsection name="Catalina">
@@ -143,6 +143,9 @@
<update>
Cookie parser refactoring, submitted by John Kew. (remm)
</update>
+ <fix>
+ Make cookie escaping / unescaping consistent. (markt)
+ </fix>
<fix>
<bug>43479</bug>: Memory leak cleaning up sendfile connections, submitted by Chris Elving. (remm)
</fix>
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org