-
Notifications
You must be signed in to change notification settings - Fork 1k
Description
[REQUIRED] Environment info
firebase-tools: 8.18.1
Platform: OSX
[REQUIRED] Test case
Write a function that sets multiple cookies:
exports.myFunc = require('firebase-functions').https.onRequest((req, res) => {
res.setHeader('Set-Cookie', [
'some=cookie',
'other=one'
]);
res.statusCode = 200;
res.end('');
});
Use Hosting as a proxy to the function. firebase.json
:
{
"hosting": {
"rewrites": [
{ "source": "/wherever", "function": "myFunc" }
]
}
}
[REQUIRED] Steps to reproduce
Hit the proxied function URL: http://myhostingsubdomain.blah.com/wherever
. Check the response headers in Chrome DevTools and check the Application Cookies - only the first will be registered.
[REQUIRED] Expected behavior
The response should include multiple Set-Cookie headers - one for each cookie. Browsers (including Chrome) don't handle a single Set-Cookie header with multiple cookies in it and will ignore all but the first cookie (especially with cookie fields like Expires which can include commas in them). This prevents usage like https://dev.to/johncarroll/how-to-share-firebase-authentication-across-subdomains-1ka8 where your function has to be hosted at the same origin as your Hosting sites (so cloudfunctions.net/blah is no good).
I expect to see response headers like:
Set-Cookie: some=cookie
Set-Cookie: other=one
[REQUIRED] Actual behavior
The response has a single header like:
set-cookie: some=cookie, other=one
Cause
node-fetch
is being used incorrectly, indirectly from lib/hosting/proxy.js
via lib/apiv2.js
's Client::request
. See node-fetch/node-fetch#582 for a similar case. The headers are being extracted from proxyRes.response.headers
in lib/hosting/proxy.js
:
for (const [key, value] of proxyRes.response.headers) {
res.setHeader(key, value);
}
But because node-fetch
stringifies the incoming response headers (which for an Array, effectively concatenates them with commas), we lose our array of headers in the proxied response. The recommended approach is to use response.headers.raw()
to grab those raw Array value
s. When I make that change in lib/hosting/proxy.js
, it works:
for (const [key, value] of Object.entries(proxyRes.response.headers.raw())) {
res.setHeader(key, value);
}
I have no yet validated whether the same problem happens in production or not. Really hoping it doesn't 🤞
UPDATE: Production is fine! This is an emulator-only problem.