-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow multiple set-cookie headers #4840
Conversation
name, | ||
existingValue ? `${existingValue}, ${value}` : value | ||
); | ||
this.append(tuple[0], tuple[1]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I refactored the constructor a bit, to keep the code DRY
and to reuse Set-Cookie
logic in append/set
methods.
Better appoach then mine. What about custom headers which are allowed to be send multiple times? |
Thanks! |
I'm working on adding some more tests. |
Could you add a test for the constructor taking an |
Sure, can I grab yours with some minor editions? |
Sure! Just check the expected output which is wrong as you can see in the automated testing routine for macos-release |
@@ -97,12 +96,22 @@ class HeadersBase { | |||
return `Headers {${output}}`; | |||
} | |||
|
|||
cookies(): IterableIterator<string> { | |||
return this[cookieMap].values(); | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method isn't in the web API
https://developer.mozilla.org/en-US/docs/Web/API/Headers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know, I mentioned that but it was hard to implement Set-Cookie
behaviour it without extending it a bit since the web API did a compromise that the server cannot do. Although a better alternative could be to use a symbol
, maybe in the Deno namespace.
[Deno.cookiesIteratorSymbol](): IterableIterator<string> {
return this[cookieMap].values();
}
That way is web compatible & can be iterated in std/http/io.ts
. I'm not yet very familiar with the codebase, an alternative to expose a Symbol that can be used in std
and cli/web
will work too.
What do you think?
// Servers SHOULD NOT include more than one Set-Cookie header field in | ||
// the same response with the same cookie-name | ||
[cookieMap]: Map<string, string>; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general Headers are not a Key/Value pair - I think headerMap should be replaced with a list of key, value pairs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented a Map<cookieName, cookieHeaderValue>
so we only kept the last value for the same cookie name, which is what the spec says. If I use a list of key/value pairs, I'll need to add additional logic to remove duplicates and keep the last one.
We are not storing strictly headers, but cookieName/SetCookieValue
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks - this is much better than before with the regex, but it's made the Headers object not web compatible.
Thank you. It should be web compatible now, by using a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @marcosc90 sorry for the delay on this. I've wanted to check this out and get my hands dirty with it - because maybe I'm just missing something - but I think this can be done in a simpler more general way by changing the structure of headers from Map<string, string>
to Array<[string, string]>
. But I haven't had the time to actually try myself.
@@ -43,15 +46,23 @@ function validateValue(value: string): void { | |||
class HeadersBase { | |||
[headerMap]: Map<string, string>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the wrong structure to store HTTP headers. It should be Array<[string, string]>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using Array<[string, string]>
would make it browser incompatible. If use call Headers.prototype.append
with the same key in the browser you expect to override the previous header. But not with Set-Cookie
. In this case is has to be incompatible with the standardized Header
implementation.
IMHO I would prefer HeaderMap to be an Array
as well to make it work without exceptions. But the user has to be warned, that append
is not a Map
anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with you, didn't want to change that because of the premise of trying to be fully browser compatible.
I can do a rework, store headers in Array<[string, string]>
and change all the methods. But we'll need to define what we'll expect when the user does:
header.set('Set-Cooke', 'some-value');
header.set('Set-Cooke', 'other-value');
header.get('Set-Cookie'); // ['some-value', 'other-value']
header.get('Set-Cookie'); // 'some-value, other-value'
If we return an array, it's not respecting the specification. Although Set-Cookie
is not used by users on the client side.
If we use an Array
I can drop the cookies Map
, although I'll have to loop every time we try to set a cookie, because we can't store cookies with same name, we should only keep the latest one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And what happens when using an Array
and header.set('Content-Type');
twice!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And what happens when using an
Array
andheader.set('Content-Type');
twice!
We can still make it browser compatible by using Array<[string, string]>
and doing extra validation and looping through the array on every method. The implementation will be less clean and a bit slower since we'll be iterating constantly through the array.
After offline discussion we decided to go with #5100 as it doesn't introduce new symbols. Thank you @marcosc90 for your work but I'm gonna close this PR without a merge. |
Multiple
Set-Cookie
headers should be allowed without allowing multiple headers with same cookie nameSee RFC 6265
This was also being worked here #4829, although with a different approach
Fixes #4826
I exposed a new method
cookies
to iterate through the cookiesMap
, I know this is not in the spec but the spec was built for client-side JavaScript. (Alternatives are welcome though)