You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
multiple headers of the "same name" allowed in http #3591
Multiple message-header fields with the same field-name MAY be present in a message if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)]. It MUST be possible to combine the multiple header fields into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field-value to the first, each separated by a comma. The order in which header fields with the same field-name are received is therefore significant to the interpretation of the combined field value, and thus a proxy MUST NOT change the order of these field values when a message is forwarded.
Only use the first key when there are duplicate keys once the keys have been converted to lower-case.
Basically, this solution would be to say that since HTTP headers are not case-sensitive, if { cookie: 'foo=bar;', Cookie: 'foo=meh;' } is given, act on it as if the user had really written { cookie: 'foo=bar;', cookie: 'foo=meh;' }, which in JavaScript would have been converted to { cookie: 'foo=meh;' }:
When given an object to set headers from (i.e. res.writeHead(status, obj)), if the obj contains duplicate keys once the keys have been converted to lower case, throw a TypeError.
This would signal to users that there is an issue in the given object, which was expected to only contains header-value pairs.
Option two sounds more appealing since if you can comma separated list syntax to define multiple headers otherwise.
Another option to consider is allowing an optional array syntax for that:
{ cookie: ['foo=bar', 'foo=meh'] }
The problem I saw in production was where one library was using cookie and one external source used Cookie and the headers were merged and one was lost.
Another option to consider is allowing an optional array syntax for that:
{ cookie: ['foo=bar', 'foo=meh'] }
I didn't mention it, because that is already supported; each element in the array will be a different header, making that response look like the following:
Cookie: foo=bar
Cookie: foo=meh
Assuming we are talking about res.writeHead. If you are referring to a different Node.js API, let me know, as I don't see what API is being used actually mentioned here.
It seems like the solution here is to either allow multiple "same name" headers, or, fail loudly when the user tries to send them.
Failing loudly would be a breaking change, and also isn't really a solution since sending multiple headers with the same name is supported by the HTTP specification and required by certain clients. Failing loudly in response to a valid action could also result in someone posting another issue, and we'd be back to square one. Therefore I suggest the only actual solution is to allow multiple headers with the same name.
Therefore I suggest the only actual solution is to allow multiple headers with the same name.
I don't agree with continuing doing something bad simply because fixing it would break things.
Can we start with a warning "depreciated" message ? Deprecated: Multiple header names are being passed <stack trace>. This will be deprecated as of version X
Maybe I've misunderstood something, or not explained myself clearly enough.
As I understand things, what node does now is bad, because instead of honouring multiple headers with the same name (which is allowed in the HTTP specification and necessary in some circumstance) it squashes them.
Changing this to instead of honouring multiple headers with the same name, node reports an error, is still bad and arguably even worse.
In current situation 💡, it would make sense to add Headers into Request and Response and gently deprecate ⛔ old methods, or even leave them as is for backward compatibility with few notes 📝
You mean it's allowed because it's not expressly prohibited?
@danielb2 The title of this issue is somewhat confusing. It talks about multiple headers of the "same name", but does not differentiate between requests and responses. From my understanding there are different problems with Node's implementation of both, however I am only talking about responses. Section 4.2 of the HTTP specification explicitly allows multiple headers with the same name to be sent, providing their values can be combined into a comma separated list.
Multiple message-header fields with the same field-name MAY be present in a message if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)]. It MUST be possible to combine the multiple header fields into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field-value to the first, each separated by a comma. The order in which header fields with the same field-name are received is therefore significant to the interpretation of the combined field value, and thus a proxy MUST NOT change the order of these field values when a message is forwarded.
Node does not currently support adding multiple headers to a response. The closest you can get is to call response.setHeader with an array, which will still result a single header. Therefore Node is not fully compatible with the HTTP specification.
Under what circumstances would it be necessary? (Aside from a mistake)
Google's X-Robots-Tag specification depends on being able to send multiple X-Robots-Tag headers on the response (in a violation of the HTTP specification since they cannot be combined). For example...
The X-Robots-Tag specification is silent of whether this syntax would even work, but at best the noimageindex directive would only apply to bingbot rather than all robots, thus changing the semantic meaning of the X-Robots-Tag header.
Others have cited the following examples where the need to be able to send multiple headers with the same name as part of the HTTP response.
In current situation 💡, it would make sense to add Headers into Request and Response and gently deprecate ⛔ old methods, or even leave them as is for backward compatibility with few notes 📝
Unfortunately this still wouldn't work where multiple response headers with the same name are necessary since according to the append will combine values, rather than writing multiple response headers, which is necessary in some situations.
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.
@cressie176 what about semicolon or newline delimiter '\n' as an option to set multiple values for the same header? 🤔
Hi @bricss, I don't see anything in the HTTP specification about semicolons or new line delimiters having special meaning. I assume that they would be treated as part of the field value, rather than indicating multiple headers.
It seems like the solution here is to either allow multiple "same name" headers, or, fail loudly when the user tries to send them.
If anyone is interested in solving this, the two things that would likely be helpful are:
1. detailing the exact desired solution in a comment here (if different from my summary, or if adding important missing details)
2. sending a PR implementing one or all of those solutions.
@ljharb what do you think about this PR: #6865 😅 I know it's old
Activity
bnoordhuis commentedon Oct 29, 2015
It should be the last one. Headers are added in object insertion order, the last one wins out.
The behavior itself is most likely undocumented but I think we have tests for this (not easy to grep for though.)
danielb2 commentedon Oct 30, 2015
Should it allow multiple by the same at all? Is it too costly to check for this?
bricss commentedon Oct 31, 2015
FYI -> http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
jasnell commentedon Oct 31, 2015
/cc @nodejs/http
dougwilson commentedon Oct 31, 2015
Potentially there are a few solutions here:
Basically, this solution would be to say that since HTTP headers are not case-sensitive, if
{ cookie: 'foo=bar;', Cookie: 'foo=meh;' }is given, act on it as if the user had really written{ cookie: 'foo=bar;', cookie: 'foo=meh;' }, which in JavaScript would have been converted to{ cookie: 'foo=meh;' }:res.writeHead(status, obj)), if theobjcontains duplicate keys once the keys have been converted to lower case, throw aTypeError.This would signal to users that there is an issue in the given object, which was expected to only contains header-value pairs.
danielb2 commentedon Nov 2, 2015
Option two sounds more appealing since if you can comma separated list syntax to define multiple headers otherwise.
Another option to consider is allowing an optional array syntax for that:
{ cookie: ['foo=bar', 'foo=meh'] }
The problem I saw in production was where one library was using
cookieand one external source usedCookieand the headers were merged and one was lost.dougwilson commentedon Nov 2, 2015
I didn't mention it, because that is already supported; each element in the array will be a different header, making that response look like the following:
Assuming we are talking about
res.writeHead. If you are referring to a different Node.js API, let me know, as I don't see what API is being used actually mentioned here.danielb2 commentedon Nov 2, 2015
Perfect :)
bricss commentedon Nov 2, 2015
In that case I presume we can close an issue.
danielb2 commentedon Nov 2, 2015
Why would you make that presumption?
bricss commentedon Nov 2, 2015
FYI -> http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
cressie176 commentedon Jan 10, 2016
Having a similar problem with X-Robots-Tag. I need to support the following
As specified here.
Trott commentedon Jan 10, 2016
@cressie176 According to the documentation:
So I think this would work for your case:
cressie176 commentedon Jan 10, 2016
@Trott, thanks for the quick response. Unfortunately I've tried that - it generates a single header which I don't think conforms to googles spec.
Furthermore if I add an additional directive to apply to all user agents, it gets concatenated with the last one in the list, i.e.
Results in
47 remaining items
ljharb commentedon Mar 8, 2021
It seems like the solution here is to either allow multiple "same name" headers, or, fail loudly when the user tries to send them.
If anyone is interested in solving this, the two things that would likely be helpful are:
cressie176 commentedon Mar 8, 2021
Failing loudly would be a breaking change, and also isn't really a solution since sending multiple headers with the same name is supported by the HTTP specification and required by certain clients. Failing loudly in response to a valid action could also result in someone posting another issue, and we'd be back to square one. Therefore I suggest the only actual solution is to allow multiple headers with the same name.
danielb2 commentedon Mar 8, 2021
I don't agree with continuing doing something bad simply because fixing it would break things.
Can we start with a warning "depreciated" message ?
Deprecated: Multiple header names are being passed <stack trace>. This will be deprecated as of version Xcressie176 commentedon Mar 8, 2021
@danielb2
Maybe I've misunderstood something, or not explained myself clearly enough.
As I understand things, what node does now is bad, because instead of honouring multiple headers with the same name (which is allowed in the HTTP specification and necessary in some circumstance) it squashes them.
Changing this to instead of honouring multiple headers with the same name, node reports an error, is still bad and arguably even worse.
danielb2 commentedon Mar 9, 2021
You mean it's allowed because it's not expressly prohibited? Under what circumstances would it be necessary? (Aside from a mistake)
bricss commentedon Mar 9, 2021
In current situation 💡, it would make sense to add Headers into Request and Response and gently deprecate ⛔ old methods, or even leave them as is for backward compatibility with few notes 📝
cressie176 commentedon Mar 9, 2021
@danielb2 The title of this issue is somewhat confusing. It talks about multiple headers of the "same name", but does not differentiate between requests and responses. From my understanding there are different problems with Node's implementation of both, however I am only talking about responses. Section 4.2 of the HTTP specification explicitly allows multiple headers with the same name to be sent, providing their values can be combined into a comma separated list.
Node does not currently support adding multiple headers to a response. The closest you can get is to call
response.setHeaderwith an array, which will still result a single header. Therefore Node is not fully compatible with the HTTP specification.Google's X-Robots-Tag specification depends on being able to send multiple
X-Robots-Tagheaders on the response (in a violation of the HTTP specification since they cannot be combined). For example...The above headers:
Combining this into a single header would result in:
The X-Robots-Tag specification is silent of whether this syntax would even work, but at best the
noimageindexdirective would only apply to bingbot rather than all robots, thus changing the semantic meaning of the X-Robots-Tag header.Others have cited the following examples where the need to be able to send multiple headers with the same name as part of the HTTP response.
It is not unreasonable to suspect there may be more examples which have not yet been discovered or reported.
cressie176 commentedon Mar 9, 2021
Unfortunately this still wouldn't work where multiple response headers with the same name are necessary since according to the append will combine values, rather than writing multiple response headers, which is necessary in some situations.
bricss commentedon Mar 9, 2021
@cressie176 what about semicolon or newline delimiter '\n' as an option to set multiple values for the same header? 🤔
cressie176 commentedon Mar 10, 2021
Hi @bricss, I don't see anything in the HTTP specification about semicolons or new line delimiters having special meaning. I assume that they would be treated as part of the field value, rather than indicating multiple headers.
PeterDaveHello commentedon Mar 11, 2021
@ljharb what do you think about this PR: #6865 😅 I know it's old
rajeevnaikte commentedon Jan 21, 2022
Construct header using
req.rawHeadersShogunPanda commentedon May 23, 2022
Relative PR has just landed in master. Closing this.