writeHead doesn't work as expected when passing headers as second parameter
luchsamapparat opened this issue · 6 comments
Hey,
first of all: thanks for providing this library!
I ran into an issue with another library where writeHead
is called like this:
res.writeHead(302, {
'Access-Control-Allow-Origin': '*',
'Location': path
});
It took me some time to realize, that azure-function-express
provides its own implementation of this method. It seems that there is a incompatibility, as the original one allows for the second statusMessage
to be omitted as you can see in the Node documentation:
const body = 'hello world';
response.writeHead(200, {
'Content-Length': Buffer.byteLength(body),
'Content-Type': 'text/plain' });
https://nodejs.org/api/http.html#http_response_writehead_statuscode_statusmessage_headers
The implementation provided by azure-function-express
doesn't support this call signature:
function writeHead(context, statusCode, statusMessage, headers) {
// 1. Status code
statusCode |= 0; // eslint-disable-line no-param-reassign
if (statusCode < 100 || statusCode > 999) {
throw new RangeError(`Invalid status code: ${statusCode}`);
}
// 2. Status message
this.statusMessage = statusMessage || statusCodes[statusCode] || "unknown";
// 3. Headers
if (this._headers) {
// Slow-case: when progressive API and header fields are passed.
if (headers) {
const keys = Object.keys(headers);
for (let i = 0; i < keys.length; i++) {
const k = keys[i];
if (k) {
this.setHeader(k, headers[k]);
}
}
}
// only progressive api is used
headers = this._renderHeaders(); // eslint-disable-line no-param-reassign
}
// 4. Sets everything
context.res.status = statusCode;
context.res.headers = headers;
}
https://github.com/yvele/azure-function-express/blob/master/src/OutgoingMessage.js#L44
After I fixed this issue locally, I stumbled upon another issue. The library I use, contains the following to calls:
res.writeHead(302, null, {
'Access-Control-Allow-Origin': '*',
'Location': path
});
res.end();
But when looking at the implementation of end
, it seems that the status code is overwritten:
function end(context, data, encoding) {
// 1. Write head
this.writeHead(this.statusCode); // Make jshttp/on-headers able to trigger
// 2. Return raw body to Azure Function runtime
context.res.body = convertToBody(data, encoding);
context.res.isRaw = true;
context.done();
}
writeHead
does not set this.statusCode
which leads to end
setting the statusCode
to 200
. Is this the intended behavior? In my case this means, that the Location
header is ignored by the browser as the status code is not within the 3** range.
@luchsamapparat thank you for your investigation on this.
May I ask you what exactly is the library you are using?
I'm using oauth-shim to build an OAuth proxy according to the documentation from hello.js.
The implementation is pretty simple as you just have to configure Express.js to use oauth-shim:
const express = require("express");
const createHandler = require("azure-function-express").createHandler;
const oauthshim = require('oauth-shim');
const param = require('oauth-shim/src/utils/param');
const app = express();
app.all('/api/oauth-btg', oauthshim);
// monkey patch for writeHead issue in azure-function-express
oauthshim.redirect = function (req, res, next) {
if (req.oauthshim && req.oauthshim.redirect) {
let hash = req.oauthshim.data;
let path = req.oauthshim.redirect;
path += (hash ? '#' + param(hash) : '');
// bugfix: always pass statusMessage as second param
res.writeHead(302, null, {
'Access-Control-Allow-Origin': '*',
'Location': path
});
res.statusCode = 302;
res.end();
}
else if (next) {
next();
}
};
oauthshim.init([{
client_id: 'XXX',
client_secret: 'XXX',
grant_url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
domain: 'XXX'
}]);
module.exports = createHandler(app);
maybe it's me but i cannot get this call to this._renderHeaders() here:
https://github.com/yvele/azure-function-express/blob/master/src/OutgoingMessage.js#L67
where does _renderHeaders() come from ? (not in the azure-functions response object)
my app crashes with a NPE just there.