Author: markt
Date: Wed Apr 29 09:38:29 2009
New Revision: 769730

URL: http://svn.apache.org/viewvc?rev=769730&view=rev
Log:
Fix bug 46597. Port all the cookie handling changes from Tomcat 6.

Modified:
    
tomcat/connectors/trunk/util/java/org/apache/tomcat/util/http/ServerCookie.java
    tomcat/container/tc5.5.x/webapps/docs/changelog.xml
    tomcat/container/tc5.5.x/webapps/docs/config/systemprops.xml

Modified: 
tomcat/connectors/trunk/util/java/org/apache/tomcat/util/http/ServerCookie.java
URL: 
http://svn.apache.org/viewvc/tomcat/connectors/trunk/util/java/org/apache/tomcat/util/http/ServerCookie.java?rev=769730&r1=769729&r2=769730&view=diff
==============================================================================
--- 
tomcat/connectors/trunk/util/java/org/apache/tomcat/util/http/ServerCookie.java 
(original)
+++ 
tomcat/connectors/trunk/util/java/org/apache/tomcat/util/http/ServerCookie.java 
Wed Apr 29 09:38:29 2009
@@ -18,11 +18,14 @@
 package org.apache.tomcat.util.http;
 
 import java.io.Serializable;
+import java.text.DateFormat;
 import java.text.FieldPosition;
+import java.text.SimpleDateFormat;
 import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
 
 import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.DateTool;
 import org.apache.tomcat.util.buf.MessageBytes;
 
 
@@ -50,6 +53,37 @@
     private int maxAge = -1;
     private int version = 0;
 
+    // Other fields
+    private static final String OLD_COOKIE_PATTERN =
+        "EEE, dd-MMM-yyyy HH:mm:ss z";
+    private static final ThreadLocal<DateFormat> OLD_COOKIE_FORMAT =
+        new ThreadLocal<DateFormat>() {
+        protected DateFormat initialValue() {
+            DateFormat df =
+                new SimpleDateFormat(OLD_COOKIE_PATTERN, Locale.US);
+            df.setTimeZone(TimeZone.getTimeZone("GMT"));
+            return df;
+        }
+    };
+    private static final String ancientDate;
+
+
+    static {
+        ancientDate = OLD_COOKIE_FORMAT.get().format(new Date(10000));
+    }
+
+    /**
+     * If set to true, we parse cookies according to the servlet spec,
+     */
+    public static final boolean STRICT_SERVLET_COMPLIANCE =
+        
Boolean.valueOf(System.getProperty("org.apache.catalina.STRICT_SERVLET_COMPLIANCE",
 "false")).booleanValue();
+
+    /**
+     * If set to false, we don't use the IE6/7 Max-Age/Expires work around
+     */
+    public static final boolean ALWAYS_ADD_EXPIRES =
+        
Boolean.valueOf(System.getProperty("org.apache.tomcat.util.http.ServerCookie.ALWAYS_ADD_EXPIRES",
 "true")).booleanValue();
+
     // Note: Servlet Spec =< 2.5 only refers to Netscape and RFC2109,
     // not RFC2965
 
@@ -127,6 +161,7 @@
     
     private static final String tspecials = ",; ";
     private static final String tspecials2 = "()<>@,;:\\\"/[]?={} \t";
+    private static final String tspecials2NoSlash = "()<>@,;:\\\"[]?={} \t";
 
     /*
      * Tests a string and returns true if the string counts as a
@@ -139,6 +174,11 @@
      *                  if it is not
      */
     public static boolean isToken(String value) {
+        return isToken(value,null);
+    }
+    
+    public static boolean isToken(String value, String literals) {
+        String tspecials = (literals==null?ServerCookie.tspecials:literals);
         if( value==null) return true;
         int len = value.length();
 
@@ -164,9 +204,13 @@
         }
         return false;
     }
-    
-        
+
     public static boolean isToken2(String value) {
+        return isToken2(value,null);
+    }
+
+    public static boolean isToken2(String value, String literals) {
+        String tspecials2 = (literals==null?ServerCookie.tspecials2:literals);
         if( value==null) return true;
         int len = value.length();
 
@@ -230,9 +274,6 @@
         }
     }
 
-    private static final String ancientDate =
-        DateTool.formatOldCookie(new Date(10000));
-
     // TODO RFC2965 fields also need to be passed
     public static void appendCookieValue( StringBuffer headerBuf,
                                           int version,
@@ -250,7 +291,7 @@
         buf.append("=");
         // Servlet implementation does not check anything else
         
-        maybeQuote2(version, buf, value);
+        version = maybeQuote2(version, buf, value,true);
 
         // Add version 1 specific information
         if (version == 1) {
@@ -273,28 +314,34 @@
         // Max-Age=secs ... or use old "Expires" format
         // TODO RFC2965 Discard
         if (maxAge >= 0) {
-            if (version == 0) {
+            if (version > 0) {
+                buf.append ("; Max-Age=");
+                buf.append (maxAge);
+            }
+            // IE6, IE7 and possibly other browsers don't understand Max-Age.
+            // They do understand Expires, even with V1 cookies!
+            if (version == 0 || ALWAYS_ADD_EXPIRES) {
                 // Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires Netscape format )
                 buf.append ("; Expires=");
                 // To expire immediately we need to set the time in past
                 if (maxAge == 0)
                     buf.append( ancientDate );
                 else
-                    DateTool.formatOldCookie
-                        (new Date( System.currentTimeMillis() +
-                                   maxAge *1000L), buf,
-                         new FieldPosition(0));
-
-            } else {
-                buf.append ("; Max-Age=");
-                buf.append (maxAge);
+                    OLD_COOKIE_FORMAT.get().format(
+                            new Date(System.currentTimeMillis() +
+                                    maxAge*1000L),
+                            buf, new FieldPosition(0));
             }
         }
 
         // Path=path
         if (path!=null) {
             buf.append ("; Path=");
-            maybeQuote2(version, buf, path);
+            if (version==0) {
+                maybeQuote2(version, buf, path);
+            } else {
+                maybeQuote2(version, buf, path, 
ServerCookie.tspecials2NoSlash, false);
+            }
         }
 
         // Secure
@@ -332,27 +379,40 @@
      * @param buf
      * @param value
      */
-    public static void maybeQuote2(int version, StringBuffer buf,
-            String value) {
+    public static int maybeQuote2 (int version, StringBuffer buf, String 
value) {
+        return maybeQuote2(version,buf,value,false);
+    }
+
+    public static int maybeQuote2 (int version, StringBuffer buf, String 
value, boolean allowVersionSwitch) {
+        return maybeQuote2(version,buf,value,null,allowVersionSwitch);
+    }
+
+    public static int maybeQuote2 (int version, StringBuffer buf, String 
value, String literals, boolean allowVersionSwitch) {
         if (value==null || value.length()==0) {
             buf.append("\"\"");
         } else if (containsCTL(value,version)) 
             throw new IllegalArgumentException("Control character in cookie 
value, consider BASE64 encoding your value");
         else if (alreadyQuoted(value)) {
             buf.append('"');
-            buf.append(escapeDoubleQuotes(value,1,value.length()-1));          
  buf.append('"');
+            buf.append(escapeDoubleQuotes(value,1,value.length()-1));
             buf.append('"');
-        } else if (version==0 && !isToken(value)) {
+        } else if (allowVersionSwitch && (!STRICT_SERVLET_COMPLIANCE) && 
version==0 && !isToken2(value, literals)) {
             buf.append('"');
             buf.append(escapeDoubleQuotes(value,0,value.length()));
             buf.append('"');
-        } else if (version==1 && !isToken2(value)) {
+            version = 1;
+        } else if (version==0 && !isToken(value,literals)) {
+            buf.append('"');
+            buf.append(escapeDoubleQuotes(value,0,value.length()));
+            buf.append('"');
+        } else if (version==1 && !isToken2(value,literals)) {
             buf.append('"');
             buf.append(escapeDoubleQuotes(value,0,value.length()));
             buf.append('"');
         } else {
             buf.append(value);
         }
+        return version;
     }
     
     /**

Modified: tomcat/container/tc5.5.x/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/container/tc5.5.x/webapps/docs/changelog.xml?rev=769730&r1=769729&r2=769730&view=diff
==============================================================================
--- tomcat/container/tc5.5.x/webapps/docs/changelog.xml (original)
+++ tomcat/container/tc5.5.x/webapps/docs/changelog.xml Wed Apr 29 09:38:29 2009
@@ -59,6 +59,10 @@
         (markt)
       </fix>
       <fix>
+        <bug>46597</bug>: Port all cookie handling changes from Tomcat 6.0.x.
+        (markt)
+      </fix>
+      <fix>
         <bug>45628</bug>: JARs that do not declare any dependencies should
         always be considered as fulfilled. (markt)
       </fix>

Modified: tomcat/container/tc5.5.x/webapps/docs/config/systemprops.xml
URL: 
http://svn.apache.org/viewvc/tomcat/container/tc5.5.x/webapps/docs/config/systemprops.xml?rev=769730&r1=769729&r2=769730&view=diff
==============================================================================
--- tomcat/container/tc5.5.x/webapps/docs/config/systemprops.xml (original)
+++ tomcat/container/tc5.5.x/webapps/docs/config/systemprops.xml Wed Apr 29 
09:38:29 2009
@@ -101,17 +101,32 @@
     <property name="org.apache.catalina. STRICT_SERVLET_COMPLIANCE">
       <p>If this is <code>true</code> the following actions will occur:
       <ul>
-      <li>any wrapped request or response object passed to an application
-      dispatcher will be checked to ensure that it has wrapped the original
-      request or response. (SRV.8.2 / SRV.14.2.5.1)
-      </li>
-      <li>when updating the access count for the session, the update will be
-      synchronized.
-      </li>
+        <li>any wrapped request or response object passed to an application
+          dispatcher will be checked to ensure that it has wrapped the original
+          request or response. (SRV.8.2 / SRV.14.2.5.1)
+        </li>
+        <li>when updating the access count for the session, the update will be
+          synchronized.
+        </li>
+        <li>
+          cookies will be parsed strictly, by default v0 cookies will not work
+          with any invalid characters.<br/>If set to false, any v0 cookie with
+          invalid character will be switched to a v1 cookie and the value will
+          be quoted.
+        </li>
       </ul>
       </p>
     </property>
 
+    <property
+    name="org.apache.tomcat.util.http. ServerCookie.ALWAYS_ADD_EXPIRES">
+      <p>If this is <code>true</code> 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 <code>true</code> will be used.</p>
+    </property>
+
   </properties>
 
 </section>



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to