Skip to content

Commit c247cb0

Browse files
Peter MartonMylesBorins
Peter Marton
authored andcommitted
http: add options to http.createServer()
This adds the optional options argument to `http.createServer()`. It contains two options: the `IncomingMessage` and `ServerReponse` option. PR-URL: #15752 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Anatoli Papirovski <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Evan Lucas <[email protected]>
1 parent 7a432c1 commit c247cb0

9 files changed

+222
-9
lines changed

doc/api/http.md

+12-2
Original file line numberDiff line numberDiff line change
@@ -1663,10 +1663,20 @@ A collection of all the standard HTTP response status codes, and the
16631663
short description of each. For example, `http.STATUS_CODES[404] === 'Not
16641664
Found'`.
16651665

1666-
## http.createServer([requestListener])
1666+
## http.createServer([options][, requestListener])
16671667
<!-- YAML
16681668
added: v0.1.13
1669-
-->
1669+
- version: REPLACEME
1670+
pr-url: https://github.com/nodejs/node/pull/15752
1671+
description: The `options` argument is supported now.
1672+
-->
1673+
- `options` {Object}
1674+
* `IncomingMessage` {http.IncomingMessage} Specifies the IncomingMessage class
1675+
to be used. Useful for extending the original `IncomingMessage`. Defaults
1676+
to: `IncomingMessage`
1677+
* `ServerResponse` {http.ServerResponse} Specifies the ServerResponse class to
1678+
be used. Useful for extending the original `ServerResponse`. Defaults to:
1679+
`ServerResponse`
16701680
- `requestListener` {Function}
16711681

16721682
* Returns: {http.Server}

doc/api/https.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ See [`http.Server#keepAliveTimeout`][].
6565
<!-- YAML
6666
added: v0.3.4
6767
-->
68-
- `options` {Object} Accepts `options` from [`tls.createServer()`][] and [`tls.createSecureContext()`][].
68+
- `options` {Object} Accepts `options` from [`tls.createServer()`][],
69+
[`tls.createSecureContext()`][] and [`http.createServer()`][].
6970
- `requestListener` {Function} A listener to be added to the `request` event.
7071

7172
Example:
@@ -258,6 +259,7 @@ const req = https.request(options, (res) => {
258259
[`http.Server#setTimeout()`]: http.html#http_server_settimeout_msecs_callback
259260
[`http.Server#timeout`]: http.html#http_server_timeout
260261
[`http.Server`]: http.html#http_class_http_server
262+
[`http.createServer()`]: http.html#httpcreateserveroptions-requestlistener
261263
[`http.close()`]: http.html#http_server_close_callback
262264
[`http.get()`]: http.html#http_http_get_options_callback
263265
[`http.request()`]: http.html#http_http_request_options_callback

lib/_http_common.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const {
3434

3535
const debug = require('util').debuglog('http');
3636

37+
const kIncomingMessage = Symbol('IncomingMessage');
3738
const kOnHeaders = HTTPParser.kOnHeaders | 0;
3839
const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;
3940
const kOnBody = HTTPParser.kOnBody | 0;
@@ -73,7 +74,11 @@ function parserOnHeadersComplete(versionMajor, versionMinor, headers, method,
7374
parser._url = '';
7475
}
7576

76-
parser.incoming = new IncomingMessage(parser.socket);
77+
// Parser is also used by http client
78+
var ParserIncomingMessage = parser.socket && parser.socket.server ?
79+
parser.socket.server[kIncomingMessage] : IncomingMessage;
80+
81+
parser.incoming = new ParserIncomingMessage(parser.socket);
7782
parser.incoming.httpVersionMajor = versionMajor;
7883
parser.incoming.httpVersionMinor = versionMinor;
7984
parser.incoming.httpVersion = `${versionMajor}.${versionMinor}`;
@@ -300,5 +305,6 @@ module.exports = {
300305
freeParser,
301306
httpSocketSetup,
302307
methods,
303-
parsers
308+
parsers,
309+
kIncomingMessage
304310
};

lib/_http_server.js

+19-4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const {
3333
continueExpression,
3434
chunkExpression,
3535
httpSocketSetup,
36+
kIncomingMessage,
3637
_checkInvalidHeaderChar: checkInvalidHeaderChar
3738
} = require('_http_common');
3839
const { OutgoingMessage } = require('_http_outgoing');
@@ -41,9 +42,12 @@ const {
4142
defaultTriggerAsyncIdScope,
4243
getOrSetAsyncId
4344
} = require('internal/async_hooks');
45+
const { IncomingMessage } = require('_http_incoming');
4446
const errors = require('internal/errors');
4547
const Buffer = require('buffer').Buffer;
4648

49+
const kServerResponse = Symbol('ServerResponse');
50+
4751
const STATUS_CODES = {
4852
100: 'Continue',
4953
101: 'Switching Protocols',
@@ -263,9 +267,19 @@ function writeHead(statusCode, reason, obj) {
263267
// Docs-only deprecated: DEP0063
264268
ServerResponse.prototype.writeHeader = ServerResponse.prototype.writeHead;
265269

270+
function Server(options, requestListener) {
271+
if (!(this instanceof Server)) return new Server(options, requestListener);
272+
273+
if (typeof options === 'function') {
274+
requestListener = options;
275+
options = {};
276+
} else if (options == null || typeof options === 'object') {
277+
options = util._extend({}, options);
278+
}
279+
280+
this[kIncomingMessage] = options.IncomingMessage || IncomingMessage;
281+
this[kServerResponse] = options.ServerResponse || ServerResponse;
266282

267-
function Server(requestListener) {
268-
if (!(this instanceof Server)) return new Server(requestListener);
269283
net.Server.call(this, { allowHalfOpen: true });
270284

271285
if (requestListener) {
@@ -587,7 +601,7 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
587601
}
588602
}
589603

590-
var res = new ServerResponse(req);
604+
var res = new server[kServerResponse](req);
591605
res._onPendingData = updateOutgoingData.bind(undefined, socket, state);
592606

593607
res.shouldKeepAlive = keepAlive;
@@ -690,5 +704,6 @@ module.exports = {
690704
STATUS_CODES,
691705
Server,
692706
ServerResponse,
693-
_connectionListener: connectionListener
707+
_connectionListener: connectionListener,
708+
kServerResponse
694709
};

lib/https.js

+6
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ const { inherits } = util;
3636
const debug = util.debuglog('https');
3737
const { urlToOptions, searchParamsSymbol } = require('internal/url');
3838
const errors = require('internal/errors');
39+
const { IncomingMessage, ServerResponse } = require('http');
40+
const { kIncomingMessage } = require('_http_common');
41+
const { kServerResponse } = require('_http_server');
3942

4043
function Server(opts, requestListener) {
4144
if (!(this instanceof Server)) return new Server(opts, requestListener);
@@ -57,6 +60,9 @@ function Server(opts, requestListener) {
5760
opts.ALPNProtocols = ['http/1.1'];
5861
}
5962

63+
this[kIncomingMessage] = opts.IncomingMessage || IncomingMessage;
64+
this[kServerResponse] = opts.ServerResponse || ServerResponse;
65+
6066
tls.Server.call(this, opts, _connectionListener);
6167

6268
this.httpAllowHalfOpen = false;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
'use strict';
2+
3+
/**
4+
* This test covers http.Server({ IncomingMessage }) option:
5+
* With IncomingMessage option the server should use
6+
* the new class for creating req Object instead of the default
7+
* http.IncomingMessage.
8+
*/
9+
const common = require('../common');
10+
const assert = require('assert');
11+
const http = require('http');
12+
13+
class MyIncomingMessage extends http.IncomingMessage {
14+
getUserAgent() {
15+
return this.headers['user-agent'] || 'unknown';
16+
}
17+
}
18+
19+
const server = http.Server({
20+
IncomingMessage: MyIncomingMessage
21+
}, common.mustCall(function(req, res) {
22+
assert.strictEqual(req.getUserAgent(), 'node-test');
23+
res.statusCode = 200;
24+
res.end();
25+
}));
26+
server.listen();
27+
28+
server.on('listening', function makeRequest() {
29+
http.get({
30+
port: this.address().port,
31+
headers: {
32+
'User-Agent': 'node-test'
33+
}
34+
}, (res) => {
35+
assert.strictEqual(res.statusCode, 200);
36+
res.on('end', () => {
37+
server.close();
38+
});
39+
res.resume();
40+
});
41+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'use strict';
2+
3+
/**
4+
* This test covers http.Server({ ServerResponse }) option:
5+
* With ServerResponse option the server should use
6+
* the new class for creating res Object instead of the default
7+
* http.ServerResponse.
8+
*/
9+
const common = require('../common');
10+
const assert = require('assert');
11+
const http = require('http');
12+
13+
class MyServerResponse extends http.ServerResponse {
14+
status(code) {
15+
return this.writeHead(code, { 'Content-Type': 'text/plain' });
16+
}
17+
}
18+
19+
const server = http.Server({
20+
ServerResponse: MyServerResponse
21+
}, common.mustCall(function(req, res) {
22+
res.status(200);
23+
res.end();
24+
}));
25+
server.listen();
26+
27+
server.on('listening', function makeRequest() {
28+
http.get({ port: this.address().port }, (res) => {
29+
assert.strictEqual(res.statusCode, 200);
30+
res.on('end', () => {
31+
server.close();
32+
});
33+
res.resume();
34+
});
35+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict';
2+
3+
/**
4+
* This test covers http.Server({ IncomingMessage }) option:
5+
* With IncomingMessage option the server should use
6+
* the new class for creating req Object instead of the default
7+
* http.IncomingMessage.
8+
*/
9+
const common = require('../common');
10+
const fixtures = require('../common/fixtures');
11+
12+
if (!common.hasCrypto)
13+
common.skip('missing crypto');
14+
15+
const assert = require('assert');
16+
const http = require('http');
17+
const https = require('https');
18+
19+
class MyIncomingMessage extends http.IncomingMessage {
20+
getUserAgent() {
21+
return this.headers['user-agent'] || 'unknown';
22+
}
23+
}
24+
25+
const server = https.createServer({
26+
key: fixtures.readKey('agent1-key.pem'),
27+
cert: fixtures.readKey('agent1-cert.pem'),
28+
ca: fixtures.readKey('ca1-cert.pem'),
29+
IncomingMessage: MyIncomingMessage
30+
}, common.mustCall(function(req, res) {
31+
assert.strictEqual(req.getUserAgent(), 'node-test');
32+
res.statusCode = 200;
33+
res.end();
34+
}));
35+
server.listen();
36+
37+
server.on('listening', function makeRequest() {
38+
https.get({
39+
port: this.address().port,
40+
rejectUnauthorized: false,
41+
headers: {
42+
'User-Agent': 'node-test'
43+
}
44+
}, (res) => {
45+
assert.strictEqual(res.statusCode, 200);
46+
res.on('end', () => {
47+
server.close();
48+
});
49+
res.resume();
50+
});
51+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use strict';
2+
3+
/**
4+
* This test covers http.Server({ ServerResponse }) option:
5+
* With ServerResponse option the server should use
6+
* the new class for creating res Object instead of the default
7+
* http.ServerResponse.
8+
*/
9+
const common = require('../common');
10+
const fixtures = require('../common/fixtures');
11+
12+
if (!common.hasCrypto)
13+
common.skip('missing crypto');
14+
15+
const assert = require('assert');
16+
const http = require('http');
17+
const https = require('https');
18+
19+
class MyServerResponse extends http.ServerResponse {
20+
status(code) {
21+
return this.writeHead(code, { 'Content-Type': 'text/plain' });
22+
}
23+
}
24+
25+
const server = https.createServer({
26+
key: fixtures.readKey('agent1-key.pem'),
27+
cert: fixtures.readKey('agent1-cert.pem'),
28+
ca: fixtures.readKey('ca1-cert.pem'),
29+
ServerResponse: MyServerResponse
30+
}, common.mustCall(function(req, res) {
31+
res.status(200);
32+
res.end();
33+
}));
34+
server.listen();
35+
36+
server.on('listening', function makeRequest() {
37+
https.get({
38+
port: this.address().port,
39+
rejectUnauthorized: false
40+
}, (res) => {
41+
assert.strictEqual(res.statusCode, 200);
42+
res.on('end', () => {
43+
server.close();
44+
});
45+
res.resume();
46+
});
47+
});

0 commit comments

Comments
 (0)