http: expose headers on an http.ClientRequest "information" event

1xx intermediate status responses are allowed to have headers; so
expose the "httpVersion", "httpVersionMajor", "httpVersionMinor",
"headers", "rawHeaders", and "statusMessage" properties on this
event.

PR-URL: https://github.com/nodejs/node/pull/28459
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
This commit is contained in:
Austin Wright 2019-06-27 16:10:55 -07:00 committed by Rich Trott
parent 2111207f44
commit d5737a8537
3 changed files with 83 additions and 3 deletions

View File

@ -421,10 +421,18 @@ added: v10.0.0
-->
* `info` {Object}
* `httpVersion` {string}
* `httpVersionMajor` {integer}
* `httpVersionMinor` {integer}
* `statusCode` {integer}
* `statusMessage` {string}
* `headers` {Object}
* `rawHeaders` {string[]}
Emitted when the server sends a 1xx response (excluding 101 Upgrade). The
listeners of this event will receive an object containing the status code.
Emitted when the server sends a 1xx intermediate response (excluding 101
Upgrade). The listeners of this event will receive an object containing the
HTTP version, status code, status message, key-value headers object,
and array with the raw header names followed by their respective values.
```js
const http = require('http');

View File

@ -549,7 +549,15 @@ function parserOnIncomingClient(res, shouldKeepAlive) {
req.emit('continue');
}
// Send information events to all 1xx responses except 101 Upgrade.
req.emit('information', { statusCode: res.statusCode });
req.emit('information', {
statusCode: res.statusCode,
statusMessage: res.statusMessage,
httpVersion: res.httpVersion,
httpVersionMajor: res.httpVersionMajor,
httpVersionMinor: res.httpVersionMinor,
headers: res.headers,
rawHeaders: res.rawHeaders
});
return 1; // Skip body but don't treat as Upgrade.
}

View File

@ -0,0 +1,64 @@
'use strict';
require('../common');
const assert = require('assert');
const http = require('http');
const Countdown = require('../common/countdown');
const test_res_body = 'other stuff!\n';
const countdown = new Countdown(2, () => server.close());
const server = http.createServer((req, res) => {
console.error('Server sending informational message #1...');
// These function calls may rewritten as necessary
// to call res.writeHead instead
res._writeRaw('HTTP/1.1 102 Processing\r\n');
res._writeRaw('Foo: Bar\r\n');
res._writeRaw('\r\n');
console.error('Server sending full response...');
res.writeHead(200, {
'Content-Type': 'text/plain',
'ABCD': '1'
});
res.end(test_res_body);
});
server.listen(0, function() {
const req = http.request({
port: this.address().port,
path: '/world'
});
req.end();
console.error('Client sending request...');
let body = '';
req.on('information', function(res) {
assert.strictEqual(res.httpVersion, '1.1');
assert.strictEqual(res.httpVersionMajor, 1);
assert.strictEqual(res.httpVersionMinor, 1);
assert.strictEqual(res.statusCode, 102,
`Received ${res.statusCode}, not 102.`);
assert.strictEqual(res.statusMessage, 'Processing',
`Received ${res.statusMessage}, not "Processing".`);
assert.strictEqual(res.headers.foo, 'Bar');
assert.strictEqual(res.rawHeaders[0], 'Foo');
assert.strictEqual(res.rawHeaders[1], 'Bar');
console.error('Client got 102 Processing...');
countdown.dec();
});
req.on('response', function(res) {
// Check that all 102 Processing received before full response received.
assert.strictEqual(countdown.remaining, 1);
assert.strictEqual(res.statusCode, 200,
`Final status code was ${res.statusCode}, not 200.`);
res.setEncoding('utf8');
res.on('data', function(chunk) { body += chunk; });
res.on('end', function() {
console.error('Got full response.');
assert.strictEqual(body, test_res_body);
assert.ok('abcd' in res.headers);
countdown.dec();
});
});
});