Author: markt
Date: Thu Sep 25 19:38:15 2014
New Revision: 1627619

URL: http://svn.apache.org/r1627619
Log:
Refactor cookie parsing to make it more pluggable

Added:
    tomcat/trunk/java/org/apache/tomcat/util/http/CookieProcessor.java   (with 
props)
    tomcat/trunk/java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java   
(with props)
Modified:
    tomcat/trunk/java/org/apache/catalina/Context.java
    tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java
    tomcat/trunk/java/org/apache/catalina/connector/Request.java
    tomcat/trunk/java/org/apache/catalina/core/StandardContext.java
    tomcat/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml
    tomcat/trunk/java/org/apache/catalina/startup/ContextRuleSet.java
    tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java
    tomcat/trunk/java/org/apache/coyote/Request.java
    tomcat/trunk/java/org/apache/tomcat/util/http/Cookies.java
    tomcat/trunk/test/org/apache/catalina/core/TesterContext.java
    tomcat/trunk/test/org/apache/tomcat/util/http/TestCookies.java
    tomcat/trunk/test/org/apache/tomcat/util/http/TesterCookiesPerformance.java
    tomcat/trunk/webapps/docs/config/context.xml

Modified: tomcat/trunk/java/org/apache/catalina/Context.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/Context.java?rev=1627619&r1=1627618&r2=1627619&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/Context.java (original)
+++ tomcat/trunk/java/org/apache/catalina/Context.java Thu Sep 25 19:38:15 2014
@@ -17,7 +17,6 @@
 package org.apache.catalina;
 
 import java.net.URL;
-import java.nio.charset.Charset;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
@@ -38,6 +37,7 @@ import org.apache.tomcat.util.descriptor
 import org.apache.tomcat.util.descriptor.web.FilterMap;
 import org.apache.tomcat.util.descriptor.web.LoginConfig;
 import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
+import org.apache.tomcat.util.http.CookieProcessor;
 
 /**
  * A <b>Context</b> is a Container that represents a servlet context, and
@@ -1640,38 +1640,16 @@ public interface Context extends Contain
     public Object getNamingToken();
 
     /**
-     * Should this context use the new RFC6265 based cookie parser for
-     * processing HTTP cookies? The default value is currently false but that
-     * may change in a future point release.
-     */
-    public void setUseRfc6265(boolean useRfc6265);
-
-    /**
-     * Does this context use the new RFC6265 based cookie parser for
-     * processing HTTP cookies? The default value is currently false but that
-     * may change in a future point release.
-     */
-    public boolean getUseRfc6265();
-
-    /**
-     * Specifies the name of the character encoding to use to convert bytes 
into
-     * characters when processing cookies using the RFC6265 based cookie 
parser.
-     * It has no effect if the RFC6265 parser is not used.
-     * If an unrecognised character encoding is specified, a warning will be
-     * logged and the default value of UTF-8 will be used.
-     */
-    public void setCookieEncoding(String encoding);
-
-    /**
-     * Returns the name of the character encoding used to convert bytes into
-     * characters when processing cookies using the RFC6265 based cookie 
parser.
-     * The default value is UTF-8.
+     * Sets the {@link CookieProcessor} that will be used to process cookies
+     * for this Context.
+     *
+     * @param cookieProcessor   The new cookie processor
      */
-    public String getCookieEncoding();
+    public void setCookieProcessor(CookieProcessor cookieProcessor);
 
     /**
-     * Returns the character set used to convert bytes into characters when
-     * processing cookies using the RFC6265 based cookie parser.
+     * Obtains the {@link CookieProcessor} that will be used to process cookies
+     * for this Context.
      */
-    public Charset getCookieEncodingCharset();
+    public CookieProcessor getCookieProcessor();
 }

Modified: tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java?rev=1627619&r1=1627618&r2=1627619&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java 
(original)
+++ tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java Thu Sep 
25 19:38:15 2014
@@ -46,8 +46,8 @@ import org.apache.tomcat.util.buf.B2CCon
 import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.buf.CharChunk;
 import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.http.Cookies;
 import org.apache.tomcat.util.http.ServerCookie;
+import org.apache.tomcat.util.http.ServerCookies;
 import org.apache.tomcat.util.net.SSLSupport;
 import org.apache.tomcat.util.net.SocketStatus;
 import org.apache.tomcat.util.res.StringManager;
@@ -903,15 +903,8 @@ public class CoyoteAdapter implements Ad
                 }
             }
 
-            if (request.getContext().getUseRfc6265()) {
-                req.getCookies().setUseRfc6265(true);
-            } else {
-                req.getCookies().setUseRfc6265(false);
-            }
-
-
             // Look for session ID in cookies and SSL session
-            parseSessionCookiesId(req, request);
+            parseSessionCookiesId(request);
             parseSessionSslId(request);
 
             sessionID = request.getRequestedSessionId();
@@ -1145,7 +1138,7 @@ public class CoyoteAdapter implements Ad
     /**
      * Parse session id in URL.
      */
-    protected void parseSessionCookiesId(org.apache.coyote.Request req, 
Request request) {
+    protected void parseSessionCookiesId(Request request) {
 
         // If session tracking via cookies has been disabled for the current
         // context, don't go looking for a session ID in a cookie as a cookie
@@ -1159,7 +1152,7 @@ public class CoyoteAdapter implements Ad
         }
 
         // Parse session id from cookies
-        Cookies serverCookies = req.getCookies();
+        ServerCookies serverCookies = request.getServerCookies();
         int count = serverCookies.getCookieCount();
         if (count <= 0) {
             return;

Modified: tomcat/trunk/java/org/apache/catalina/connector/Request.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/connector/Request.java?rev=1627619&r1=1627618&r2=1627619&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/connector/Request.java (original)
+++ tomcat/trunk/java/org/apache/catalina/connector/Request.java Thu Sep 25 
19:38:15 2014
@@ -84,10 +84,11 @@ import org.apache.tomcat.util.ExceptionU
 import org.apache.tomcat.util.buf.B2CConverter;
 import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.http.Cookies;
+import org.apache.tomcat.util.http.CookieProcessor;
 import org.apache.tomcat.util.http.FastHttpDateFormat;
 import org.apache.tomcat.util.http.Parameters;
 import org.apache.tomcat.util.http.ServerCookie;
+import org.apache.tomcat.util.http.ServerCookies;
 import org.apache.tomcat.util.http.fileupload.FileItem;
 import org.apache.tomcat.util.http.fileupload.FileUploadBase;
 import 
org.apache.tomcat.util.http.fileupload.FileUploadBase.InvalidContentTypeException;
@@ -283,12 +284,20 @@ public class Request
 
 
     /**
-     * Cookies parsed flag.
+     * Cookie headers parsed flag. Indicates that the cookie headers have been
+     * parsed into ServerCookies.
      */
     protected boolean cookiesParsed = false;
 
 
     /**
+     * Cookie parsed flag. Indicates that the ServerCookies have been converted
+     * into user facing Cookie objects.
+     */
+    protected boolean cookiesConverted = false;
+
+
+    /**
      * Secure flag.
      */
     protected boolean secure = false;
@@ -462,6 +471,7 @@ public class Request
         }
         partsParseException = null;
         cookiesParsed = false;
+        cookiesConverted = false;
         locales.clear();
         localesParsed = false;
         secure = false;
@@ -1668,7 +1678,7 @@ public class Request
     public void addCookie(Cookie cookie) {
 
         if (!cookiesParsed) {
-            parseCookies();
+            convertCookies();
         }
 
         int size = 0;
@@ -1703,6 +1713,7 @@ public class Request
      */
     public void clearCookies() {
         cookiesParsed = true;
+        cookiesConverted = true;
         cookies = null;
     }
 
@@ -1899,17 +1910,27 @@ public class Request
 
 
     /**
-     * Return the set of Cookies received with this Request.
+     * Return the set of Cookies received with this Request. Triggers parsing 
of
+     * the Cookie HTTP headers followed by conversion to Cookie objects if this
+     * has not already been performed.
      */
     @Override
     public Cookie[] getCookies() {
-
-        if (!cookiesParsed) {
-            parseCookies();
+        if (!cookiesConverted) {
+            convertCookies();
         }
-
         return cookies;
+    }
+
 
+    /**
+     * Return the server representation of the cookies associated with this
+     * request. Triggers parsing of the Cookie HTTP headers (but not conversion
+     * to Cookie objects) if the headers have not yet been parsed.
+     */
+    public ServerCookies getServerCookies() {
+        parseCookies();
+        return coyoteRequest.getCookies();
     }
 
 
@@ -2841,13 +2862,37 @@ public class Request
     }
 
     /**
-     * Parse cookies.
+     * Parse cookies. This only parses the cookies into the memory efficient
+     * ServerCookies structure. It does not populate the Cookie objects.
      */
     protected void parseCookies() {
+        if (cookiesParsed) {
+            return;
+        }
 
         cookiesParsed = true;
 
-        Cookies serverCookies = coyoteRequest.getCookies();
+        ServerCookies serverCookies = coyoteRequest.getCookies();
+        CookieProcessor cookieProcessor = getContext().getCookieProcessor();
+        cookieProcessor.parseCookieHeader(coyoteRequest.getMimeHeaders(), 
serverCookies);
+    }
+
+    /**
+     * Converts the parsed cookies (parsing the Cookie headers first if they
+     * have not been parsed) into Cookie objects.
+     */
+    protected void convertCookies() {
+        if (cookiesConverted) {
+            return;
+        }
+
+        cookiesConverted = true;
+
+        parseCookies();
+
+        ServerCookies serverCookies = coyoteRequest.getCookies();
+        CookieProcessor cookieProcessor = getContext().getCookieProcessor();
+
         int count = serverCookies.getCookieCount();
         if (count <= 0) {
             return;
@@ -2865,10 +2910,7 @@ public class Request
                 Cookie cookie = new Cookie(scookie.getName().toString(),null);
                 int version = scookie.getVersion();
                 cookie.setVersion(version);
-                if (getContext().getUseRfc6265()) {
-                    scookie.getValue().getByteChunk().setCharset(
-                            getContext().getCookieEncodingCharset());
-                }
+                
scookie.getValue().getByteChunk().setCharset(cookieProcessor.getCharset());
                 cookie.setValue(unescape(scookie.getValue().toString()));
                 cookie.setPath(unescape(scookie.getPath().toString()));
                 String domain = scookie.getDomain().toString();
@@ -2888,9 +2930,9 @@ public class Request
             System.arraycopy(cookies, 0, ncookies, 0, idx);
             cookies = ncookies;
         }
-
     }
 
+
     /**
      * Parse request parameters.
      */

Modified: tomcat/trunk/java/org/apache/catalina/core/StandardContext.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardContext.java?rev=1627619&r1=1627618&r2=1627619&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/StandardContext.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/StandardContext.java Thu Sep 25 
19:38:15 2014
@@ -21,11 +21,8 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
@@ -118,7 +115,6 @@ import org.apache.tomcat.InstanceManager
 import org.apache.tomcat.JarScanner;
 import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.IntrospectionUtils;
-import org.apache.tomcat.util.buf.B2CConverter;
 import org.apache.tomcat.util.buf.UDecoder;
 import org.apache.tomcat.util.descriptor.XmlIdentifiers;
 import org.apache.tomcat.util.descriptor.web.ApplicationParameter;
@@ -132,6 +128,8 @@ import org.apache.tomcat.util.descriptor
 import org.apache.tomcat.util.descriptor.web.MessageDestinationRef;
 import org.apache.tomcat.util.descriptor.web.SecurityCollection;
 import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
+import org.apache.tomcat.util.http.CookieProcessor;
+import org.apache.tomcat.util.http.Cookies;
 import org.apache.tomcat.util.scan.StandardJarScanner;
 import org.apache.tomcat.util.security.PrivilegedGetTccl;
 import org.apache.tomcat.util.security.PrivilegedSetTccl;
@@ -825,46 +823,23 @@ public class StandardContext extends Con
 
     private final Object namingToken = new Object();
 
-    private boolean useRfc6265 = false;
-    private Charset cookieEncoding = StandardCharsets.UTF_8;
+    private CookieProcessor cookieProcessor;
 
 
     // ----------------------------------------------------- Context Properties
 
-
     @Override
-    public void setUseRfc6265(boolean useRfc6265) {
-        this.useRfc6265 = useRfc6265;
+    public void setCookieProcessor(CookieProcessor cookieProcessor) {
+        this.cookieProcessor = cookieProcessor;
     }
 
 
     @Override
-    public boolean getUseRfc6265() {
-        return useRfc6265;
-    }
-
-
-    @Override
-    public void setCookieEncoding(String encoding) {
-        try {
-            Charset charset = B2CConverter.getCharset(encoding);
-            cookieEncoding = charset;
-        } catch (UnsupportedEncodingException uee) {
-            cookieEncoding = StandardCharsets.UTF_8;
-            log.warn(sm.getString("standardContext.unknownCookieEncoding"), 
uee);
+    public CookieProcessor getCookieProcessor() {
+        if (cookieProcessor == null) {
+            cookieProcessor = new Cookies();
         }
-    }
-
-
-    @Override
-    public String getCookieEncoding() {
-        return cookieEncoding.name();
-    }
-
-
-    @Override
-    public Charset getCookieEncodingCharset() {
-        return cookieEncoding;
+        return cookieProcessor;
     }
 
 

Modified: tomcat/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml?rev=1627619&r1=1627618&r2=1627619&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml (original)
+++ tomcat/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml Thu Sep 
25 19:38:15 2014
@@ -103,10 +103,6 @@
                type="boolean"
                writeable="false" />
 
-    <attribute name="cookieEncoding"
-               description="If the new cookie parser is used, which encoding 
should be used to decode the cookie values?"
-               type="java.lang.String"/>
-
     <attribute name="cookies"
                description="Should we attempt to use cookies for session id 
communication?"
                type="boolean"/>
@@ -335,11 +331,6 @@
                is="true"
                type="boolean"/>
 
-    <attribute name="useNewCookieParser"
-               description="Use the new RFC6265 based cookie parser"
-               is="false"
-               type="boolean"/>
-
     <attribute name="webappVersion"
                description="The version of this web application - used in 
parallel deployment to differentiate different versions of the same web 
application"
                type="java.lang.String"

Modified: tomcat/trunk/java/org/apache/catalina/startup/ContextRuleSet.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/ContextRuleSet.java?rev=1627619&r1=1627618&r2=1627619&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/ContextRuleSet.java (original)
+++ tomcat/trunk/java/org/apache/catalina/startup/ContextRuleSet.java Thu Sep 
25 19:38:15 2014
@@ -242,6 +242,13 @@ public class ContextRuleSet extends Rule
                             "setJarScanFilter",
                             "org.apache.tomcat.JarScanFilter");
 
+        digester.addObjectCreate(prefix + "Context/CookieProcessor",
+                                 "org.apache.tomcat.util.http.Cookies",
+                                 "className");
+        digester.addSetProperties(prefix + "Context/CookieProcessor");
+        digester.addSetNext(prefix + "Context/CookieProcessor",
+                            "setCookieProcessor",
+                            "org.apache.tomcat.util.http.CookieProcessor");
     }
 
 }

Modified: tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java?rev=1627619&r1=1627618&r2=1627619&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java (original)
+++ tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java Thu Sep 25 
19:38:15 2014
@@ -19,8 +19,6 @@ package org.apache.catalina.startup;
 import java.beans.PropertyChangeListener;
 import java.io.File;
 import java.net.URL;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
@@ -63,6 +61,7 @@ import org.apache.tomcat.util.descriptor
 import org.apache.tomcat.util.descriptor.web.FilterMap;
 import org.apache.tomcat.util.descriptor.web.LoginConfig;
 import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
+import org.apache.tomcat.util.http.CookieProcessor;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
@@ -758,17 +757,8 @@ public class FailedContext extends Lifec
     public Object getNamingToken() { return null; }
 
     @Override
-    public void setUseRfc6265(boolean useRfc6265) { /* NO-OP */ }
+    public void setCookieProcessor(CookieProcessor cookieProcessor) { /* NO-OP 
*/ }
 
     @Override
-    public boolean getUseRfc6265() {return false; }
-
-    @Override
-    public void setCookieEncoding(String encoding) { /* NO-OP */ }
-
-    @Override
-    public String getCookieEncoding() { return "UTF-8"; }
-
-    @Override
-    public Charset getCookieEncodingCharset() { return StandardCharsets.UTF_8; 
}
+    public CookieProcessor getCookieProcessor() { return null; }
 }
\ No newline at end of file

Modified: tomcat/trunk/java/org/apache/coyote/Request.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/Request.java?rev=1627619&r1=1627618&r2=1627619&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/Request.java (original)
+++ tomcat/trunk/java/org/apache/coyote/Request.java Thu Sep 25 19:38:15 2014
@@ -25,9 +25,9 @@ import javax.servlet.ReadListener;
 import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.buf.MessageBytes;
 import org.apache.tomcat.util.buf.UDecoder;
-import org.apache.tomcat.util.http.Cookies;
 import org.apache.tomcat.util.http.MimeHeaders;
 import org.apache.tomcat.util.http.Parameters;
+import org.apache.tomcat.util.http.ServerCookies;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
@@ -62,6 +62,8 @@ public final class Request {
     private static final StringManager sm =
             StringManager.getManager(Constants.Package);
 
+    // Expected maximum typica number of cookies per request.
+    private static final int INITIAL_COOKIE_SIZE = 4;
 
     // ----------------------------------------------------------- Constructors
 
@@ -121,7 +123,8 @@ public final class Request {
     private long contentLength = -1;
     private MessageBytes contentTypeMB = null;
     private String charEncoding = null;
-    private final Cookies cookies = new Cookies(headers);
+
+    private final ServerCookies serverCookies = new 
ServerCookies(INITIAL_COOKIE_SIZE);
     private final Parameters parameters = new Parameters();
 
     private final MessageBytes remoteUser=MessageBytes.newInstance();
@@ -381,15 +384,13 @@ public final class Request {
 
     // -------------------- Cookies --------------------
 
-
-    public Cookies getCookies() {
-        return cookies;
+    public ServerCookies getCookies() {
+        return serverCookies;
     }
 
 
     // -------------------- Parameters --------------------
 
-
     public Parameters getParameters() {
         return parameters;
     }
@@ -528,7 +529,7 @@ public final class Request {
         remotePort = -1;
         available = 0;
 
-        cookies.recycle();
+        serverCookies.recycle();
         parameters.recycle();
 
         uriMB.recycle();

Added: tomcat/trunk/java/org/apache/tomcat/util/http/CookieProcessor.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/CookieProcessor.java?rev=1627619&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/http/CookieProcessor.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/util/http/CookieProcessor.java Thu Sep 
25 19:38:15 2014
@@ -0,0 +1,33 @@
+/*
+ *  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.nio.charset.Charset;
+
+public interface CookieProcessor {
+
+    /**
+     * Parse the provided headers into server cookie objects.
+     */
+    void parseCookieHeader(MimeHeaders headers, ServerCookies serverCookies);
+
+    /**
+     * The character set that is to be used to turn the bytes provided in the
+     * cookie header into characters for the cookie value.
+     */
+    Charset getCharset();
+}

Propchange: tomcat/trunk/java/org/apache/tomcat/util/http/CookieProcessor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/java/org/apache/tomcat/util/http/Cookies.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/Cookies.java?rev=1627619&r1=1627618&r2=1627619&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/http/Cookies.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/http/Cookies.java Thu Sep 25 
19:38:15 2014
@@ -16,14 +16,13 @@
  */
 package org.apache.tomcat.util.http;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.buf.ByteChunk;
 import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.http.parser.Cookie;
 import org.apache.tomcat.util.log.UserDataHelper;
 import org.apache.tomcat.util.res.StringManager;
 
@@ -36,7 +35,7 @@ import org.apache.tomcat.util.res.String
  * @author Costin Manolache
  * @author kevin seguin
  */
-public final class Cookies {
+public final class Cookies implements CookieProcessor {
 
     private static final Log log = LogFactory.getLog(Cookies.class);
 
@@ -45,72 +44,16 @@ public final class Cookies {
     private static final StringManager sm =
             StringManager.getManager("org.apache.tomcat.util.http");
 
-    // expected average number of cookies per request
-    public static final int INITIAL_SIZE = 4;
-    private ServerCookies scookies = new ServerCookies(INITIAL_SIZE);
-    private boolean unprocessed = true;
-    private boolean useRfc6265 = false;
 
-    private final MimeHeaders headers;
-
-
-    /**
-     *  Construct a new cookie collection, that will extract
-     *  the information from headers.
-     *
-     * @param headers Cookies are lazy-evaluated and will extract the
-     *     information from the provided headers.
-     */
-    public Cookies(MimeHeaders headers) {
-        this.headers = headers;
-    }
-
-
-    public void recycle() {
-        scookies.recycle();
-        unprocessed = true;
-        useRfc6265 = false;
-    }
-
-
-    /**
-     * EXPENSIVE!!!  only for debugging.
-     */
     @Override
-    public String toString() {
-        StringWriter sw = new StringWriter();
-        PrintWriter pw = new PrintWriter(sw);
-        pw.println("=== Cookies ===");
-        int count = getCookieCount();
-        for (int i = 0; i < count; ++i) {
-            pw.println(getCookie(i).toString());
-        }
-        return sw.toString();
+    public Charset getCharset() {
+        return StandardCharsets.ISO_8859_1;
     }
 
 
-    /**
-     * Indexed access.
-     */
-    public ServerCookie getCookie(int idx) {
-        if (unprocessed) {
-            // This will trigger cookie processing
-            getCookieCount();
-        }
-        return scookies.getCookie(idx);
-    }
-
-
-    public int getCookieCount() {
-        if (unprocessed) {
-            unprocessed = false;
-            processCookies(headers);
-        }
-        return scookies.getCookieCount();
-    }
-
+    @Override
+    public void parseCookieHeader(MimeHeaders headers, ServerCookies 
serverCookies) {
 
-    private void processCookies(MimeHeaders headers) {
         if (headers == null) {
             // nothing to process
             return;
@@ -135,10 +78,11 @@ public final class Cookies {
                     if (len > 0) {
                         byte[] buf = new byte[len];
                         System.arraycopy(bc.getBytes(), bc.getOffset(), buf, 
0, len);
-                        processCookieHeader(buf, 0, len);
+                        processCookieHeader(buf, 0, len, serverCookies);
                     }
                 } else {
-                    processCookieHeader(bc.getBytes(), bc.getOffset(), 
bc.getLength());
+                    processCookieHeader(bc.getBytes(), bc.getOffset(), 
bc.getLength(),
+                            serverCookies);
                 }
             }
 
@@ -148,100 +92,15 @@ public final class Cookies {
     }
 
 
-    public void setUseRfc6265(boolean useRfc6265) {
-        this.useRfc6265 = useRfc6265;
-    }
-
-
-    // XXX will be refactored soon!
-    private static boolean equals(String s, byte b[], int start, int end) {
-        int blen = end-start;
-        if (b == null || blen != s.length()) {
-            return false;
-        }
-        int boff = start;
-        for (int i = 0; i < blen; i++) {
-            if (b[boff++] != s.charAt(i)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-
-    /**
-     * Returns true if the byte is a whitespace character as
-     * defined in RFC2619
-     * JVK
-     */
-    private 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;
-        }
-    }
-
-
-    /**
-     * Unescapes any double quotes in the given cookie value.
-     *
-     * @param bc The cookie value to modify
-     */
-    private 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);
-    }
-
-
-    final void processCookieHeader(byte bytes[], int off, int len) {
-        if (useRfc6265) {
-            Cookie.parseCookie(bytes, off, len, scookies);
-        } else {
-            doProcessCookieHeaderOriginal(bytes, off, len);
-        }
-    }
-
-
     /**
      * Parses a cookie header after the initial "Cookie:"
      * [WS][$]token[WS]=[WS](token|QV)[;|,]
      * RFC 2965 / RFC 2109
      * JVK
      */
-    private void doProcessCookieHeaderOriginal(byte bytes[], int off, int len){
+    private static final void processCookieHeader(byte bytes[], int off, int 
len,
+            ServerCookies serverCookies) {
+
         if (len <= 0 || bytes == null) {
             return;
         }
@@ -460,7 +319,7 @@ public final class Cookies {
                     continue;
                 }
 
-                sc = scookies.addCookie();
+                sc = serverCookies.addCookie();
                 sc.setVersion( version );
                 sc.getName().setBytes( bytes, nameStart,
                                        nameEnd-nameStart);
@@ -527,4 +386,76 @@ public final class Cookies {
         // Error, we have reached the end of the header w/o a end quote
         return end;
     }
+
+
+    private static final boolean equals(String s, byte b[], int start, int 
end) {
+        int blen = end-start;
+        if (b == null || blen != s.length()) {
+            return false;
+        }
+        int boff = start;
+        for (int i = 0; i < blen; i++) {
+            if (b[boff++] != s.charAt(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+
+    /**
+     * Returns true if the byte is a whitespace character as
+     * defined in RFC2619
+     * JVK
+     */
+    private 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;
+        }
+    }
+
+
+    /**
+     * Unescapes any double quotes in the given cookie value.
+     *
+     * @param bc The cookie value to modify
+     */
+    private static final 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);
+    }
 }

Added: 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=1627619&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java 
(added)
+++ tomcat/trunk/java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java 
Thu Sep 25 19:38:15 2014
@@ -0,0 +1,71 @@
+/*
+ *  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.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.parser.Cookie;
+
+public class Rfc6265CookieProcessor implements CookieProcessor {
+
+    private static final Log log = 
LogFactory.getLog(Rfc6265CookieProcessor.class);
+
+    @Override
+    public Charset getCharset() {
+        return StandardCharsets.UTF_8;
+    }
+
+
+    @Override
+    public void parseCookieHeader(MimeHeaders headers,
+            ServerCookies serverCookies) {
+
+        if (headers == null) {
+            // nothing to process
+            return;
+        }
+
+        // process each "cookie" header
+        int pos = headers.findHeader("Cookie", 0);
+        while (pos >= 0) {
+            MessageBytes cookieValue = headers.getValue(pos);
+
+            if (cookieValue != null && !cookieValue.isNull() ) {
+                if (cookieValue.getType() != MessageBytes.T_BYTES ) {
+                    Exception e = new Exception();
+                    log.warn("Cookies: Parsing cookie as String. Expected 
bytes.", e);
+                    cookieValue.toBytes();
+                }
+                if (log.isDebugEnabled()) {
+                    log.debug("Cookies: Parsing b[]: " + 
cookieValue.toString());
+                }
+                ByteChunk bc = cookieValue.getByteChunk();
+
+                Cookie.parseCookie(bc.getBytes(), bc.getOffset(), 
bc.getLength(),
+                        serverCookies);
+            }
+
+            // search from the next position
+            pos = headers.findHeader("Cookie", ++pos);
+        }
+    }
+}

Propchange: 
tomcat/trunk/java/org/apache/tomcat/util/http/Rfc6265CookieProcessor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/test/org/apache/catalina/core/TesterContext.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/core/TesterContext.java?rev=1627619&r1=1627618&r2=1627619&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/core/TesterContext.java (original)
+++ tomcat/trunk/test/org/apache/catalina/core/TesterContext.java Thu Sep 25 
19:38:15 2014
@@ -19,8 +19,6 @@ package org.apache.catalina.core;
 import java.beans.PropertyChangeListener;
 import java.io.File;
 import java.net.URL;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
@@ -64,6 +62,7 @@ import org.apache.tomcat.util.descriptor
 import org.apache.tomcat.util.descriptor.web.FilterMap;
 import org.apache.tomcat.util.descriptor.web.LoginConfig;
 import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
+import org.apache.tomcat.util.http.CookieProcessor;
 
 /**
  * Minimal implementation for use in unit tests.
@@ -1220,22 +1219,11 @@ public class TesterContext implements Co
     }
 
     @Override
-    public Object getNamingToken() {
-        return null;
-    }
-
-    @Override
-    public void setUseRfc6265(boolean useRfc6265) { /* NO-OP */ }
-
-    @Override
-    public boolean getUseRfc6265() {return false; }
-
-    @Override
-    public void setCookieEncoding(String encoding) { /* NO-OP */ }
+    public Object getNamingToken() { return null; }
 
     @Override
-    public String getCookieEncoding() { return "UTF-8"; }
+    public void setCookieProcessor(CookieProcessor cookieProcessor) { /* NO-OP 
*/ }
 
     @Override
-    public Charset getCookieEncodingCharset() { return StandardCharsets.UTF_8; 
}
+    public CookieProcessor getCookieProcessor() { return null; }
 }

Modified: tomcat/trunk/test/org/apache/tomcat/util/http/TestCookies.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/http/TestCookies.java?rev=1627619&r1=1627618&r2=1627619&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/util/http/TestCookies.java (original)
+++ tomcat/trunk/test/org/apache/tomcat/util/http/TestCookies.java Thu Sep 25 
19:38:15 2014
@@ -472,16 +472,22 @@ public class TestCookies {
 
     private void test(boolean useRfc6265, String header, Cookie... expected) {
         MimeHeaders mimeHeaders = new MimeHeaders();
-        Cookies cookies = new Cookies(mimeHeaders);
-        cookies.setUseRfc6265(useRfc6265);
+        ServerCookies serverCookies = new ServerCookies(4);
+        CookieProcessor cookieProcessor;
+
+        if (useRfc6265) {
+            cookieProcessor = new Rfc6265CookieProcessor();
+        } else {
+            cookieProcessor = new Cookies();
+        }
         MessageBytes cookieHeaderValue = mimeHeaders.addValue("Cookie");
         byte[] bytes = header.getBytes(StandardCharsets.UTF_8);
         cookieHeaderValue.setBytes(bytes, 0, bytes.length);
-        // Calling getCookieCount() triggers parsing
-        Assert.assertEquals(expected.length, cookies.getCookieCount());
+        cookieProcessor.parseCookieHeader(mimeHeaders, serverCookies);
+        Assert.assertEquals(expected.length, serverCookies.getCookieCount());
         for (int i = 0; i < expected.length; i++) {
             Cookie cookie = expected[i];
-            ServerCookie actual = cookies.getCookie(i);
+            ServerCookie actual = serverCookies.getCookie(i);
             Assert.assertEquals(cookie.getVersion(), actual.getVersion());
             Assert.assertEquals(cookie.getName(), actual.getName().toString());
             
actual.getValue().getByteChunk().setCharset(StandardCharsets.UTF_8);

Modified: 
tomcat/trunk/test/org/apache/tomcat/util/http/TesterCookiesPerformance.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/http/TesterCookiesPerformance.java?rev=1627619&r1=1627618&r2=1627619&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/util/http/TesterCookiesPerformance.java 
(original)
+++ tomcat/trunk/test/org/apache/tomcat/util/http/TesterCookiesPerformance.java 
Thu Sep 25 19:38:15 2014
@@ -45,31 +45,35 @@ public class TesterCookiesPerformance {
 
         MessageBytes headerValue = mimeHeaders.addValue("Cookie");
         headerValue.setBytes(cookieHeaderBytes, 0, cookieHeaderBytes.length);
+        ServerCookies serverCookies = new ServerCookies(4);
+
+        Cookies originalCookieProcessor = new Cookies();
+        Rfc6265CookieProcessor rfc6265CookieProcessor = new 
Rfc6265CookieProcessor();
 
-        Cookies cookies = new Cookies(mimeHeaders);
         // warm up
         for (int i = 0; i < parsingLoops; i++) {
-            Assert.assertEquals(cookieCount, cookies.getCookieCount());
-            cookies.recycle();
+            originalCookieProcessor.parseCookieHeader(mimeHeaders, 
serverCookies);
+            Assert.assertEquals(cookieCount, serverCookies.getCookieCount());
+            serverCookies.recycle();
         }
 
         long oldStart = System.nanoTime();
         for (int i = 0; i < parsingLoops; i++) {
-            cookies.setUseRfc6265(false);
-            Assert.assertEquals(cookieCount, cookies.getCookieCount());
-            cookies.recycle();
+            originalCookieProcessor.parseCookieHeader(mimeHeaders, 
serverCookies);
+            Assert.assertEquals(cookieCount, serverCookies.getCookieCount());
+            serverCookies.recycle();
         }
         long oldDuration = System.nanoTime() - oldStart;
 
         long newStart = System.nanoTime();
         for (int i = 0; i < parsingLoops; i++) {
-            cookies.setUseRfc6265(true);
-            Assert.assertEquals(cookieCount, cookies.getCookieCount());
-            cookies.recycle();
+            rfc6265CookieProcessor.parseCookieHeader(mimeHeaders, 
serverCookies);
+            Assert.assertEquals(cookieCount, serverCookies.getCookieCount());
+            serverCookies.recycle();
         }
         long newDuration = System.nanoTime() - newStart;
 
-        System.out.println("Old duration: " + oldDuration);
-        System.out.println("New duration: " + newDuration);
+        System.out.println("Original duration: " + oldDuration);
+        System.out.println("RFC6265 duration:  " + newDuration);
     }
 }

Modified: tomcat/trunk/webapps/docs/config/context.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/context.xml?rev=1627619&r1=1627618&r2=1627619&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/context.xml (original)
+++ tomcat/trunk/webapps/docs/config/context.xml Thu Sep 25 19:38:15 2014
@@ -300,13 +300,6 @@
         no filtering will be applied.</p>
       </attribute>
 
-      <attribute name="cookieEncoding" required="false">
-        <p>If the RFC6265 based cookie parser is used this attribute determines
-        the encoding to be used to convert the byte values in the HTTP header 
to
-        strings. If not specified, the default of <code>UTF-8</code> will be
-        used.</p>
-      </attribute>
-
       <attribute name="cookies" required="false">
         <p>Set to <code>true</code> if you want cookies to be used for
         session identifier communication if supported by the client (this
@@ -536,12 +529,6 @@
         penalty.</p>
       </attribute>
 
-      <attribute name="useRfc6265" required="false">
-        <p>Determines if the RFC6265 based cookie parser is used. The default
-        value is <code>false</code> in which case the original parser based on
-        RFC2109 and the Netscape cookie specification will be used.</p>
-      </attribute>
-
       <attribute name="useHttpOnly" required="false">
        <p>Should the HttpOnly flag be set on session cookies to prevent client
           side script from accessing the session ID? Defaults to



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

Reply via email to