Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8269296

com/sun/net/httpserver/Headers.java: Ensure mutators normalize keys and disallow null for keys and values

    XMLWordPrintable

Details

    • CSR
    • Resolution: Approved
    • P4
    • 18
    • core-libs
    • None
    • behavioral
    • low
    • Hide
      In previous versions of the JDK `com.sun.net.httpserver.Headers` was documented to support `null` keys and `null` values. However, it was also specified that Headers created by the HttpServer would never contain `null` keys or values, and passing a Headers instance containing nulls to the HttpServer caused undocumented exceptions. With this change, the exception will be raised more eagerly, when attempting to add `null` to a Headers instance, rather than later, when passing the instance to the HttpServer.
      There is a risk of incompatibility in the case where an application takes advantage of a headers instance with nulls for its own purpose, and then removing them before passing the instance back to the HttpServer. This scenario seems unlikely however.
      Another potential risk of incompatibility is if an application queries a header for a key of the value `null`. Previously `false` would have been returned but now a NullPointerException is thrown.
      These behavior changes will need to be described in the release notes.
      Show
      In previous versions of the JDK `com.sun.net.httpserver.Headers` was documented to support `null` keys and `null` values. However, it was also specified that Headers created by the HttpServer would never contain `null` keys or values, and passing a Headers instance containing nulls to the HttpServer caused undocumented exceptions. With this change, the exception will be raised more eagerly, when attempting to add `null` to a Headers instance, rather than later, when passing the instance to the HttpServer. There is a risk of incompatibility in the case where an application takes advantage of a headers instance with nulls for its own purpose, and then removing them before passing the instance back to the HttpServer. This scenario seems unlikely however. Another potential risk of incompatibility is if an application queries a header for a key of the value `null`. Previously `false` would have been returned but now a NullPointerException is thrown. These behavior changes will need to be described in the release notes.
    • Java API
    • JDK

    Description

      Summary

      Reconcile handling of header names and values in the com.sun.net.httpserver.Headers class in the jdk.httpserver module by

      (1) aligning the behaviour of its mutators with respect to key normalization,
      (2) enforcing the restriction of null arguments for keys and values eagerly and consistently to prevent the construction of faulty Headers instances.
      (3) adding a toString implementation.

      Problem

      (1) The Headers class normalizes its keys to adhere to the following format: First character uppercase, all other characters lowercase. This behaviour is not consistent across the mutator methods of the class, in particular because not all methods of the implemented java.util.Map interface are overridden with an adequate implementation.

      (2) Headers does not consistently prohibit null as argument for header keys and values. It is possible to create a headers instance with a key-value mapping where the key is null, or where the value is null or a list with a null element. However, any of those three mappings leads to a failure in the HttpServer as a NullPointerException is thrown when the server tries to send a response with the mapping in the response header. This behaviour fails lazily which is not user-friendly. Furthermore, the behaviour is inconsistent because some methods allow null arguments and other do not. In particular, the following methods may inconsistently throw a NullPointerException in JDK 16 depending on whether the key or value arguments are null:

      Inherited from java.util.Map
      - add
      - compute
      - computeIfAbsent
      - computeIfPresent
      - merge
      - putIfAbsent
      - replace

      Headers
      - put
      - set

      (3) Object::toString is not overridden so the returned String is not very informative.

      Solution

      (1) Provide an implementation of the java.util.Map default method replaceAll that normalizes header keys and update the existing putAll implementation. Additionally, add the @Override annotation to all methods that override a method of java.util.Map to improve the maintainability of the class.

      (2) Establish the eager and consistent prohibition of null for header keys and values. Update the class-level specification to describe null as ineligible for keys and values. Update the implementation of all accessor and mutator methods to include null checks. With this behavioural change, the following methods now throw a NullPointerException consistently if the key or value arguments are null (where they passed previously):

      Inherited from java.util.Map
      - add
      - compute
      - computeIfAbsent
      - computeIfPresent
      - containsKey
      - containsValue
      - get
      - getOrDefault
      - merge
      - putAll
      - putIfAbsent
      - remove
      - replace
      - replaceAll

      Headers
      - getFirst
      - put
      - set

      (3) Provide an adequate toString implementation.

      Specification

      com/sun/net/httpserver/Headers.java

       -    * <p> All methods in this class accept {@code null} values for keys and values.
       -    * However, {@code null} keys will never will be present in HTTP request
       -    * headers, and will not be output/sent in response headers. Null values can be
       -    * represented as either a {@code null} entry for the key (i.e. the list is
       -    * {@code null}) or where the key has a list, but one (or more) of the  list's
       -    * values is {@code null}. Null values are output as a header line containing
       -    * the key but no associated value.
       -    *
       +    * <p> All methods in this class reject {@code null} values for keys and values.
       +    * {@code null} keys will never be present in HTTP request or response headers.
            * @since 1.6
            */
           public class Headers implements Map<String,List<String>> {
      
               ...
      
               /**
       -        * Returns the first value from the {@link List} of {@code String}
       -        * values for the given key (if at least one exists).
       +        * Returns the first value from the {@link List} of {@code String} values
       +        * for the given {@code key}, or {@code null} if no mapping for the
       +        * {@code key} exists.
                *
                * @param key the key to search for
       -        * @return the first {@code String} value associated with the key
       +        * @return    the first {@code String} value associated with the key,
       +        *            or {@code null} if no mapping for the key exists
                */
               public String getFirst(String key) { ... }
      
               ...
      
           }

      Attachments

        Issue Links

          Activity

            People

              jboes Julia Boes (Inactive)
              jboes Julia Boes (Inactive)
              Chris Hegarty, Daniel Fuchs
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: