Skip to content

Commit 01dc646

Browse files
Peter Martonrvagg
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. Backport-PR-URL: #20456 PR-URL: #15752 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anatoli Papirovski <apapirovski@mac.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com>
1 parent 0cae3c3 commit 01dc646

9 files changed

Lines changed: 223 additions & 11 deletions

‎doc/api/http.md‎

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,10 +1663,21 @@ 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+
changes:
1670+
- version: REPLACEME
1671+
pr-url: https://github.com/nodejs/node/pull/15752
1672+
description: The `options` argument is supported now.
1673+
-->
1674+
-`options` {Object}
1675+
*`IncomingMessage` {http.IncomingMessage} Specifies the IncomingMessage class
1676+
to be used. Useful for extending the original `IncomingMessage`. Defaults
1677+
to: `IncomingMessage`
1678+
*`ServerResponse` {http.ServerResponse} Specifies the ServerResponse class to
1679+
be used. Useful for extending the original `ServerResponse`. Defaults to:
1680+
`ServerResponse`
16701681
-`requestListener` {Function}
16711682

16721683
* Returns: {http.Server}

‎doc/api/https.md‎

Lines changed: 3 additions & 1 deletion
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:
@@ -255,6 +256,7 @@ const req = https.request(options, (res) => {
255256
[`http.Server#setTimeout()`]: http.html#http_server_settimeout_msecs_callback
256257
[`http.Server#timeout`]: http.html#http_server_timeout
257258
[`http.Server`]: http.html#http_class_http_server
259+
[`http.createServer()`]: http.html#httpcreateserveroptions-requestlistener
258260
[`http.close()`]: http.html#http_server_close_callback
259261
[`http.get()`]: http.html#http_http_get_options_callback
260262
[`http.request()`]: http.html#http_http_request_options_callback

‎lib/_http_common.js‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const {
3434

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

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

76-
parser.incoming=newIncomingMessage(parser.socket);
77+
// Parser is also used by http client
78+
varParserIncomingMessage=parser.socket&&parser.socket.server ?
79+
parser.socket.server[kIncomingMessage] : IncomingMessage;
80+
81+
parser.incoming=newParserIncomingMessage(parser.socket);
7782
parser.incoming.httpVersionMajor=versionMajor;
7883
parser.incoming.httpVersionMinor=versionMinor;
7984
parser.incoming.httpVersion=`${versionMajor}.${versionMinor}`;
@@ -353,5 +358,6 @@ module.exports = {
353358
freeParser,
354359
httpSocketSetup,
355360
methods,
356-
parsers
361+
parsers,
362+
kIncomingMessage
357363
};

‎lib/_http_server.js‎

Lines changed: 19 additions & 4 deletions
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,6 +42,9 @@ const {
4142
defaultTriggerAsyncIdScope,
4243
getOrSetAsyncId
4344
}=require('internal/async_hooks');
45+
const{ IncomingMessage }=require('_http_incoming');
46+
47+
constkServerResponse=Symbol('ServerResponse');
4448

4549
constSTATUS_CODES={
4650
100: 'Continue',
@@ -260,9 +264,19 @@ function writeHead(statusCode, reason, obj) {
260264
// Docs-only deprecated: DEP0063
261265
ServerResponse.prototype.writeHeader=ServerResponse.prototype.writeHead;
262266

267+
functionServer(options,requestListener){
268+
if(!(thisinstanceofServer))returnnewServer(options,requestListener);
269+
270+
if(typeofoptions==='function'){
271+
requestListener=options;
272+
options={};
273+
}elseif(options==null||typeofoptions==='object'){
274+
options=util._extend({},options);
275+
}
276+
277+
this[kIncomingMessage]=options.IncomingMessage||IncomingMessage;
278+
this[kServerResponse]=options.ServerResponse||ServerResponse;
263279

264-
functionServer(requestListener){
265-
if(!(thisinstanceofServer))returnnewServer(requestListener);
266280
net.Server.call(this,{allowHalfOpen: true});
267281

268282
if(requestListener){
@@ -578,7 +592,7 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
578592
}
579593
}
580594

581-
varres=newServerResponse(req);
595+
varres=newserver[kServerResponse](req);
582596
res._onPendingData=updateOutgoingData.bind(undefined,socket,state);
583597

584598
res.shouldKeepAlive=keepAlive;
@@ -681,5 +695,6 @@ module.exports = {
681695
STATUS_CODES,
682696
Server,
683697
ServerResponse,
684-
_connectionListener: connectionListener
698+
_connectionListener: connectionListener,
699+
kServerResponse
685700
};

‎lib/https.js‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ const util = require('util');
3030
const{ inherits }=util;
3131
constdebug=util.debuglog('https');
3232
const{ urlToOptions, searchParamsSymbol }=require('internal/url');
33+
const{ IncomingMessage, ServerResponse }=require('http');
34+
const{ kIncomingMessage }=require('_http_common');
35+
const{ kServerResponse }=require('_http_server');
3336

3437
functionServer(opts,requestListener){
3538
if(!(thisinstanceofServer))returnnewServer(opts,requestListener);
@@ -51,9 +54,10 @@ function Server(opts, requestListener) {
5154
opts.ALPNProtocols=['http/1.1'];
5255
}
5356

54-
tls.Server.call(this,opts,http._connectionListener);
57+
this[kIncomingMessage]=opts.IncomingMessage||IncomingMessage;
58+
this[kServerResponse]=opts.ServerResponse||ServerResponse;
5559

56-
this.httpAllowHalfOpen=false;
60+
tls.Server.call(this,opts,http._connectionListener);
5761

5862
if(requestListener){
5963
this.addListener('request',requestListener);
Lines changed: 41 additions & 0 deletions
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+
constcommon=require('../common');
10+
constassert=require('assert');
11+
consthttp=require('http');
12+
13+
classMyIncomingMessageextendshttp.IncomingMessage{
14+
getUserAgent(){
15+
returnthis.headers['user-agent']||'unknown';
16+
}
17+
}
18+
19+
constserver=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',functionmakeRequest(){
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+
});
Lines changed: 35 additions & 0 deletions
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+
constcommon=require('../common');
10+
constassert=require('assert');
11+
consthttp=require('http');
12+
13+
classMyServerResponseextendshttp.ServerResponse{
14+
status(code){
15+
returnthis.writeHead(code,{'Content-Type': 'text/plain'});
16+
}
17+
}
18+
19+
constserver=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',functionmakeRequest(){
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+
});
Lines changed: 51 additions & 0 deletions
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+
constcommon=require('../common');
10+
constfixtures=require('../common/fixtures');
11+
12+
if(!common.hasCrypto)
13+
common.skip('missing crypto');
14+
15+
constassert=require('assert');
16+
consthttp=require('http');
17+
consthttps=require('https');
18+
19+
classMyIncomingMessageextendshttp.IncomingMessage{
20+
getUserAgent(){
21+
returnthis.headers['user-agent']||'unknown';
22+
}
23+
}
24+
25+
constserver=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',functionmakeRequest(){
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+
});
Lines changed: 47 additions & 0 deletions
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+
constcommon=require('../common');
10+
constfixtures=require('../common/fixtures');
11+
12+
if(!common.hasCrypto)
13+
common.skip('missing crypto');
14+
15+
constassert=require('assert');
16+
consthttp=require('http');
17+
consthttps=require('https');
18+
19+
classMyServerResponseextendshttp.ServerResponse{
20+
status(code){
21+
returnthis.writeHead(code,{'Content-Type': 'text/plain'});
22+
}
23+
}
24+
25+
constserver=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',functionmakeRequest(){
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)