Author: markt
Date: Sat Nov 14 03:47:48 2009
New Revision: 836113
URL: http://svn.apache.org/viewvc?rev=836113&view=rev
Log:
More cookie refactoring
- new support class for common elements of parsing and writing
- better consistency between parsing and writing
- remove unused code
- reduce visibility of methods where possible
- auto-switch to v1 for any attribute that might require quoting
- better names for constants
- allow v0 cookies to break http spec (disabled by default)
- update test cases and documentation
Added:
tomcat/trunk/java/org/apache/tomcat/util/http/CookieSupport.java (with
props)
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesAllowHttpSeps.java
(with props)
Modified:
tomcat/trunk/java/org/apache/tomcat/util/http/Cookies.java
tomcat/trunk/java/org/apache/tomcat/util/http/ServerCookie.java
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesAllowEquals.java
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesDefaultSysProps.java
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesDisallowEquals.java
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesNoFwdStrictSysProps.java
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesStrictSysProps.java
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesSwitchSysProps.java
tomcat/trunk/webapps/docs/config/systemprops.xml
Added: tomcat/trunk/java/org/apache/tomcat/util/http/CookieSupport.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/CookieSupport.java?rev=836113&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/http/CookieSupport.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/util/http/CookieSupport.java Sat Nov 14
03:47:48 2009
@@ -0,0 +1,236 @@
+/*
+ * 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;
+
+
+/**
+ * Static constants for this package.
+ */
+public final class CookieSupport {
+
+
+ // ---------------------------------------------------------------
Constants
+ /**
+ * If set to true, we parse cookies strictly according to the servlet,
+ * cookie and HTTP specs by default.
+ */
+ public static final boolean STRICT_SERVLET_COMPLIANCE;
+
+ /**
+ * If true, cookie values are allowed to contain an equals character
without
+ * being quoted.
+ */
+ public static final boolean ALLOW_EQUALS_IN_VALUE;
+
+ /**
+ * If true, separators that are not explicitly dis-allowed by the v0 cookie
+ * spec but are disallowed by the HTTP spec will be allowed in v0 cookie
+ * names and values. These characters are: \"()/:<=>?...@[\\]{} Note that
the
+ * inclusion of / depend on the value of {...@link
#FWD_SLASH_IS_SEPARATOR}.
+ */
+ public static final boolean ALLOW_HTTP_SEPARATORS_IN_V0;
+
+ /**
+ * If set to false, we don't use the IE6/7 Max-Age/Expires work around.
+ * Default is usually true. If STRICT_SERVLET_COMPLIANCE==true then default
+ * is false. Explicitly setting always takes priority.
+ */
+ public static final boolean ALWAYS_ADD_EXPIRES;
+
+ /**
+ * If set to true, the <code>/</code> character will be treated as a
+ * separator. Default is usually false. If STRICT_SERVLET_COMPLIANCE==true
+ * then default is true. Explicitly setting always takes priority.
+ */
+ public static final boolean FWD_SLASH_IS_SEPARATOR;
+
+ /**
+ * The list of separators that apply to version 0 cookies. To quote the
+ * spec, these are comma, semi-colon and white-space. The HTTP spec
+ * definition of linear white space is [CRLF] 1*( SP | HT )
+ */
+ public static final char[] V0_SEPARATORS = {',', ';', ' ', '\t'};
+ public static final boolean[] V0_SEPARATOR_FLAGS = new boolean[128];
+
+ /**
+ * The list of separators that apply to version 1 cookies. This may or may
+ * not include '/' depending on the setting of
+ * {...@link #FWD_SLASH_IS_SEPARATOR}.
+ */
+ public static final char[] HTTP_SEPARATORS;
+ public static final boolean[] HTTP_SEPARATOR_FLAGS = new boolean[128];
+
+ static {
+ STRICT_SERVLET_COMPLIANCE = Boolean.valueOf(System.getProperty(
+ "org.apache.catalina.STRICT_SERVLET_COMPLIANCE",
+ "false")).booleanValue();
+
+ ALLOW_EQUALS_IN_VALUE = Boolean.valueOf(System.getProperty(
+
"org.apache.tomcat.util.http.ServerCookie.ALLOW_EQUALS_IN_VALUE",
+ "false")).booleanValue();
+
+ ALLOW_HTTP_SEPARATORS_IN_V0 = Boolean.valueOf(System.getProperty(
+
"org.apache.tomcat.util.http.ServerCookie.ALLOW_HTTP_SEPARATORS_IN_V0",
+ "false")).booleanValue();
+
+ String alwaysAddExpires = System.getProperty(
+ "org.apache.tomcat.util.http.ServerCookie.ALWAYS_ADD_EXPIRES");
+ if (alwaysAddExpires == null) {
+ ALWAYS_ADD_EXPIRES = !STRICT_SERVLET_COMPLIANCE;
+ } else {
+ ALWAYS_ADD_EXPIRES =
+ Boolean.valueOf(alwaysAddExpires).booleanValue();
+ }
+
+ String fwdSlashIsSeparator = System.getProperty(
+
"org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR");
+ if (fwdSlashIsSeparator == null) {
+ FWD_SLASH_IS_SEPARATOR = STRICT_SERVLET_COMPLIANCE;
+ } else {
+ FWD_SLASH_IS_SEPARATOR =
+ Boolean.valueOf(fwdSlashIsSeparator).booleanValue();
+ }
+
+ /*
+ Excluding the '/' char by default violates the RFC, but
+ it looks like a lot of people put '/'
+ in unquoted values: '/': ; //47
+ '\t':9 ' ':32 '\"':34 '(':40 ')':41 ',':44 ':':58 ';':59 '<':60
+ '=':61 '>':62 '?':63 '@':64 '[':91 '\\':92 ']':93 '{':123 '}':125
+ */
+ if (CookieSupport.FWD_SLASH_IS_SEPARATOR) {
+ HTTP_SEPARATORS = new char[] { '\t', ' ', '\"', '(', ')', ',',
'/',
+ ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '{',
'}' };
+ } else {
+ HTTP_SEPARATORS = new char[] { '\t', ' ', '\"', '(', ')', ',',
+ ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '{',
'}' };
+ }
+ for (int i = 0; i < 128; i++) {
+ V0_SEPARATOR_FLAGS[i] = false;
+ HTTP_SEPARATOR_FLAGS[i] = false;
+ }
+ for (int i = 0; i < V0_SEPARATORS.length; i++) {
+ V0_SEPARATOR_FLAGS[V0_SEPARATORS[i]] = true;
+ }
+ for (int i = 0; i < HTTP_SEPARATORS.length; i++) {
+ HTTP_SEPARATOR_FLAGS[HTTP_SEPARATORS[i]] = true;
+ }
+
+ }
+
+ // -----------------------------------------------------------------
Methods
+
+ /**
+ * Returns true if the byte is a separator as defined by V0 of the cookie
+ * spec.
+ */
+ public static final boolean isV0Separator(final char c) {
+ if (c < 0x20 || c >= 0x7f) {
+ if (c != 0x09) {
+ throw new IllegalArgumentException(
+ "Control character in cookie value or attribute.");
+ }
+ }
+
+ return V0_SEPARATOR_FLAGS[c];
+ }
+
+ public static boolean isV0Token(String value) {
+ if( value==null) return false;
+
+ int i = 0;
+ int len = value.length();
+
+ if (alreadyQuoted(value)) {
+ i++;
+ len--;
+ }
+
+ for (; i < len; i++) {
+ char c = value.charAt(i);
+
+ if (isV0Separator(c))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the byte is a separator as defined by V1 of the cookie
+ * spec, RFC2109.
+ * @throws IllegalArgumentException if a control character was supplied as
+ * input
+ */
+ public static final boolean isHttpSeparator(final char c) {
+ if (c < 0x20 || c >= 0x7f) {
+ if (c != 0x09) {
+ throw new IllegalArgumentException(
+ "Control character in cookie value or attribute.");
+ }
+ }
+
+ return HTTP_SEPARATOR_FLAGS[c];
+ }
+
+ public static boolean isHttpToken(String value) {
+ if( value==null) return false;
+
+ int i = 0;
+ int len = value.length();
+
+ if (alreadyQuoted(value)) {
+ i++;
+ len--;
+ }
+
+ for (; i < len; i++) {
+ char c = value.charAt(i);
+
+ if (isHttpSeparator(c))
+ return true;
+ }
+ return false;
+ }
+
+ public static boolean containsCTL(String value) {
+ if (value==null) return false;
+ int len = value.length();
+ for (int i = 0; i < len; i++) {
+ char c = value.charAt(i);
+ if (c < 0x20 || c >= 0x7f) {
+ if (c == 0x09)
+ continue; //allow horizontal tabs
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean alreadyQuoted (String value) {
+ if (value==null || value.length() < 2) return false;
+ return (value.charAt(0)=='\"' && value.charAt(value.length()-1)=='\"');
+ }
+
+
+
+ // -------------------------------------------------------------
Constructor
+ private CookieSupport() {
+ // Utility class. Don't allow instances to be created.
+ }
+}
Propchange: tomcat/trunk/java/org/apache/tomcat/util/http/CookieSupport.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=836113&r1=836112&r2=836113&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/http/Cookies.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/http/Cookies.java Sat Nov 14
03:47:48 2009
@@ -19,7 +19,6 @@
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.util.StringTokenizer;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.MessageBytes;
@@ -47,72 +46,6 @@
MimeHeaders headers;
/**
- * If set to true, we parse cookies strictly according to the servlet,
- * cookie and HTTP specs by default.
- */
- public static final boolean STRICT_SERVLET_COMPLIANCE;
-
- /**
- * If true, cookie values are allowed to contain an equals character
without
- * being quoted.
- */
- public static final boolean ALLOW_EQUALS_IN_VALUE;
-
- /**
- * If set to true, the <code>/</code> character will be treated as a
- * separator. Default is usually false. If STRICT_SERVLET_COMPLIANCE==true
- * then default is true. Explicitly setting always takes priority.
- */
- public static final boolean FWD_SLASH_IS_SEPARATOR;
-
- /*
- List of Separator Characters (see isSeparator())
- */
- public static final char SEPARATORS[];
-
- protected static final boolean separators[] = new boolean[128];
- static {
- STRICT_SERVLET_COMPLIANCE = Boolean.valueOf(System.getProperty(
- "org.apache.catalina.STRICT_SERVLET_COMPLIANCE",
- "false")).booleanValue();
-
- ALLOW_EQUALS_IN_VALUE = Boolean.valueOf(System.getProperty(
-
"org.apache.tomcat.util.http.ServerCookie.ALLOW_EQUALS_IN_VALUE",
- "false")).booleanValue();
-
- String fwdSlashIsSeparator = System.getProperty(
-
"org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR");
- if (fwdSlashIsSeparator == null) {
- FWD_SLASH_IS_SEPARATOR = STRICT_SERVLET_COMPLIANCE;
- } else {
- FWD_SLASH_IS_SEPARATOR =
- Boolean.valueOf(fwdSlashIsSeparator).booleanValue();
- }
-
- /*
- Excluding the '/' char by default violates the RFC, but
- it looks like a lot of people put '/'
- in unquoted values: '/': ; //47
- '\t':9 ' ':32 '\"':34 '(':40 ')':41 ',':44 ':':58 ';':59 '<':60
- '=':61 '>':62 '?':63 '@':64 '[':91 '\\':92 ']':93 '{':123 '}':125
- */
- if (FWD_SLASH_IS_SEPARATOR) {
- SEPARATORS = new char[] { '\t', ' ', '\"', '(', ')', ',', '/',
- ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '{',
'}' };
- } else {
- SEPARATORS = new char[] { '\t', ' ', '\"', '(', ')', ',',
- ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '{',
'}' };
- }
-
- for (int i = 0; i < 128; i++) {
- separators[i] = false;
- }
- for (int i = 0; i < SEPARATORS.length; i++) {
- separators[SEPARATORS[i]] = true;
- }
- }
-
- /**
* Construct a new cookie collection, that will extract
* the information from headers.
*
@@ -124,29 +57,6 @@
}
/**
- * Construct a new uninitialized cookie collection.
- * Use {...@link #setHeaders} to initialize.
- */
- // [seguin] added so that an empty Cookies object could be
- // created, have headers set, then recycled.
- public Cookies() {
- }
-
- /**
- * Set the headers from which cookies will be pulled.
- * This has the side effect of recycling the object.
- *
- * @param headers Cookies are lazy-evaluated and will extract the
- * information from the provided headers.
- */
- // [seguin] added so that an empty Cookies object could be
- // created, have headers set, then recycled.
- public void setHeaders(MimeHeaders headers) {
- recycle();
- this.headers=headers;
- }
-
- /**
* Recycle.
*/
public void recycle() {
@@ -196,7 +106,7 @@
* most of the time an existing ServerCookie object is returned.
* The caller can set the name/value and attributes for the cookie
*/
- public ServerCookie addCookie() {
+ private ServerCookie addCookie() {
if( cookieCount >= scookies.length ) {
ServerCookie scookiesTmp[]=new ServerCookie[2*cookieCount];
System.arraycopy( scookies, 0, scookiesTmp, 0, cookieCount);
@@ -235,24 +145,24 @@
}
// Uncomment to test the new parsing code
- if( cookieValue.getType() == MessageBytes.T_BYTES ) {
- if(log.isDebugEnabled())
- log.debug("Cookies: Parsing b[]: " +
cookieValue.toString());
- ByteChunk bc=cookieValue.getByteChunk();
- processCookieHeader( bc.getBytes(),
- bc.getOffset(),
- bc.getLength());
- } else {
- if(log.isDebugEnabled())
- log.debug("Cookies: Parsing S: " + cookieValue.toString());
- processCookieHeader( cookieValue.toString() );
- }
+ 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();
+ processCookieHeader( bc.getBytes(),
+ bc.getOffset(),
+ bc.getLength());
pos++;// search from the next position
}
}
// XXX will be refactored soon!
- public static boolean equals( String s, byte b[], int start, int end) {
+ private static boolean equals( String s, byte b[], int start, int end) {
int blen = end-start;
if (b == null || blen != s.length()) {
return false;
@@ -267,87 +177,12 @@
}
- // ---------------------------------------------------------
- // -------------------- DEPRECATED, OLD --------------------
-
- private void processCookieHeader( String cookieString )
- {
- if(log.isDebugEnabled())
- log.debug("Cookies: Parsing cookie header " + cookieString);
- // normal cookie, with a string value.
- // This is the original code, un-optimized - it shouldn't
- // happen in normal case
-
- StringTokenizer tok = new StringTokenizer(cookieString,
- ";", false);
- while (tok.hasMoreTokens()) {
- String token = tok.nextToken();
- int i = token.indexOf("=");
- if (i > -1) {
-
- // XXX
- // the trims here are a *hack* -- this should
- // be more properly fixed to be spec compliant
-
- String name = token.substring(0, i).trim();
- String value = token.substring(i+1, token.length()).trim();
- // RFC 2109 and bug
- value=stripQuote( value );
- ServerCookie cookie = addCookie();
-
- cookie.getName().setString(name);
- cookie.getValue().setString(value);
- if(log.isDebugEnabled())
- log.debug("Cookies: Add cookie " + name + "=" + value);
- } else {
- // we have a bad cookie.... just let it go
- }
- }
- }
-
- /**
- *
- * Strips quotes from the start and end of the cookie string
- * This conforms to RFC 2965
- *
- * @param value a <code>String</code> specifying the cookie
- * value (possibly quoted).
- *
- * @see #setValue
- *
- */
- private static String stripQuote( String value )
- {
- // log("Strip quote from " + value );
- if (value.startsWith("\"") && value.endsWith("\"")) {
- try {
- return value.substring(1,value.length()-1);
- } catch (Exception ex) {
- }
- }
- return value;
- }
-
- /**
- * Returns true if the byte is a separator character as
- * defined in RFC2619. Since this is called often, this
- * function should be organized with the most probable
- * outcomes first.
- * JVK
- */
- public static final boolean isSeparator(final byte c) {
- if (c > 0 && c < 126)
- return separators[c];
- else
- return false;
- }
-
/**
* Returns true if the byte is a whitespace character as
* defined in RFC2619
* JVK
*/
- public static final boolean isWhiteSpace(final byte c) {
+ 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)
@@ -370,12 +205,39 @@
}
/**
+ * 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);
+ }
+
+ /**
* Parses a cookie header after the initial "Cookie:"
* [WS][$]token[WS]=[WS](token|QV)[;|,]
* RFC 2965
* JVK
*/
- public final void processCookieHeader(byte bytes[], int off, int len){
+ protected final void processCookieHeader(byte bytes[], int off, int len){
if( len<=0 || bytes==null ) return;
int end=off+len;
int pos=off;
@@ -394,7 +256,10 @@
// Skip whitespace and non-token characters (separators)
while (pos < end &&
- (isSeparator(bytes[pos]) || isWhiteSpace(bytes[pos])))
+ (CookieSupport.isHttpSeparator((char) bytes[pos]) &&
+ !CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 ||
+ CookieSupport.isV0Separator((char) bytes[pos]) ||
+ isWhiteSpace(bytes[pos])))
{pos++; }
if (pos >= end)
@@ -406,9 +271,9 @@
pos++;
}
- // Get the cookie name. This must be a token
+ // Get the cookie/attribute name. This must be a token
valueEnd = valueStart = nameStart = pos;
- pos = nameEnd = getTokenEndPosition(bytes,pos,end);
+ pos = nameEnd = getTokenEndPosition(bytes,pos,end,version,true);
// Skip whitespace
while (pos < end && isWhiteSpace(bytes[pos])) {pos++; }
@@ -455,19 +320,23 @@
// The position is OK (On a delimiter)
break;
default:
- if (!isSeparator(bytes[pos])) {
+ if (version == 0 &&
+ !CookieSupport.isV0Separator((char)bytes[pos])
&&
+ CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 ||
+ !CookieSupport.isHttpSeparator((char)bytes[pos])) {
// Token
valueStart=pos;
// getToken returns the position at the delimeter
// or other non-token character
- valueEnd=getTokenEndPosition(bytes, valueStart, end);
+ valueEnd=getTokenEndPosition(bytes, valueStart, end,
+ version, false);
// We need pos to advance
pos = valueEnd;
} else {
// INVALID COOKIE, advance to next delimiter
// The starting character of the cookie value was
// not valid.
- log.info("Cookies: Invalid cookie." +
+ log.info("Cookies: Invalid cookie. " +
"Value not a token or quoted value");
while (pos < end && bytes[pos] != ';' &&
bytes[pos] != ',')
@@ -503,23 +372,6 @@
pos++;
- /*
- if (nameEnd <= nameStart || valueEnd < valueStart ) {
- // Something is wrong, but this may be a case
- // of having two ';' characters in a row.
- // log("Cookie name/value does not conform to RFC 2965");
- // Advance to next delimiter (ignoring everything else)
- while (pos < end && bytes[pos] != ';' && bytes[pos] != ',')
- { pos++; };
- pos++;
- // Make sure no special cookies can be attributed to
- // the previous cookie by setting the current cookie
- // to null
- sc = null;
- continue;
- }
- */
-
// All checks passed. Add the cookie, start with the
// special avpairs first
if (isSpecial) {
@@ -557,12 +409,11 @@
continue;
}
-
+ // v2 cookie attributes - skip them
if (equals( "Port", bytes, nameStart, nameEnd)) {
- // sc.getPort is not currently implemented.
- // sc.getPort().setBytes( bytes,
- // valueStart,
- // valueEnd-valueStart );
+ continue;
+ }
+ if (equals( "CommentURL", bytes, nameStart, nameEnd)) {
continue;
}
@@ -580,8 +431,7 @@
valueEnd-valueStart);
if (isQuoted) {
// We know this is a byte value so this is safe
- ServerCookie.unescapeDoubleQuotes(
- sc.getValue().getByteChunk());
+ unescapeDoubleQuotes(sc.getValue().getByteChunk());
}
} else {
// Name Only
@@ -597,11 +447,17 @@
* token, with no separator characters in between.
* JVK
*/
- public static final int getTokenEndPosition(byte bytes[], int off, int
end){
+ private static final int getTokenEndPosition(byte bytes[], int off, int
end,
+ int version, boolean isName){
int pos = off;
while (pos < end &&
- (!isSeparator(bytes[pos]) ||
- bytes[pos]=='=' && ALLOW_EQUALS_IN_VALUE)) {
+ (!CookieSupport.isHttpSeparator((char)bytes[pos]) ||
+ version == 0 &&
+ CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 &&
+ bytes[pos] != '=' &&
+ !CookieSupport.isV0Separator((char)bytes[pos]) ||
+ !isName && bytes[pos] == '=' &&
+ CookieSupport.ALLOW_EQUALS_IN_VALUE)) {
pos++;
}
@@ -615,7 +471,7 @@
* the position of the end quote. This escapes anything after a '\' char
* JVK RFC 2616
*/
- public static final int getQuotedValueEndPosition(byte bytes[], int off,
int end){
+ private static final int getQuotedValueEndPosition(byte bytes[], int off,
int end){
int pos = off;
while (pos < end) {
if (bytes[pos] == '"') {
Modified: tomcat/trunk/java/org/apache/tomcat/util/http/ServerCookie.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/ServerCookie.java?rev=836113&r1=836112&r2=836113&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/http/ServerCookie.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/http/ServerCookie.java Sat Nov 14
03:47:48 2009
@@ -25,7 +25,6 @@
import java.util.Locale;
import java.util.TimeZone;
-import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.MessageBytes;
@@ -40,6 +39,7 @@
*/
public class ServerCookie implements Serializable {
+ private static final long serialVersionUID = 1L;
// Version 0 (Netscape) attributes
private MessageBytes name=MessageBytes.newInstance();
@@ -69,69 +69,21 @@
};
private static final String ancientDate;
- /**
- * If set to true, we parse cookies strictly according to the servlet,
- * cookie and HTTP specs by default.
- */
- public static final boolean STRICT_SERVLET_COMPLIANCE;
-
- /**
- * If set to false, we don't use the IE6/7 Max-Age/Expires work around.
- * Default is usually true. If STRICT_SERVLET_COMPLIANCE==true then default
- * is false. Explicitly setting always takes priority.
- */
- public static final boolean ALWAYS_ADD_EXPIRES;
-
- /**
- * If set to true, the <code>/</code> character will be treated as a
- * separator. Default is usually false. If STRICT_SERVLET_COMPLIANCE==true
- * then default is true. Explicitly setting always takes priority.
- */
- public static final boolean FWD_SLASH_IS_SEPARATOR;
-
-
static {
ancientDate = OLD_COOKIE_FORMAT.get().format(new Date(10000));
-
- STRICT_SERVLET_COMPLIANCE = Boolean.valueOf(System.getProperty(
- "org.apache.catalina.STRICT_SERVLET_COMPLIANCE",
- "false")).booleanValue();
-
-
- String alwaysAddExpires = System.getProperty(
- "org.apache.tomcat.util.http.ServerCookie.ALWAYS_ADD_EXPIRES");
- if (alwaysAddExpires == null) {
- ALWAYS_ADD_EXPIRES = !STRICT_SERVLET_COMPLIANCE;
- } else {
- ALWAYS_ADD_EXPIRES =
- Boolean.valueOf(alwaysAddExpires).booleanValue();
- }
-
- String fwdSlashIsSeparator = System.getProperty(
-
"org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR");
- if (fwdSlashIsSeparator == null) {
- FWD_SLASH_IS_SEPARATOR = STRICT_SERVLET_COMPLIANCE;
- } else {
- FWD_SLASH_IS_SEPARATOR =
- Boolean.valueOf(fwdSlashIsSeparator).booleanValue();
- }
-
- if (FWD_SLASH_IS_SEPARATOR) {
- tspecials2 = "()<>@,;:\\\"/[]?={} \t";
- } else {
- tspecials2 = "()<>@,;:\\\"[]?={} \t";
- }
}
- // Note: Servlet Spec =< 2.5 only refers to Netscape and RFC2109,
+ // Note: Servlet Spec =< 3.0 only refers to Netscape and RFC2109,
// not RFC2965
- // Version 1 (RFC2965) attributes
- // TODO Add support for CommentURL
+ // Version 2 (RFC2965) attributes that would need to be added to support
+ // v2 cookies
+ // CommentURL
// Discard - implied by maxAge <0
- // TODO Add support for Port
+ // Port
public ServerCookie() {
+ // NOOP
}
public void recycle() {
@@ -199,98 +151,9 @@
+ getVersion() + " " + getPath() + " " + getDomain();
}
- private static final String tspecials = ",; ";
- private static final String tspecials2;
-
- /*
- * Tests a string and returns true if the string counts as a
- * reserved token in the Java language.
- *
- * @param value the <code>String</code> to be tested
- *
- * @return <code>true</code> if the <code>String</code> is a reserved
- * token; <code>false</code> if it is not
- */
- public static boolean isToken(String value) {
- return isToken(value,null);
- }
-
- public static boolean isToken(String value, String literals) {
- String tspecials = (literals==null?ServerCookie.tspecials:literals);
- if( value==null) return true;
- int len = value.length();
-
- for (int i = 0; i < len; i++) {
- char c = value.charAt(i);
-
- if (tspecials.indexOf(c) != -1)
- return false;
- }
- return true;
- }
-
- public static boolean containsCTL(String value, int version) {
- if( value==null) return false;
- int len = value.length();
- for (int i = 0; i < len; i++) {
- char c = value.charAt(i);
- if (c < 0x20 || c >= 0x7f) {
- if (c == 0x09)
- continue; //allow horizontal tabs
- return true;
- }
- }
- return false;
- }
-
- public static boolean isToken2(String value) {
- return isToken2(value,null);
- }
-
- public static boolean isToken2(String value, String literals) {
- String tokens = (literals==null?ServerCookie.tspecials2:literals);
- if( value==null) return true;
- int len = value.length();
-
- for (int i = 0; i < len; i++) {
- char c = value.charAt(i);
- if (tokens.indexOf(c) != -1)
- return false;
- }
- return true;
- }
-
// -------------------- Cookie parsing tools
- /**
- * Return the header name to set the cookie, based on cookie version.
- */
- public String getCookieHeaderName() {
- return getCookieHeaderName(version);
- }
-
- /**
- * Return the header name to set the cookie, based on cookie version.
- */
- public static String getCookieHeaderName(int version) {
- // TODO Re-enable logging when RFC2965 is implemented
- // log( (version==1) ? "Set-Cookie2" : "Set-Cookie");
- if (version == 1) {
- // XXX RFC2965 not referenced in Servlet Spec
- // Set-Cookie2 is not supported by Netscape 4, 6, IE 3, 5
- // Set-Cookie2 is supported by Lynx and Opera
- // Need to check on later IE and FF releases but for now...
- // RFC2109
- return "Set-Cookie";
- // return "Set-Cookie2";
- } else {
- // Old Netscape
- return "Set-Cookie";
- }
- }
-
- // TODO RFC2965 fields also need to be passed
public static void appendCookieValue( StringBuffer headerBuf,
int version,
String name,
@@ -308,41 +171,81 @@
buf.append("=");
// Servlet implementation does not check anything else
- version = maybeQuote2(version, buf, value, true);
+ /*
+ * The spec allows some latitude on when to send the version attribute
+ * with a Set-Cookie header. To be nice to clients, we'll make sure the
+ * version attribute is first. That means checking the various things
+ * that can cause us to switch to a v1 cookie first.
+ *
+ * Note that by checking for tokens we will also throw an exception if
a
+ * control character is encountered.
+ */
+ // Start by using the version we were asked for
+ int newVersion = version;
- // Spec team clarified setting comment on a v0 cookie switches it to v1
- if (version == 0 && comment != null) {
- version = 1;
+ // If it is v0, check if we need to switch
+ if (newVersion == 0 &&
+ (!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 &&
+ CookieSupport.isHttpToken(value) ||
+ CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 &&
+ CookieSupport.isV0Token(value))) {
+ // HTTP token in value - need to use v1
+ newVersion = 1;
}
-
+
+ if (newVersion == 0 && comment != null) {
+ // Using a comment makes it a v1 cookie
+ newVersion = 1;
+ }
+
+ if (newVersion == 0 &&
+ (!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 &&
+ CookieSupport.isHttpToken(path) ||
+ CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 &&
+ CookieSupport.isV0Token(path))) {
+ // HTTP token in path - need to use v1
+ newVersion = 1;
+ }
+
+ if (newVersion == 0 &&
+ (!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 &&
+ CookieSupport.isHttpToken(domain) ||
+ CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 &&
+ CookieSupport.isV0Token(domain))) {
+ // HTTP token in domain - need to use v1
+ newVersion = 1;
+ }
+
+ // Now build the cookie header
+ // Value
+ maybeQuote(buf, value);
// Add version 1 specific information
- if (version == 1) {
+ if (newVersion == 1) {
// Version=1 ... required
buf.append ("; Version=1");
// Comment=comment
if ( comment!=null ) {
buf.append ("; Comment=");
- maybeQuote2(version, buf, comment);
+ maybeQuote(buf, comment);
}
}
// Add domain information, if present
if (domain!=null) {
buf.append("; Domain=");
- maybeQuote2(version, buf, domain);
+ maybeQuote(buf, domain);
}
// Max-Age=secs ... or use old "Expires" format
- // TODO RFC2965 Discard
if (maxAge >= 0) {
- if (version > 0) {
+ if (newVersion > 0) {
buf.append ("; Max-Age=");
buf.append (maxAge);
}
// IE6, IE7 and possibly other browsers don't understand Max-Age.
// They do understand Expires, even with V1 cookies!
- if (version == 0 || ALWAYS_ADD_EXPIRES) {
+ if (newVersion == 0 || CookieSupport.ALWAYS_ADD_EXPIRES) {
// Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires Netscape format )
buf.append ("; Expires=");
// To expire immediately we need to set the time in past
@@ -359,7 +262,7 @@
// Path=path
if (path!=null) {
buf.append ("; Path=");
- maybeQuote2(version, buf, path);
+ maybeQuote(buf, path);
}
// Secure
@@ -374,51 +277,28 @@
headerBuf.append(buf);
}
- public static boolean alreadyQuoted (String value) {
- if (value==null || value.length()==0) return false;
- return (value.charAt(0)=='\"' && value.charAt(value.length()-1)=='\"');
- }
-
/**
- * Quotes values using rules that vary depending on Cookie version.
- * @param version
+ * Quotes values if required.
* @param buf
* @param value
*/
- public static int maybeQuote2 (int version, StringBuffer buf, String
value) {
- return maybeQuote2(version,buf,value,false);
- }
-
- public static int maybeQuote2 (int version, StringBuffer buf, String
value, boolean allowVersionSwitch) {
- return maybeQuote2(version,buf,value,null,allowVersionSwitch);
- }
-
- public static int maybeQuote2 (int version, StringBuffer buf, String
value, String literals, boolean allowVersionSwitch) {
+ private static void maybeQuote (StringBuffer buf, String value) {
if (value==null || value.length()==0) {
buf.append("\"\"");
- }else if (containsCTL(value,version))
- throw new IllegalArgumentException("Control character in cookie
value, consider BASE64 encoding your value");
- else if (alreadyQuoted(value)) {
+ } else if (CookieSupport.alreadyQuoted(value)) {
buf.append('"');
buf.append(escapeDoubleQuotes(value,1,value.length()-1));
buf.append('"');
- } else if (allowVersionSwitch && version==0 && !isToken2(value,
literals)) {
+ } else if (CookieSupport.isHttpToken(value) &&
+ !CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 ||
+ CookieSupport.isV0Token(value) &&
+ CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0) {
buf.append('"');
buf.append(escapeDoubleQuotes(value,0,value.length()));
buf.append('"');
- version = 1;
- } else if (version==0 && !isToken(value,literals)) {
- buf.append('"');
- buf.append(escapeDoubleQuotes(value,0,value.length()));
- buf.append('"');
- } else if (version==1 && !isToken2(value,literals)) {
- buf.append('"');
- buf.append(escapeDoubleQuotes(value,0,value.length()));
- buf.append('"');
- }else {
+ } else {
buf.append(value);
}
- return version;
}
@@ -453,31 +333,5 @@
return b.toString();
}
- /**
- * Unescapes any double quotes in the given cookie value.
- *
- * @param bc The cookie value to modify
- */
- public 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);
- }
}
Modified:
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesAllowEquals.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesAllowEquals.java?rev=836113&r1=836112&r2=836113&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesAllowEquals.java
(original)
+++ tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesAllowEquals.java
Sat Nov 14 03:47:48 2009
@@ -68,7 +68,7 @@
disconnect();
reset();
tomcat.stop();
- assertTrue(response.contains(COOKIE_WITH_EQUALS));
+ assertEquals(COOKIE_WITH_EQUALS, response);
}
@Override
Added:
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesAllowHttpSeps.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesAllowHttpSeps.java?rev=836113&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesAllowHttpSeps.java
(added)
+++ tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesAllowHttpSeps.java
Sat Nov 14 03:47:48 2009
@@ -0,0 +1,99 @@
+/*
+ * 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.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.startup.SimpleHttpClient;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.catalina.startup.Tomcat;
+
+public class TestCookiesAllowHttpSeps extends TomcatBaseTest{
+
+ private static final String COOKIE_WITH_SEPS = "name=val(ue";
+
+ public void testWithHttpSep() throws Exception {
+ System.setProperty(
+
"org.apache.tomcat.util.http.ServerCookie.ALLOW_HTTP_SEPARATORS_IN_V0",
+ "true");
+
+ TestCookieHttpSepClient client = new TestCookieHttpSepClient();
+ client.doRequest();
+ }
+
+ private class TestCookieHttpSepClient extends SimpleHttpClient {
+
+
+ private void doRequest() throws Exception {
+ Tomcat tomcat = getTomcatInstance();
+ StandardContext root = tomcat.addContext("", TEMP_DIR);
+ Tomcat.addServlet(root, "Simple", new SimpleServlet());
+ root.addServletMapping("/test", "Simple");
+
+ tomcat.start();
+ // Open connection
+ setPort(tomcat.getConnector().getPort());
+ connect();
+
+ String[] request = new String[1];
+ request[0] =
+ "GET /test HTTP/1.0" + CRLF +
+ "Cookie: " + COOKIE_WITH_SEPS + CRLF + CRLF;
+ setRequest(request);
+ processRequest(true); // blocks until response has been read
+ String response = getResponseBody();
+
+ // Close the connection
+ disconnect();
+ reset();
+ tomcat.stop();
+ assertEquals(COOKIE_WITH_SEPS, response);
+ }
+
+ @Override
+ public boolean isResponseBodyOK() {
+ return true;
+ }
+
+ }
+
+
+ private static class SimpleServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse
resp)
+ throws ServletException, IOException {
+ Cookie cookies[] = req.getCookies();
+ for (Cookie cookie : cookies) {
+ resp.getWriter().write(cookie.getName() + "=" +
+ cookie.getValue() + "\n");
+ }
+ resp.flushBuffer();
+ }
+
+ }
+
+}
Propchange:
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesAllowHttpSeps.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesDefaultSysProps.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesDefaultSysProps.java?rev=836113&r1=836112&r2=836113&view=diff
==============================================================================
---
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesDefaultSysProps.java
(original)
+++
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesDefaultSysProps.java
Sat Nov 14 03:47:48 2009
@@ -59,9 +59,7 @@
getUrl("http://localhost:" + getPort() + "/switch", res, headers);
List<String> cookieHeaders = headers.get("Set-Cookie");
for (String cookieHeader : cookieHeaders) {
- if (cookieHeader.contains("name=")) {
- assertTrue(cookieHeader.contains("name=\"val?ue\";"));
- }
+ assertEquals("name=\"val?ue\"; Version=1", cookieHeader);
}
}
Modified:
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesDisallowEquals.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesDisallowEquals.java?rev=836113&r1=836112&r2=836113&view=diff
==============================================================================
---
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesDisallowEquals.java
(original)
+++
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesDisallowEquals.java
Sat Nov 14 03:47:48 2009
@@ -65,7 +65,7 @@
disconnect();
reset();
tomcat.stop();
- assertTrue(response.contains(COOKIE_TRUNCATED));
+ assertEquals(COOKIE_TRUNCATED, response);
}
@Override
Modified:
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesNoFwdStrictSysProps.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesNoFwdStrictSysProps.java?rev=836113&r1=836112&r2=836113&view=diff
==============================================================================
---
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesNoFwdStrictSysProps.java
(original)
+++
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesNoFwdStrictSysProps.java
Sat Nov 14 03:47:48 2009
@@ -51,7 +51,7 @@
res = getUrl("http://localhost:" + getPort() + "/invalidFwd");
assertEquals("Cookie name ok", res.toString());
res = getUrl("http://localhost:" + getPort() + "/invalidStrict");
- assertEquals("Cookie name fail", res.toString());
+ assertEquals("Cookie name ok", res.toString()); // Will auto switch
res = getUrl("http://localhost:" + getPort() + "/valid");
assertEquals("Cookie name ok", res.toString());
Modified:
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesStrictSysProps.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesStrictSysProps.java?rev=836113&r1=836112&r2=836113&view=diff
==============================================================================
---
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesStrictSysProps.java
(original)
+++
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesStrictSysProps.java
Sat Nov 14 03:47:48 2009
@@ -51,9 +51,9 @@
res = getUrl("http://localhost:" + getPort() + "/blank");
assertEquals("Cookie name fail", res.toString());
res = getUrl("http://localhost:" + getPort() + "/invalidFwd");
- assertEquals("Cookie name fail", res.toString());
+ assertEquals("Cookie name ok", res.toString()); // Will auto-switch
res = getUrl("http://localhost:" + getPort() + "/invalidStrict");
- assertEquals("Cookie name fail", res.toString());
+ assertEquals("Cookie name ok", res.toString()); // Will auto-switch
res = getUrl("http://localhost:" + getPort() + "/valid");
assertEquals("Cookie name ok", res.toString());
@@ -62,9 +62,7 @@
getUrl("http://localhost:" + getPort() + "/switch", res, headers);
List<String> cookieHeaders = headers.get("Set-Cookie");
for (String cookieHeader : cookieHeaders) {
- if (cookieHeader.contains("name=")) {
- assertTrue(cookieHeader.contains("name=val?ue"));
- }
+ assertEquals("name=\"val?ue\"; Version=1", cookieHeader);
}
}
Modified:
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesSwitchSysProps.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesSwitchSysProps.java?rev=836113&r1=836112&r2=836113&view=diff
==============================================================================
---
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesSwitchSysProps.java
(original)
+++
tomcat/trunk/test/org/apache/tomcat/util/http/TestCookiesSwitchSysProps.java
Sat Nov 14 03:47:48 2009
@@ -54,9 +54,9 @@
res = getUrl("http://localhost:" + getPort() + "/blank");
assertEquals("Cookie name fail", res.toString());
res = getUrl("http://localhost:" + getPort() + "/invalidFwd");
- assertEquals("Cookie name fail", res.toString());
+ assertEquals("Cookie name ok", res.toString()); // Will auto-switch
res = getUrl("http://localhost:" + getPort() + "/invalidStrict");
- assertEquals("Cookie name fail", res.toString());
+ assertEquals("Cookie name ok", res.toString()); // Will auto-switch
res = getUrl("http://localhost:" + getPort() + "/valid");
assertEquals("Cookie name ok", res.toString());
Modified: tomcat/trunk/webapps/docs/config/systemprops.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/systemprops.xml?rev=836113&r1=836112&r2=836113&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/systemprops.xml (original)
+++ tomcat/trunk/webapps/docs/config/systemprops.xml Sat Nov 14 03:47:48 2009
@@ -248,8 +248,8 @@
</ul>
</p>
<p>Note that changing a number of the above defaults is likely to break
- the majority of systems as a number of browsers are unable to correctly
- handle the cookie headers that result from a strict adherence to the
+ the majority of systems as some browsers are unable to correctly handle
+ the cookie headers that result from a strict adherence to the
specifications. Defaults, regardless of whether or not they have been
changed by setting
<code>org.apache.catalina.STRICT_SERVLET_COMPLIANCE</code> can always be
@@ -277,6 +277,13 @@
</property>
<property
+ name="org.apache.tomcat.util.http.
ServerCookie.ALLOW_HTTP_SEPARATORS_IN_V0">
+ <p>If this is <code>true</code> Tomcat will allow HTTP separators in
+ cookie names and values. If not specified, the default specification
+ compliant value of <code>false</code> will be used.</p>
+ </property>
+
+ <property
name="org.apache.tomcat.util.http. ServerCookie.ALWAYS_ADD_EXPIRES">
<p>If this is <code>true</code> Tomcat will always add an expires
parameter to a SetCookie header even for cookies with version greater
than
@@ -294,7 +301,8 @@
be treated as a separator. Note that this character is frequently used in
cookie path attributes and some browsers will fail to process a cookie if
the path attribute is quoted as is required by a strict adherence to the
- specifications. If not specified, the default value will be used. If
+ specifications. This is highly likely to break session tracking using
+ cookies. If not specified, the default value will be used. If
<code>org.apache.catalina.STRICT_SERVLET_COMPLIANCE</code> is set to
<code>true</code>, the default of this setting will be <code>true</code>,
else the default value will be <code>false</code>.</p>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]