From 852b99672515bc23d522c560bdcc9cdc72535620 Mon Sep 17 00:00:00 2001 From: Peter Marton Date: Thu, 5 Oct 2017 14:24:12 +0200 Subject: [PATCH] http2: add req and res options to server creation Add optional Http2ServerRequest and Http2ServerResponse options to createServer and createSecureServer. Allows custom req & res classes that extend the default ones to be used without overriding the prototype. Backport-PR-URL: https://github.com/nodejs/node/pull/20456 PR-URL: https://github.com/nodejs/node/pull/15560 Reviewed-By: James M Snell Reviewed-By: Matteo Collina Reviewed-By: Anatoli Papirovski Reviewed-By: Anna Henningsen --- doc/api/http2.md | 8 ++++ lib/internal/http2/compat.js | 8 ++-- lib/internal/http2/core.js | 10 ++++- .../test-http2-options-server-request.js | 40 +++++++++++++++++++ .../test-http2-options-server-response.js | 34 ++++++++++++++++ 5 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 test/parallel/test-http2-options-server-request.js create mode 100644 test/parallel/test-http2-options-server-response.js diff --git a/doc/api/http2.md b/doc/api/http2.md index f3322da4c2e4d5..040b9818745755 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -1757,6 +1757,14 @@ changes: * `Http1ServerResponse` {http.ServerResponse} Specifies the ServerResponse class to used for HTTP/1 fallback. Useful for extending the original `http.ServerResponse`. **Default:** `http.ServerResponse` + * `Http2ServerRequest` {http2.Http2ServerRequest} Specifies the + Http2ServerRequest class to use. + Useful for extending the original `Http2ServerRequest`. + **Default:** `Http2ServerRequest` + * `Http2ServerResponse` {htt2.Http2ServerResponse} Specifies the + Http2ServerResponse class to use. + Useful for extending the original `Http2ServerResponse`. + **Default:** `Http2ServerResponse` * `onRequestHandler` {Function} See [Compatibility API][] * Returns: {Http2Server} diff --git a/lib/internal/http2/compat.js b/lib/internal/http2/compat.js index b5dd81c80f4038..5e6c51377e94ba 100644 --- a/lib/internal/http2/compat.js +++ b/lib/internal/http2/compat.js @@ -661,11 +661,11 @@ class Http2ServerResponse extends Stream { } } -function onServerStream(stream, headers, flags, rawHeaders) { +function onServerStream(ServerRequest, ServerResponse, + stream, headers, flags, rawHeaders) { const server = this; - const request = new Http2ServerRequest(stream, headers, undefined, - rawHeaders); - const response = new Http2ServerResponse(stream); + const request = new ServerRequest(stream, headers, undefined, rawHeaders); + const response = new ServerResponse(stream); // Check for the CONNECT method const method = headers[HTTP2_HEADER_METHOD]; diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index 361f4eeb64981d..68bfbb043b0b63 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -2539,6 +2539,10 @@ function initializeOptions(options) { options.Http1ServerResponse = options.Http1ServerResponse || http.ServerResponse; + options.Http2ServerRequest = options.Http2ServerRequest || + Http2ServerRequest; + options.Http2ServerResponse = options.Http2ServerResponse || + Http2ServerResponse; return options; } @@ -2604,7 +2608,11 @@ class Http2Server extends NETServer { function setupCompat(ev) { if (ev === 'request') { this.removeListener('newListener', setupCompat); - this.on('stream', onServerStream); + this.on('stream', onServerStream.bind( + this, + this[kOptions].Http2ServerRequest, + this[kOptions].Http2ServerResponse) + ); } } diff --git a/test/parallel/test-http2-options-server-request.js b/test/parallel/test-http2-options-server-request.js new file mode 100644 index 00000000000000..2143d379823d51 --- /dev/null +++ b/test/parallel/test-http2-options-server-request.js @@ -0,0 +1,40 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const assert = require('assert'); +const h2 = require('http2'); + +class MyServerRequest extends h2.Http2ServerRequest { + getUserAgent() { + return this.headers['user-agent'] || 'unknown'; + } +} + +const server = h2.createServer({ + Http2ServerRequest: MyServerRequest +}, (req, res) => { + assert.strictEqual(req.getUserAgent(), 'node-test'); + + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.end(); +}); +server.listen(0); + +server.on('listening', common.mustCall(() => { + + const client = h2.connect(`http://localhost:${server.address().port}`); + const req = client.request({ + ':path': '/', + 'User-Agent': 'node-test' + }); + + req.on('response', common.mustCall()); + + req.resume(); + req.on('end', common.mustCall(() => { + server.close(); + client.destroy(); + })); +})); diff --git a/test/parallel/test-http2-options-server-response.js b/test/parallel/test-http2-options-server-response.js new file mode 100644 index 00000000000000..6f1ae1881d22d8 --- /dev/null +++ b/test/parallel/test-http2-options-server-response.js @@ -0,0 +1,34 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const h2 = require('http2'); + +class MyServerResponse extends h2.Http2ServerResponse { + status(code) { + return this.writeHead(code, { 'Content-Type': 'text/plain' }); + } +} + +const server = h2.createServer({ + Http2ServerResponse: MyServerResponse +}, (req, res) => { + res.status(200); + res.end(); +}); +server.listen(0); + +server.on('listening', common.mustCall(() => { + + const client = h2.connect(`http://localhost:${server.address().port}`); + const req = client.request({ ':path': '/' }); + + req.on('response', common.mustCall()); + + req.resume(); + req.on('end', common.mustCall(() => { + server.close(); + client.destroy(); + })); +}));