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