commons-httpclient 3.x sends multiple Cookie request headers and Apache httpd/mod_proxy merges those into one Cookie header separated by comma (,)
Environment
- Apache httpd 2.2/2.4
- Apache Commons HttpClient 3.x
- Apache Tomcat
- 8.5.x
- 9.0.x
- Red Hat JBoss Enterprise Application Platform (EAP) 7.x
Issue
-
Apache httpd/mod_proxy merges multiple Cookie request header into one Cookie header separated by comma (
,). Is this expected behavior? Is there any configurable parameter to change Apache httpd to use semicolon (;) instead? -
When I use commons-httpclient 3.x as a client, commons-httpclient 3.x adds multiple Cookie headers in one request like:
GET /example/ HTTP/1.1 User-Agent: ... Host: ... ... Cookie: NAME1=VALUE1 Cookie: NAME2=VALUE2then Apache httpd/mod_proxy merges those into one Cookie header separated by comma (
,) and forward it to the backend server:Cookie: NAME1=VALUE1, NAME2=VALUE2This behavior is not compatible with RFC6265 compliant server like Tomcat 8.5. And same issue happens when EAP 7 (Undertow) run as a backend server, too.
Resolution
There's no configurable parameter to change Apache httpd's behavior and it is an expected behavior which is compliant to HTTP/1.1 specification.
Note that Content from tools.ietf.org is not included.the section 4.2 of RFC2616 mentions "It MUST be possible to combine the multiple header fields into one "field-name: field-value" pair..., each separated by a comma". Please refer to the following for details:
4.2 Message Headers
...
Multiple message-header fields with the same field-name MAY be
present in a message if and only if the entire field-value for that
header field is defined as a comma-separated list [i.e., #(values)].
It MUST be possible to combine the multiple header fields into one
"field-name: field-value" pair, without changing the semantics of the
message, by appending each subsequent field-value to the first, each
separated by a comma. The order in which header fields with the same
field-name are received is therefore significant to the
interpretation of the combined field value, and thus a proxy MUST NOT
change the order of these field values when a message is forwarded.
HTTP/1.1 spec was updated to RFC7230 recently but the above is still valid. And note that Content from tools.ietf.org is not included.the section 3.2 of RFC7230 also mentions "A sender MUST NOT generate multiple header fields with the same field name in a message unless either the entire field value for that header field is defined as a comma-separated list". So, this means the behavior of commons-httpclient 3.x violates the latest spec.
3.2.2. Field Order
...
A sender MUST NOT generate multiple header fields with the same field
name in a message unless either the entire field value for that
header field is defined as a comma-separated list [i.e., #(values)]
or the header field is a well-known exception (as noted below).
A recipient MAY combine multiple header fields with the same field
name into one "field-name: field-value" pair, without changing the
semantics of the message, by appending each subsequent field value to
the combined field value in order, separated by a comma. The order
in which header fields with the same field name are received is
therefore significant to the interpretation of the combined field
value; a proxy MUST NOT change the order of these field values when
forwarding a message.
Please also notice that the latest Cookie specification [RFC6265] mentions the following in Content from tools.ietf.org is not included.the section 5.4. (The previous Cookie specifications, RFC2109 and RFC2965, do not have this statement, so some old client may violate this. But, RFC6265 would be what client should be follow in future.):
When the user agent generates an HTTP request, the user agent MUST
NOT attach more than one Cookie header field.
Workaround
You can workaround this issue by changing behaviors of either commons-httpclient 3.x, Tomcat 8.5 or EAP 7:
commons-httpclient 3.x
-
Set Content from hc.apache.org is not included.
http.protocol.single-cookie-headerparameter to true in your commons-httpclient 3.x like:HttpMethod method = new GetMethod(url); method.getParams().setParameter("http.protocol.single-cookie-header", true); ...Also refer to Content from hc.apache.org is not included.the documentation of commons-httpclient 3.x which mentions the following:
Browser Compatibility The compatibility specification is designed to be compatible with as many different servers as possible even if they are not completely standards compliant. If you are encountering problems with parsing cookies, you should probably try using this specification. There are many web sites with badly written CGI scripts that only work when all cookies are put into one request header. It is advisable to set http.protocol.single-cookie-header parameter to true for maximum compatibility.Note that the latest Apache HttpComponents Client 4.x, which is a successor of commons-httpclient, still has Content from hc.apache.org is not included.a similar parameter but the default behavior is already changed to the browser compatible one.
Tomcat 8.5 & 9.0
-
Change Content from tomcat.apache.org is not included.
CookieProcessorfromorg.apache.tomcat.util.http.Rfc6265CookieProcessortoorg.apache.tomcat.util.http.LegacyCookieProcessorin yourcontext.xmlon Tomcat 8.5:<CookieProcessor className="org.apache.tomcat.util.http.LegacyCookieProcessor" />
EAP 7
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.