Skip to content

Commit

Permalink
http: implement capture rejections for 'request' event
Browse files Browse the repository at this point in the history
PR-URL: #27867
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
  • Loading branch information
mcollina authored and targos committed Jan 14, 2020
1 parent fa544c8 commit cdc33df
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 0 deletions.
21 changes: 21 additions & 0 deletions lib/_http_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const {
} = primordials;

const net = require('net');
const EE = require('events');
const assert = require('internal/assert');
const {
parsers,
Expand Down Expand Up @@ -358,6 +359,26 @@ Server.prototype.setTimeout = function setTimeout(msecs, callback) {
return this;
};

Server.prototype[EE.captureRejectionSymbol] = function(
err, event, req, res) {

switch (event) {
case 'request':
if (!res.headersSent && !res.writableEnded) {
// Don't leak headers.
for (const name of res.getHeaderNames()) {
res.removeHeader(name);
}
res.statusCode = 500;
res.end(STATUS_CODES[500]);
} else {
res.destroy();
}
break;
default:
this.emit('error', err);
}
};

function connectionListener(socket) {
defaultTriggerAsyncIdScope(
Expand Down
108 changes: 108 additions & 0 deletions test/parallel/test-http-server-capture-rejections.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
'use strict';

const common = require('../common');
const events = require('events');
const { createServer, request } = require('http');
const assert = require('assert');

events.captureRejections = true;

{
const server = createServer(common.mustCall(async (req, res) => {
// We will test that this header is cleaned up before forwarding.
res.setHeader('content-type', 'application/json');
throw new Error('kaboom');
}));

server.listen(0, common.mustCall(() => {
const req = request({
method: 'GET',
host: server.address().host,
port: server.address().port
});

req.end();

req.on('response', common.mustCall((res) => {
assert.strictEqual(res.statusCode, 500);
assert.strictEqual(res.headers.hasOwnProperty('content-type'), false);
let data = '';
res.setEncoding('utf8');
res.on('data', common.mustCall((chunk) => {
data += chunk;
}));
res.on('end', common.mustCall(() => {
assert.strictEqual(data, 'Internal Server Error');
server.close();
}));
}));
}));
}

{
let resolve;
const latch = new Promise((_resolve) => {
resolve = _resolve;
});
const server = createServer(common.mustCall(async (req, res) => {
server.close();

// We will test that this header is cleaned up before forwarding.
res.setHeader('content-type', 'application/json');
res.write('{');
req.resume();

// Wait so the data is on the wire
await latch;

throw new Error('kaboom');
}));

server.listen(0, common.mustCall(() => {
const req = request({
method: 'GET',
host: server.address().host,
port: server.address().port
});

req.end();

req.on('response', common.mustCall((res) => {
assert.strictEqual(res.statusCode, 200);
assert.strictEqual(res.headers['content-type'], 'application/json');
resolve();

let data = '';
res.setEncoding('utf8');
res.on('data', common.mustCall((chunk) => {
data += chunk;
}));

req.on('close', common.mustCall(() => {
assert.strictEqual(data, '{');
}));
}));
}));
}

{
const server = createServer(common.mustCall(async (req, res) => {
// We will test that this header is cleaned up before forwarding.
res.writeHead(200);
throw new Error('kaboom');
}));

server.listen(0, common.mustCall(() => {
const req = request({
method: 'GET',
host: server.address().host,
port: server.address().port
});

req.end();
req.on('error', common.mustCall((err) => {
assert.strictEqual(err.code, 'ECONNRESET');
server.close();
}));
}));
}

0 comments on commit cdc33df

Please sign in to comment.