As a matter of fact, Fetch API has been designed to be very familiar to anyone who has used XMLHttpRequest, while providing a more powerful and flexible feature set. The new API provides a generic definition of Request and Response objects, as well as other interface involved with network requests: such approach allow them to be used wherever they are needed in the future, whether it’s for service workers, Cache API, and other similar things that handle or modify requests and responses, or any kind of use case that might require you to generate your responses programmatically. It also defines related concepts such as Cross-Origin Resource Sharing (CORS) and the HTTP Origin header semantics, supplanting their separate definitions elsewhere.
In a nutshell, the bug affects the Fetch API’s Headers interface, which seems to be unable to properly process HTTP responses containing multiple Set-Cookie headers, thus resulting in a cookie nightmare for the client.
To properly understand what I’m talking about, here’s the full story.
As you might know, RFC 6265 indicates that it is allowed to have multiple headers with the Set-Cookie name: that’s quite an obvious choice, since it allows to set multiple cookies in a single HTTP response.
Unfortunately, Fetch API doesn’t allow to do that because all the methods exposed by its Headers interface (including get(), set(), append(), entries() and all the rest) have been implemented to merge the values of all the headers with the same name into a single header separated by commas.
For example, if we do this:
var headers = new Headers();
headers.append('set-cookie', 'test1=v; Max-Age=0');
headers.append('set-cookie', 'test2=v; Max-Age=0');
headers.append('set-cookie', 'test3=v; Max-Age=0');
and then we try to read the set-cookie values using get('set-cookie') , or by iterating the headers variable using entries() , we get this result:
'set-cookie' : test1=v; Max-Age=0, test2=v; Max-Age=0, test3=v; Max-Age=0
It’s worth noting that the same wrong behaviour also happens if we try to read or manipulate an existing response object having multiple headers with the same name (i.e. created by other frameworks that arguably support such allowed behavior): in other words, it seems like the Fetch API is completely unable to properly deal with such scenario.
Now, while this behavior is desired for some headers, such as Accept, the Set-Cookie header is not parsed correctly by most browsers (including Chrome and Firefox), thus resulting in cookies not being correctly set.
Bug or bad design?
The first time I’ve stumbled upon this issue, I honestly thought it was a bug: however, by carefully reading the Fetch API documentation for the various methods, I’ve started to think that the whole scenario was worked as intended. For example, here’s what the append() method’s documentation actually says:
The append() method of the Headers interface appends a new value onto an existing header inside a Headers object, or adds the header if it does not already exist. The difference between set() and append() is that if the specified header already exists and accepts multiple values, set() will overwrite the existing value with the new one, whereas append() will append the new value onto the end of the set of values.
And also, later on:
If the specified header already exists, append() will change its value to the specified value. If the specified header already exists and accepts multiple values, append() will append the new value to the end of the value set.
The append() intended behaviour is then shown in the following code sample:
myHeaders.get('Accept-Encoding'); // Returns 'deflate, gzip'
The same code sample is also used within the get() method’s documentation, which enforces the same behaviour:
If the header has multiple values associated with it, the byte string will contain all the values, in the order they were added to the Headers object.
To put it in other words: instead of append a new Set-Cookie key/value pair (as required by RFC 6265) and retrieve them as a key/value array, the Fetch API seems to be handling those headers using a standard key/value container that only supports a one-dimentional set of unique keys.
StackOverflow (hopefully) to the rescue
Being an avid StackExchange user, I often visit those sites (StackOverflow above all) to answer the questions related to the softwares, operating systems, development frameworks and programming languages I use for work and hobby. This time I chose to ask a question myself, hoping to find a workaround to solve this nasty Fetch API problem. Here’s the link to my question:
Let’s see if I’ll be able to get a valid answer to fix my issue for good.
That’s it, at least for the time being: if I’ll find a way to overcome this nasty Fetch API issue, I won’t fail to let you know by updating this article or writing a new post: take care and happy development!