Skip to content

Commit 25db02a

Browse files
authored
Merge pull request #3178 from kanongil/catch-errors-fix
Handle thrown error from res.setHeader() and res.writeHead()
2 parents 78e50de + 5e98494 commit 25db02a

File tree

2 files changed

+94
-13
lines changed

2 files changed

+94
-13
lines changed

lib/transmit.js

+45-13
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,15 @@ exports.send = function (request, callback) {
3434
return internals.fail(request, err, callback);
3535
}
3636

37-
return internals.transmit(response, callback);
37+
return internals.transmit(response, (err) => {
38+
39+
if (err) {
40+
request._setResponse(err);
41+
return internals.fail(request, err, callback);
42+
}
43+
44+
return callback();
45+
});
3846
});
3947
};
4048

@@ -274,23 +282,19 @@ internals.transmit = function (response, callback) {
274282
response.headers.etag = response.headers.etag.slice(0, -1) + '-' + (response.headers['content-encoding'] || encoding) + '"';
275283
}
276284

277-
// Write headers
278-
279-
const headers = Object.keys(response.headers);
280-
for (let i = 0; i < headers.length; ++i) {
281-
const header = headers[i];
282-
const value = response.headers[header];
283-
if (value !== undefined) {
284-
request.raw.res.setHeader(header, value);
285-
}
286-
}
285+
// Connection: close
287286

288287
const isInjection = Shot.isInjection(request.raw.req);
289288
if (!isInjection && !request.connection._started) {
290-
request.raw.res.setHeader('connection', 'close');
289+
response._header('connection', 'close');
291290
}
292291

293-
request.raw.res.writeHead(response.statusCode);
292+
// Write headers
293+
294+
const res = internals.writeHead(response);
295+
if (res) {
296+
return process.nextTick(callback, res);
297+
}
294298

295299
// Write payload
296300

@@ -369,6 +373,34 @@ internals.transmit = function (response, callback) {
369373
};
370374

371375

376+
internals.writeHead = function (response) {
377+
378+
const res = response.request.raw.res;
379+
380+
try {
381+
const headers = Object.keys(response.headers);
382+
for (let i = 0; i < headers.length; ++i) {
383+
const header = headers[i];
384+
const value = response.headers[header];
385+
if (value !== undefined) {
386+
res.setHeader(header, value);
387+
}
388+
}
389+
390+
res.writeHead(response.statusCode);
391+
}
392+
catch (err) {
393+
394+
// Reset headers and return err
395+
396+
res._headers = null;
397+
res._headerNames = {};
398+
399+
return Boom.wrap(err);
400+
}
401+
};
402+
403+
372404
internals.Empty = function () {
373405

374406
Stream.Readable.call(this);

test/transmit.js

+49
Original file line numberDiff line numberDiff line change
@@ -2364,6 +2364,55 @@ describe('transmission', () => {
23642364
done();
23652365
});
23662366
});
2367+
2368+
it('returns 500 when node rejects a header', (done) => {
2369+
2370+
const server = new Hapi.Server();
2371+
server.connection();
2372+
2373+
const handler = function (request, reply) {
2374+
2375+
return reply('ok').header('', 'test');
2376+
};
2377+
2378+
server.route({ method: 'GET', path: '/', handler: handler });
2379+
server.inject('/', (res) => {
2380+
2381+
expect(res.statusCode).to.equal(500);
2382+
done();
2383+
});
2384+
});
2385+
2386+
it('returns 500 for out of range status code', (done) => {
2387+
2388+
const server = new Hapi.Server();
2389+
server.connection();
2390+
2391+
const handler = function (request, reply) {
2392+
2393+
// Patch writeHead to always fail on out of range headers
2394+
2395+
const origWriteHead = request.raw.res.writeHead;
2396+
request.raw.res.writeHead = function (statusCode) {
2397+
2398+
statusCode |= 0;
2399+
if (statusCode < 100 || statusCode > 999) {
2400+
throw new RangeError(`Invalid status code: ${statusCode}`);
2401+
}
2402+
2403+
return origWriteHead.apply(this, arguments);
2404+
};
2405+
2406+
return reply('ok').code(1);
2407+
};
2408+
2409+
server.route({ method: 'GET', path: '/', handler: handler });
2410+
server.inject('/', (res) => {
2411+
2412+
expect(res.statusCode).to.equal(500);
2413+
done();
2414+
});
2415+
});
23672416
});
23682417

23692418
describe('cache()', () => {

0 commit comments

Comments
 (0)