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 2017/02/27 14:04:09 UTC

svn commit: r1784565 - in /tomcat/trunk: java/org/apache/tomcat/util/http/CookieProcessorBase.java java/org/apache/tomcat/util/http/LegacyCookieProcessor.java java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java webapps/docs/changelog.xml

Author: markt
Date: Mon Feb 27 14:04:09 2017
New Revision: 1784565

URL: http://svn.apache.org/viewvc?rev=1784565&view=rev
Log:
Modify the cookie header generated by the Rfc6265CookieProcessor so it always sends an Expires attribute as well as a Max-Age attribute to avoid problems with Microsoft browsers that do not support the Max-Age attribute.
Note the code that sets the Expires attribute was refactored from the LegacyCookieProcessor into a new, common base class. 

Added:
    tomcat/trunk/java/org/apache/tomcat/util/http/CookieProcessorBase.java
Modified:
    tomcat/trunk/java/org/apache/tomcat/util/http/LegacyCookieProcessor.java
    tomcat/trunk/java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java
    tomcat/trunk/webapps/docs/changelog.xml

Added: tomcat/trunk/java/org/apache/tomcat/util/http/CookieProcessorBase.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/CookieProcessorBase.java?rev=1784565&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/http/CookieProcessorBase.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/util/http/CookieProcessorBase.java Mon Feb 27 14:04:09 2017
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.tomcat.util.http;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+public abstract class CookieProcessorBase implements CookieProcessor {
+
+    private static final String COOKIE_DATE_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z";
+
+    protected static final ThreadLocal<DateFormat> COOKIE_DATE_FORMAT =
+        new ThreadLocal<DateFormat>() {
+        @Override
+        protected DateFormat initialValue() {
+            DateFormat df =
+                new SimpleDateFormat(COOKIE_DATE_PATTERN, Locale.US);
+            df.setTimeZone(TimeZone.getTimeZone("GMT"));
+            return df;
+        }
+    };
+
+    protected static final String ANCIENT_DATE;
+
+    static {
+        ANCIENT_DATE = COOKIE_DATE_FORMAT.get().format(new Date(10000));
+    }
+}

Modified: tomcat/trunk/java/org/apache/tomcat/util/http/LegacyCookieProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/LegacyCookieProcessor.java?rev=1784565&r1=1784564&r2=1784565&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/http/LegacyCookieProcessor.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/http/LegacyCookieProcessor.java Mon Feb 27 14:04:09 2017
@@ -18,13 +18,9 @@ package org.apache.tomcat.util.http;
 
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
-import java.text.DateFormat;
 import java.text.FieldPosition;
-import java.text.SimpleDateFormat;
 import java.util.BitSet;
 import java.util.Date;
-import java.util.Locale;
-import java.util.TimeZone;
 
 import javax.servlet.http.Cookie;
 
@@ -44,7 +40,7 @@ import org.apache.tomcat.util.res.String
  * @author Costin Manolache
  * @author kevin seguin
  */
-public final class LegacyCookieProcessor implements CookieProcessor {
+public final class LegacyCookieProcessor extends CookieProcessorBase {
 
     private static final Log log = LogFactory.getLog(LegacyCookieProcessor.class);
 
@@ -62,26 +58,10 @@ public final class LegacyCookieProcessor
             '\t', ' ', '\"', '(', ')', ',', ':', ';', '<', '=', '>', '?', '@',
             '[', '\\', ']', '{', '}' };
 
-    private static final String COOKIE_DATE_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z";
-    private static final ThreadLocal<DateFormat> COOKIE_DATE_FORMAT =
-        new ThreadLocal<DateFormat>() {
-        @Override
-        protected DateFormat initialValue() {
-            DateFormat df =
-                new SimpleDateFormat(COOKIE_DATE_PATTERN, Locale.US);
-            df.setTimeZone(TimeZone.getTimeZone("GMT"));
-            return df;
-        }
-    };
-
-    private static final String ANCIENT_DATE;
-
     static {
         for (char c : V0_SEPARATORS) {
             V0_SEPARATOR_FLAGS.set(c);
         }
-
-        ANCIENT_DATE = COOKIE_DATE_FORMAT.get().format(new Date(10000));
     }
 
     private final boolean STRICT_SERVLET_COMPLIANCE =

Modified: tomcat/trunk/java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java?rev=1784565&r1=1784564&r2=1784565&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java Mon Feb 27 14:04:09 2017
@@ -18,7 +18,9 @@ package org.apache.tomcat.util.http;
 
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
+import java.text.FieldPosition;
 import java.util.BitSet;
+import java.util.Date;
 
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
@@ -27,7 +29,7 @@ import org.apache.tomcat.util.buf.Messag
 import org.apache.tomcat.util.http.parser.Cookie;
 import org.apache.tomcat.util.res.StringManager;
 
-public class Rfc6265CookieProcessor implements CookieProcessor {
+public class Rfc6265CookieProcessor extends CookieProcessorBase {
 
     private static final Log log = LogFactory.getLog(Rfc6265CookieProcessor.class);
 
@@ -98,7 +100,9 @@ public class Rfc6265CookieProcessor impl
     @Override
     public String generateHeader(javax.servlet.http.Cookie cookie) {
 
-        StringBuilder header = new StringBuilder();
+        // Can't use StringBuilder due to DateFormat
+        StringBuffer header = new StringBuffer();
+
         // TODO: Name validation takes place in Cookie and cannot be configured
         //       per Context. Moving it to here would allow per Context config
         //       but delay validation until the header is generated. However,
@@ -112,12 +116,28 @@ public class Rfc6265CookieProcessor impl
             header.append(value);
         }
 
-        // RFC 6265 prefers Max-Age to Expires so use Max-Age
+        // RFC 6265 prefers Max-Age to Expires but... (see below)
         int maxAge = cookie.getMaxAge();
         if (maxAge > -1) {
             // Negative Max-Age is equivalent to no Max-Age
             header.append(";Max-Age=");
             header.append(maxAge);
+
+            // Microsoft IE and Microsoft Edge don't understand Max-Age so send
+            // expires as well. Without this, persistent cookies fail with those
+            // browsers. See http://tomcat.markmail.org/thread/g6sipbofsjossacn
+
+            // Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires Netscape format )
+            header.append ("; Expires=");
+            // To expire immediately we need to set the time in past
+            if (maxAge == 0) {
+                header.append(ANCIENT_DATE);
+            } else {
+                COOKIE_DATE_FORMAT.get().format(
+                        new Date(System.currentTimeMillis() + maxAge * 1000L),
+                        header,
+                        new FieldPosition(0));
+            }
         }
 
         String domain = cookie.getDomain();

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1784565&r1=1784564&r2=1784565&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Mon Feb 27 14:04:09 2017
@@ -175,6 +175,13 @@
         expectation is that configuration will be performed via a JSSE provider
         specific mechanisms. (markt)
       </fix>
+      <fix>
+        Modify the cookie header generated by the
+        <code>Rfc6265CookieProcessor</code> so it always sends an
+        <code>Expires</code> attribute as well as a <code>Max-Age</code>
+        attribute to avoid problems with Microsoft browsers that do not support
+        the <code>Max-Age</code> attribute. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Jasper">



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