commons-httpclient 3.x sends multiple Cookie request headers and Apache httpd/mod_proxy merges those into one Cookie header separated by comma (,)

Solution Verified - Updated

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=VALUE2
    

    then Apache httpd/mod_proxy merges those into one Cookie header separated by comma (,) and forward it to the backend server:

    Cookie: NAME1=VALUE1, NAME2=VALUE2
    

    This 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-header parameter 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
EAP 7
Components
Category

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.