JakeChampion / fetch

A window.fetch JavaScript polyfill.
MIT License
25.76k stars 2.84k forks source link

`Set-Cookie` headers should not be combined / Support `Headers.getSetCookie()` method #1384

Open ezzatron opened 1 year ago

ezzatron commented 1 year ago

The Fetch Standard defines special behaviour for Set-Cookie headers:

To sort and combine a header list list, run these steps. They return a header list.

  1. Let headers be a header list.
  2. Let names be the result of convert header names to a sorted-lowercase set with all the names of the headers in list.
  3. For each name of names:
    1. If name is `set-cookie`, then:
      1. Let values be a list of all values of headers in list whose name is a byte-case-insensitive match for name, in order.
      2. For each value of values:
        1. Append (name, value) to headers.
    2. Otherwise:
      1. Let value be the result of getting name from list.
      2. Assert: value is non-null.
      3. Append (name, value) to headers.
  4. Return headers.

This is because the values of set-cookie headers can contain commas, such as in the case of a cookie with an expiry time (e.g. cookie-name=cookie-value; Path=/; Expires=Thu, 21 Sep 2023 06:12:39 GMT; Secure). Combining them with commas can change their semantics.

This library currently seems to ignore this part of the spec, and combine set-cookie values. For example, this is the current behaviour of whatwg-fetch:

const { Headers } = require("whatwg-fetch");

const headers = new Headers();
headers.append("Set-Cookie", "x=x");
headers.append("Set-Cookie", "y=y");

console.log(JSON.stringify([...headers.entries()])); // outputs [["set-cookie","x=x, y=y"]]

In comparison, Chrome and Firefox follow the spec (Safari doesn't):

Chrome output Firefox output

This seems to be a pretty recent addition to the spec (2021ish). There's also a new method Headers: getSetCookie() method added around the same time which is missing from whatwg-fetch:

Chrome getSetCookie output

For context, I'm using whatwg-fetch as a polyfill for running Jest tests that use Mock Service Worker (MSW), similar to this example over in the MSW project. I noticed this issue because I was setting multiple cookies with different options, and the combining of the cookie values was causing strange behaviour in my tests.