summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Marton <peter@risingstack.com>2017-10-19 20:16:02 +0200
committerRuben Bridgewater <ruben@bridgewater.de>2018-02-06 15:40:24 +0100
commita899576c977aef32d85074ac09d511e4590e28d7 (patch)
treeb065bf00d067a3816db31ce0ec88287be6d75afb
parent82a73470506111ecc6361b9e0b0bb01f6377a531 (diff)
downloadnode-new-a899576c977aef32d85074ac09d511e4590e28d7.tar.gz
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: https://github.com/nodejs/node/pull/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>
-rw-r--r--doc/api/http.md14
-rw-r--r--doc/api/https.md4
-rw-r--r--lib/_http_common.js10
-rw-r--r--lib/_http_server.js23
-rw-r--r--lib/https.js6
-rw-r--r--test/parallel/test-http-server-options-incoming-message.js41
-rw-r--r--test/parallel/test-http-server-options-server-response.js35
-rw-r--r--test/parallel/test-https-server-options-incoming-message.js51
-rw-r--r--test/parallel/test-https-server-options-server-response.js47
9 files changed, 222 insertions, 9 deletions
diff --git a/doc/api/http.md b/doc/api/http.md
index fadb5054e2..5659bb2eda 100644
--- a/doc/api/http.md
+++ b/doc/api/http.md
@@ -1663,10 +1663,20 @@ A collection of all the standard HTTP response status codes, and the
short description of each. For example, `http.STATUS_CODES[404] === 'Not
Found'`.
-## http.createServer([requestListener])
+## http.createServer([options][, requestListener])
<!-- YAML
added: v0.1.13
--->
+ - version: REPLACEME
+ pr-url: https://github.com/nodejs/node/pull/15752
+ description: The `options` argument is supported now.
+-->
+- `options` {Object}
+ * `IncomingMessage` {http.IncomingMessage} Specifies the IncomingMessage class
+ to be used. Useful for extending the original `IncomingMessage`. Defaults
+ to: `IncomingMessage`
+ * `ServerResponse` {http.ServerResponse} Specifies the ServerResponse class to
+ be used. Useful for extending the original `ServerResponse`. Defaults to:
+ `ServerResponse`
- `requestListener` {Function}
* Returns: {http.Server}
diff --git a/doc/api/https.md b/doc/api/https.md
index 1db1e8eb06..c1daf77dbf 100644
--- a/doc/api/https.md
+++ b/doc/api/https.md
@@ -65,7 +65,8 @@ See [`http.Server#keepAliveTimeout`][].
<!-- YAML
added: v0.3.4
-->
-- `options` {Object} Accepts `options` from [`tls.createServer()`][] and [`tls.createSecureContext()`][].
+- `options` {Object} Accepts `options` from [`tls.createServer()`][],
+ [`tls.createSecureContext()`][] and [`http.createServer()`][].
- `requestListener` {Function} A listener to be added to the `request` event.
Example:
@@ -256,6 +257,7 @@ const req = https.request(options, (res) => {
[`http.Server#setTimeout()`]: http.html#http_server_settimeout_msecs_callback
[`http.Server#timeout`]: http.html#http_server_timeout
[`http.Server`]: http.html#http_class_http_server
+[`http.createServer()`]: http.html#httpcreateserveroptions-requestlistener
[`http.close()`]: http.html#http_server_close_callback
[`http.get()`]: http.html#http_http_get_options_callback
[`http.request()`]: http.html#http_http_request_options_callback
diff --git a/lib/_http_common.js b/lib/_http_common.js
index b4caf5939e..a7e8b0c59b 100644
--- a/lib/_http_common.js
+++ b/lib/_http_common.js
@@ -34,6 +34,7 @@ const {
const debug = require('util').debuglog('http');
+const kIncomingMessage = Symbol('IncomingMessage');
const kOnHeaders = HTTPParser.kOnHeaders | 0;
const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;
const kOnBody = HTTPParser.kOnBody | 0;
@@ -73,7 +74,11 @@ function parserOnHeadersComplete(versionMajor, versionMinor, headers, method,
parser._url = '';
}
- parser.incoming = new IncomingMessage(parser.socket);
+ // Parser is also used by http client
+ var ParserIncomingMessage = parser.socket && parser.socket.server ?
+ parser.socket.server[kIncomingMessage] : IncomingMessage;
+
+ parser.incoming = new ParserIncomingMessage(parser.socket);
parser.incoming.httpVersionMajor = versionMajor;
parser.incoming.httpVersionMinor = versionMinor;
parser.incoming.httpVersion = `${versionMajor}.${versionMinor}`;
@@ -300,5 +305,6 @@ module.exports = {
freeParser,
httpSocketSetup,
methods,
- parsers
+ parsers,
+ kIncomingMessage
};
diff --git a/lib/_http_server.js b/lib/_http_server.js
index 496ebf285c..111a8525c4 100644
--- a/lib/_http_server.js
+++ b/lib/_http_server.js
@@ -33,6 +33,7 @@ const {
continueExpression,
chunkExpression,
httpSocketSetup,
+ kIncomingMessage,
_checkInvalidHeaderChar: checkInvalidHeaderChar
} = require('_http_common');
const { OutgoingMessage } = require('_http_outgoing');
@@ -41,9 +42,12 @@ const {
defaultTriggerAsyncIdScope,
getOrSetAsyncId
} = require('internal/async_hooks');
+const { IncomingMessage } = require('_http_incoming');
const errors = require('internal/errors');
const Buffer = require('buffer').Buffer;
+const kServerResponse = Symbol('ServerResponse');
+
const STATUS_CODES = {
100: 'Continue',
101: 'Switching Protocols',
@@ -263,9 +267,19 @@ function writeHead(statusCode, reason, obj) {
// Docs-only deprecated: DEP0063
ServerResponse.prototype.writeHeader = ServerResponse.prototype.writeHead;
+function Server(options, requestListener) {
+ if (!(this instanceof Server)) return new Server(options, requestListener);
+
+ if (typeof options === 'function') {
+ requestListener = options;
+ options = {};
+ } else if (options == null || typeof options === 'object') {
+ options = util._extend({}, options);
+ }
+
+ this[kIncomingMessage] = options.IncomingMessage || IncomingMessage;
+ this[kServerResponse] = options.ServerResponse || ServerResponse;
-function Server(requestListener) {
- if (!(this instanceof Server)) return new Server(requestListener);
net.Server.call(this, { allowHalfOpen: true });
if (requestListener) {
@@ -587,7 +601,7 @@ function parserOnIncoming(server, socket, state, req, keepAlive) {
}
}
- var res = new ServerResponse(req);
+ var res = new server[kServerResponse](req);
res._onPendingData = updateOutgoingData.bind(undefined, socket, state);
res.shouldKeepAlive = keepAlive;
@@ -690,5 +704,6 @@ module.exports = {
STATUS_CODES,
Server,
ServerResponse,
- _connectionListener: connectionListener
+ _connectionListener: connectionListener,
+ kServerResponse
};
diff --git a/lib/https.js b/lib/https.js
index 5013791fe2..741ce84d2f 100644
--- a/lib/https.js
+++ b/lib/https.js
@@ -36,6 +36,9 @@ const { inherits } = util;
const debug = util.debuglog('https');
const { urlToOptions, searchParamsSymbol } = require('internal/url');
const errors = require('internal/errors');
+const { IncomingMessage, ServerResponse } = require('http');
+const { kIncomingMessage } = require('_http_common');
+const { kServerResponse } = require('_http_server');
function Server(opts, requestListener) {
if (!(this instanceof Server)) return new Server(opts, requestListener);
@@ -57,6 +60,9 @@ function Server(opts, requestListener) {
opts.ALPNProtocols = ['http/1.1'];
}
+ this[kIncomingMessage] = opts.IncomingMessage || IncomingMessage;
+ this[kServerResponse] = opts.ServerResponse || ServerResponse;
+
tls.Server.call(this, opts, _connectionListener);
this.httpAllowHalfOpen = false;
diff --git a/test/parallel/test-http-server-options-incoming-message.js b/test/parallel/test-http-server-options-incoming-message.js
new file mode 100644
index 0000000000..a4bfa1b764
--- /dev/null
+++ b/test/parallel/test-http-server-options-incoming-message.js
@@ -0,0 +1,41 @@
+'use strict';
+
+/**
+ * This test covers http.Server({ IncomingMessage }) option:
+ * With IncomingMessage option the server should use
+ * the new class for creating req Object instead of the default
+ * http.IncomingMessage.
+ */
+const common = require('../common');
+const assert = require('assert');
+const http = require('http');
+
+class MyIncomingMessage extends http.IncomingMessage {
+ getUserAgent() {
+ return this.headers['user-agent'] || 'unknown';
+ }
+}
+
+const server = http.Server({
+ IncomingMessage: MyIncomingMessage
+}, common.mustCall(function(req, res) {
+ assert.strictEqual(req.getUserAgent(), 'node-test');
+ res.statusCode = 200;
+ res.end();
+}));
+server.listen();
+
+server.on('listening', function makeRequest() {
+ http.get({
+ port: this.address().port,
+ headers: {
+ 'User-Agent': 'node-test'
+ }
+ }, (res) => {
+ assert.strictEqual(res.statusCode, 200);
+ res.on('end', () => {
+ server.close();
+ });
+ res.resume();
+ });
+});
diff --git a/test/parallel/test-http-server-options-server-response.js b/test/parallel/test-http-server-options-server-response.js
new file mode 100644
index 0000000000..f5adf39bed
--- /dev/null
+++ b/test/parallel/test-http-server-options-server-response.js
@@ -0,0 +1,35 @@
+'use strict';
+
+/**
+ * This test covers http.Server({ ServerResponse }) option:
+ * With ServerResponse option the server should use
+ * the new class for creating res Object instead of the default
+ * http.ServerResponse.
+ */
+const common = require('../common');
+const assert = require('assert');
+const http = require('http');
+
+class MyServerResponse extends http.ServerResponse {
+ status(code) {
+ return this.writeHead(code, { 'Content-Type': 'text/plain' });
+ }
+}
+
+const server = http.Server({
+ ServerResponse: MyServerResponse
+}, common.mustCall(function(req, res) {
+ res.status(200);
+ res.end();
+}));
+server.listen();
+
+server.on('listening', function makeRequest() {
+ http.get({ port: this.address().port }, (res) => {
+ assert.strictEqual(res.statusCode, 200);
+ res.on('end', () => {
+ server.close();
+ });
+ res.resume();
+ });
+});
diff --git a/test/parallel/test-https-server-options-incoming-message.js b/test/parallel/test-https-server-options-incoming-message.js
new file mode 100644
index 0000000000..102ee56751
--- /dev/null
+++ b/test/parallel/test-https-server-options-incoming-message.js
@@ -0,0 +1,51 @@
+'use strict';
+
+/**
+ * This test covers http.Server({ IncomingMessage }) option:
+ * With IncomingMessage option the server should use
+ * the new class for creating req Object instead of the default
+ * http.IncomingMessage.
+ */
+const common = require('../common');
+const fixtures = require('../common/fixtures');
+
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const http = require('http');
+const https = require('https');
+
+class MyIncomingMessage extends http.IncomingMessage {
+ getUserAgent() {
+ return this.headers['user-agent'] || 'unknown';
+ }
+}
+
+const server = https.createServer({
+ key: fixtures.readKey('agent1-key.pem'),
+ cert: fixtures.readKey('agent1-cert.pem'),
+ ca: fixtures.readKey('ca1-cert.pem'),
+ IncomingMessage: MyIncomingMessage
+}, common.mustCall(function(req, res) {
+ assert.strictEqual(req.getUserAgent(), 'node-test');
+ res.statusCode = 200;
+ res.end();
+}));
+server.listen();
+
+server.on('listening', function makeRequest() {
+ https.get({
+ port: this.address().port,
+ rejectUnauthorized: false,
+ headers: {
+ 'User-Agent': 'node-test'
+ }
+ }, (res) => {
+ assert.strictEqual(res.statusCode, 200);
+ res.on('end', () => {
+ server.close();
+ });
+ res.resume();
+ });
+});
diff --git a/test/parallel/test-https-server-options-server-response.js b/test/parallel/test-https-server-options-server-response.js
new file mode 100644
index 0000000000..8745415f8b
--- /dev/null
+++ b/test/parallel/test-https-server-options-server-response.js
@@ -0,0 +1,47 @@
+'use strict';
+
+/**
+ * This test covers http.Server({ ServerResponse }) option:
+ * With ServerResponse option the server should use
+ * the new class for creating res Object instead of the default
+ * http.ServerResponse.
+ */
+const common = require('../common');
+const fixtures = require('../common/fixtures');
+
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+
+const assert = require('assert');
+const http = require('http');
+const https = require('https');
+
+class MyServerResponse extends http.ServerResponse {
+ status(code) {
+ return this.writeHead(code, { 'Content-Type': 'text/plain' });
+ }
+}
+
+const server = https.createServer({
+ key: fixtures.readKey('agent1-key.pem'),
+ cert: fixtures.readKey('agent1-cert.pem'),
+ ca: fixtures.readKey('ca1-cert.pem'),
+ ServerResponse: MyServerResponse
+}, common.mustCall(function(req, res) {
+ res.status(200);
+ res.end();
+}));
+server.listen();
+
+server.on('listening', function makeRequest() {
+ https.get({
+ port: this.address().port,
+ rejectUnauthorized: false
+ }, (res) => {
+ assert.strictEqual(res.statusCode, 200);
+ res.on('end', () => {
+ server.close();
+ });
+ res.resume();
+ });
+});