Summary
URLConnection
and HttpUrlConnection
are fixed to return multiple header values for a given field-name in the order in which they were added.
Problem
URLConnection
defines a getHeaderFields
method that return header fields as a map, where
the key is a header field name and the value is a List
of strings, representing the values for that header field.
public Map<String,List<String>> getHeaderFields()
The default implementation in URLConnection
returns an empty map. However the JDK implementation of HttpURLConnection
overrides this method to return actual values. For the HTTP protocol, the header fields and values are those read from the HTTP response sent over the wire. The HTTP protocol allows for multi-valued fields to be repeated, once for each value (this can typically be the case for Cookies). When the HTTP parser encounters a key for which it already has read a value, it adds the new value to the list of values for that key.
The problem is that for multi valued fields, the list returned by HttpURLConnection::getHeaderFields
is in the reversed order in which it was read.
A similar issue occurs when a request header value is added to the request headers.
URLConnection
defines an addRequestProperty
method to add a value to a given key, and a getRequestProperties
method that returns the request header fields as a map
public void addRequestProperty(String key, String value)
public Map<String,List<String>> getRequestProperties()
Although implemented at URLConnection
level, here again, the List
returned by getRequestProperties()
contains the values in the reversed order to which they were added.
This behavior is at the same time surprising, counter-intuitive, and, for the HTTP case, in violation of the specification laid out in RFC2616 which states that the order of such message headers should be preserved.
Solution
This change modifies the default implementation of URLConnection::getRequestProperties
, and the JDK internal implementation of HttpURLConnection::getHeaderFields
to return multiple header values for a given field-name in the order in which they were added, or read.
Specification
This is a behavioral change only. The specification remains unchanged, but the implementation will now behave in a way that should match the caller's expectation. There are, however, the following API Documentation changes for URLConnection
:
/**
* Returns an unmodifiable Map of the header fields.
* The Map keys are Strings that represent the
* response-header field names. Each Map value is an
* unmodifiable List of Strings that represents
* the corresponding field values.
*
+ * This method is overridden by the subclasses of {@code URLConnection}.
+ *
+ * In the implementation of these methods, if a given key has multiple
+ * corresponding values, they must be returned in the order they were added,
+ * preserving the insertion-order.
+ *
+ * @implSpec The default implementation of this method returns an empty map always.
+ *
* @return a Map of header fields
* @since 1.4
*/
public Map<String,List<String>> getHeaderFields() {
...
/**
* Adds a general request property specified by a
* key-value pair. This method will not overwrite
* existing values associated with the same key.
*
+ * This method could be a no-op if appending a value
+ * to the map is not supported by the protocol being
+ * used in a given subclass.
+ *
* @param key the keyword by which the request is known
* (e.g., "{@code Accept}").
* @param value the value associated with it.
* @throws IllegalStateException if already connected
* @throws NullPointerException if key is null
* @see #getRequestProperties()
* @since 1.4
*/
public void addRequestProperty(String key, String value) {
...
/**
* Returns an unmodifiable Map of general request
* properties for this connection. The Map keys
* are Strings that represent the request-header
* field names. Each Map value is a unmodifiable List
* of Strings that represents the corresponding
* field values.
*
+ * If multiple values for a given key are added via the
+ * {@link #addRequestProperty(String, String)} method,
+ * these values will be returned in the order they were
+ * added. This method must preserve the insertion order
+ * of such values.
+ *
+ * The default implementation of this method preserves the insertion order when
+ * multiple values are added for a given key. The values are returned in the order they
+ * were added.
+ *
* @return a Map of the general request properties for this connection.
* @throws IllegalStateException if already connected
* @since 1.4
*/
public Map<String,List<String>> getRequestProperties() {
- csr of
-
JDK-8133686 HttpURLConnection.getHeaderFields and URLConnection.getRequestProperties methods return field values in reverse order
-
- Closed
-