今天在代码中调用 HttpServletRequest 对象的 getCookies() 方法时,发现实际得到的 Cookie 数量与提交的不符。实际提交了 17 个 Cookie,但是获取到的只有 14 个。
经过排查,发现如果调用 getHeaders(“Cookie”) 方法,获取原始的 Cookie 串,是可以拿到正确的 17 个 Cookie 组成的字符串的。于是确认应该是 Tomcat 在处理 Cookie 的时候进行了过滤。
经过一番搜索,发现了这个文档:
http://tomcat.apache.org/tomcat-7.0-doc/config/systemprops.html
其中,跟 Cookie 相关的参数有:
-
org.apache.tomcat.util.http. ServerCookie.ALLOW_EQUALS_IN_VALUE
(If this is true Tomcat will allow ‘=‘ characters when parsing unquoted cookie values. If false, cookie values containing ‘=‘ will be terminated when the ‘=‘ is encountered and the remainder of the cookie value will be dropped.
If not specified, the default value specification compliant value of false will be used.) -
org.apache.tomcat.util.http. ServerCookie.ALLOW_HTTP_SEPARATORS_IN_V0
(If this is true Tomcat will allow HTTP separators in cookie names and values.
If not specified, the default specification compliant value of false will be used.) -
org.apache.tomcat.util.http. ServerCookie.ALLOW_NAME_ONLY
(If this is false then the requirements of the cookie specifications that cookies must have values will be enforced and cookies consisting only of a name but no value will be ignored.
If not specified, the default specification compliant value of false will be used.) -
org.apache.tomcat.util.http. ServerCookie.ALWAYS_ADD_EXPIRES
(If this is true Tomcat will always add an expires parameter to a SetCookie header even for cookies with version greater than zero. This is to work around a known IE6 and IE7 bug that causes IE to ignore the Max-Age parameter in a SetCookie header.
If org.apache.catalina.STRICT_SERVLET_COMPLIANCE is set to true, the default of this setting will be false, else the default value will be true.) -
org.apache.tomcat.util.http. ServerCookie.FWD_SLASH_IS_SEPARATOR
(If this is true then the / (forward slash) character will 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. This is highly likely to break session tracking using cookies.
If org.apache.catalina.STRICT_SERVLET_COMPLIANCE is set to true, the default of this setting will be true, else the default value will be false.) -
org.apache.tomcat.util.http. ServerCookie.PRESERVE_COOKIE_HEADER
(If this is true Tomcat will ensure that cookie processing does not modify cookie header returned by HttpServletRequest.getHeader().
If org.apache.catalina.STRICT_SERVLET_COMPLIANCE is set to true, the default of this setting will be true, else the default value will be false.) -
org.apache.tomcat.util.http. ServerCookie.STRICT_NAMING
(If this is true then the requirements of the Servlet specification that Cookie names must adhere to RFC2109 (no use of separators) will be enforced.
If org.apache.catalina.STRICT_SERVLET_COMPLIANCE is set to true, the default of this setting will be true, else the default value will be false.)
其中详细说明了第一个选项的作用:
在网上查了下,cookie有以下版本:
版本0:由Netscape公司制定的,也被几乎所有的浏览器支持。Java中为了保持兼容性,目前只支持到版本0,Cookie的内容中不能包含空格,方括号,圆括号,等于号(=),逗号,双引号,斜杠,问号,@符号,冒号,分号。
版本1:根据RFC 2109(http://www.ietf.org/rfc/rfc2109.txt)文档制定的. 放宽了很多限制. 上面所限制的字符都可以使用. 但为了保持兼容性, 应该尽量避免使用这些特殊字符。
Tomcat 具体的过滤源码里面包含了这些字符:
如果 org.apache.tomcat.util.http.ServerCookie.FWD_SLASH_IS_SEPARATOR 设为 true (默认 False),’/’也会被作为http分隔符
如果 org.apache.tomcat.util.http.ServerCookie.ALLOW_HTTP_SEPARATORS_IN_V0 设为 true (默认 False),tomcat将会允许cookie的name和value使用http分隔符
tomcat源码中的http分隔符:’\t’, ‘ ‘, ‘\”‘, ‘(‘, ‘)’, ‘,’, ‘:’, ‘;’, ‘<’, ‘=’, '>‘, ‘?’, ‘@’, ‘[‘, ‘\’, ‘]’, ‘{‘, ‘}’
然后第二个选项就很好理解了,如果 Cookie 的 Value 是空,那么直接干掉。
于是,我们传的 Cookie 是这样的:
aaa=@abcdefg
1
aaa=@abcdefg
Tomcat 先做了一次截断,将 @ 和后面的内容都去掉了;然后做了一次判断,发现 aaa 这个 Cookie 只有 name 没有 value,于是直接干掉了。