From fb46c8fe3023f57edd83e807ec033dfd96c9a55f Mon Sep 17 00:00:00 2001 From: markt Date: Thu, 29 Oct 2009 18:36:49 +0000 Subject: [PATCH] Add system property to control treatment of / as a separator when processing cookies Modify ALWAYS_ADD_EXPIRES so STRICT_SERVLET_COMPLIANCE changes the default to a strict interpretation of the specs Note: I'll refactor the common code into a Constants class once I am finished but I'm doing that last as the refactoring won't be proposed for back-port to 6.0.x/5.5.x git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@831059 13f79535-47bb-0310-9956-ffa450edef68 --- java/org/apache/tomcat/util/http/Cookies.java | 49 +++++++++++++++--- java/org/apache/tomcat/util/http/ServerCookie.java | 59 ++++++++++++++++++---- webapps/docs/config/systemprops.xml | 26 +++++++++- 3 files changed, 114 insertions(+), 20 deletions(-) diff --git a/java/org/apache/tomcat/util/http/Cookies.java b/java/org/apache/tomcat/util/http/Cookies.java index 60d52b37f..e45b60d21 100644 --- a/java/org/apache/tomcat/util/http/Cookies.java +++ b/java/org/apache/tomcat/util/http/Cookies.java @@ -46,19 +46,54 @@ public final class Cookies { // extends MultiMap { MimeHeaders headers; + /** + * If set to true, we parse cookies strictly according to the servlet, + * cookie and HTTP specs by default. + */ + public static final boolean STRICT_SERVLET_COMPLIANCE; + + /** + * If set to true, the / character will be treated as a + * separator. Default is usually false. If STRICT_SERVLET_COMPLIANCE==true + * then default is true. Explicitly setting always takes priority. + */ + public static final boolean FWD_SLASH_IS_SEPARATOR; + /* 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 '(':40 ')':41 ',':44 ':':58 ';':59 '<':60 - '=':61 '>':62 '?':63 '@':64 '[':91 '\\':92 ']':93 '{':123 '}':125 */ - public static final char SEPARATORS[] = { '\t', ' ', '\"', '(', ')', ',', - ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '{', '}' }; + public static final char SEPARATORS[]; protected static final boolean separators[] = new boolean[128]; static { + STRICT_SERVLET_COMPLIANCE = Boolean.valueOf(System.getProperty( + "org.apache.catalina.STRICT_SERVLET_COMPLIANCE", + "false")).booleanValue(); + + String fwdSlashIsSeparator = System.getProperty( + "org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR"); + if (fwdSlashIsSeparator == null) { + FWD_SLASH_IS_SEPARATOR = STRICT_SERVLET_COMPLIANCE; + } else { + FWD_SLASH_IS_SEPARATOR = + Boolean.valueOf(fwdSlashIsSeparator).booleanValue(); + } + + /* + Excluding the '/' char by default violates the RFC, but + it looks like a lot of people put '/' + in unquoted values: '/': ; //47 + '\t':9 ' ':32 '\"':34 '(':40 ')':41 ',':44 ':':58 ';':59 '<':60 + '=':61 '>':62 '?':63 '@':64 '[':91 '\\':92 ']':93 '{':123 '}':125 + */ + if (FWD_SLASH_IS_SEPARATOR) { + SEPARATORS = new char[] { '\t', ' ', '\"', '(', ')', ',', '/', + ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '{', '}' }; + } else { + SEPARATORS = new char[] { '\t', ' ', '\"', '(', ')', ',', + ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '{', '}' }; + } + for (int i = 0; i < 128; i++) { separators[i] = false; } diff --git a/java/org/apache/tomcat/util/http/ServerCookie.java b/java/org/apache/tomcat/util/http/ServerCookie.java index 8b1d2587b..e9cc85103 100644 --- a/java/org/apache/tomcat/util/http/ServerCookie.java +++ b/java/org/apache/tomcat/util/http/ServerCookie.java @@ -68,22 +68,53 @@ public class ServerCookie implements Serializable { }; private static final String ancientDate; - - static { - ancientDate = OLD_COOKIE_FORMAT.get().format(new Date(10000)); - } + /** + * If set to true, we parse cookies strictly according to the servlet, + * cookie and HTTP specs by default. + */ + public static final boolean STRICT_SERVLET_COMPLIANCE; /** - * If set to true, we parse cookies according to the servlet spec, + * If set to false, we don't use the IE6/7 Max-Age/Expires work around. + * Default is usually true. If STRICT_SERVLET_COMPLIANCE==true then default + * is false. Explicitly setting always takes priority. */ - public static final boolean STRICT_SERVLET_COMPLIANCE = - Boolean.valueOf(System.getProperty("org.apache.catalina.STRICT_SERVLET_COMPLIANCE", "false")).booleanValue(); + public static final boolean ALWAYS_ADD_EXPIRES; /** - * If set to false, we don't use the IE6/7 Max-Age/Expires work around + * If set to true, the / character will be treated as a + * separator. Default is usually false. If STRICT_SERVLET_COMPLIANCE==true + * then default is true. Explicitly setting always takes priority. */ - public static final boolean ALWAYS_ADD_EXPIRES = - Boolean.valueOf(System.getProperty("org.apache.tomcat.util.http.ServerCookie.ALWAYS_ADD_EXPIRES", "true")).booleanValue(); + public static final boolean FWD_SLASH_IS_SEPARATOR; + + + static { + ancientDate = OLD_COOKIE_FORMAT.get().format(new Date(10000)); + + STRICT_SERVLET_COMPLIANCE = Boolean.valueOf(System.getProperty( + "org.apache.catalina.STRICT_SERVLET_COMPLIANCE", + "false")).booleanValue(); + + + String alwaysAddExpires = System.getProperty( + "org.apache.tomcat.util.http.ServerCookie.ALWAYS_ADD_EXPIRES"); + if (alwaysAddExpires == null) { + ALWAYS_ADD_EXPIRES = !STRICT_SERVLET_COMPLIANCE; + } else { + ALWAYS_ADD_EXPIRES = + Boolean.valueOf(alwaysAddExpires).booleanValue(); + } + + String fwdSlashIsSeparator = System.getProperty( + "org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR"); + if (fwdSlashIsSeparator == null) { + FWD_SLASH_IS_SEPARATOR = STRICT_SERVLET_COMPLIANCE; + } else { + FWD_SLASH_IS_SEPARATOR = + Boolean.valueOf(fwdSlashIsSeparator).booleanValue(); + } + } // Note: Servlet Spec =< 2.5 only refers to Netscape and RFC2109, // not RFC2965 @@ -319,7 +350,13 @@ public class ServerCookie implements Serializable { if (version==0) { maybeQuote2(version, buf, path); } else { - maybeQuote2(version, buf, path, ServerCookie.tspecials2NoSlash, false); + if (FWD_SLASH_IS_SEPARATOR) { + maybeQuote2(version, buf, path, ServerCookie.tspecials, + false); + } else { + maybeQuote2(version, buf, path, + ServerCookie.tspecials2NoSlash, false); + } } } diff --git a/webapps/docs/config/systemprops.xml b/webapps/docs/config/systemprops.xml index ac8389316..998b26437 100644 --- a/webapps/docs/config/systemprops.xml +++ b/webapps/docs/config/systemprops.xml @@ -244,8 +244,15 @@ ServletContext.getResource/getResourceAsStream must start with "/"
if set to false, code like getResource("myfolder/myresource.txt") will work +
  • + The default value will be changed for + org.apache.tomcat.util.http.ServerCookie.ALWAYS_ADD_EXPIRES. + org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR. +
  • +

    Note that where setting this to true changes a default, + that can always be overridden by setting a system property explicitly.

    If this is true Tomcat will always add an expires parameter to a SetCookie header even for cookies with version greater than zero. This is to work around a known IE6 and IE7 bug that causes IE to - ignore the Max-Age parameter in a SetCookie header.If not specified, the - default value of true will be used.

    + ignore the Max-Age parameter in a SetCookie header. If not specified, the + default value will be used. If + org.apache.catalina.STRICT_SERVLET_COMPLIANCE is set to + true, the default of this setting will be false, + else the default value will be true.

    +
    + + +

    If this is true then the / (forward slash) character will + be treated as a separator. Note that this character is frequently used in + cookie path attributes and some browsers will fail to process a cookie if + the path attribute is quoted as is required by a strict adherence to the + specifications. If not specified, the default value will be used. If + org.apache.catalina.STRICT_SERVLET_COMPLIANCE is set to + true, the default of this setting will be true, + else the default value will be false.

    -- 2.11.0