From 0029369c74008b9edba5b67396778d58d21e2c6a Mon Sep 17 00:00:00 2001 From: Qingyu Deng Date: Thu, 10 Jun 2021 22:14:46 +0800 Subject: [PATCH] https: add `maxHeaderSize` option for https server Fixes: https://github.com/nodejs/node/issues/38954 Refs: https://github.com/nodejs/node/pull/30570 --- lib/https.js | 7 ++ test/parallel/test-https-max-header-size.js | 123 ++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 test/parallel/test-https-max-header-size.js diff --git a/lib/https.js b/lib/https.js index 765e1a22b60696..408569b78559c3 100644 --- a/lib/https.js +++ b/lib/https.js @@ -50,6 +50,7 @@ let debug = require('internal/util/debuglog').debuglog('https', (fn) => { const { URL, urlToHttpOptions, searchParamsSymbol } = require('internal/url'); const { IncomingMessage, ServerResponse } = require('http'); const { kIncomingMessage } = require('_http_common'); +const { validateInteger } = require('internal/validators'); function Server(opts, requestListener) { if (!(this instanceof Server)) return new Server(opts, requestListener); @@ -67,6 +68,12 @@ function Server(opts, requestListener) { opts.ALPNProtocols = ['http/1.1']; } + this.maxHeaderSize = 0; + if (opts.maxHeaderSize !== undefined) { + validateInteger(opts.maxHeaderSize, 'maxHeaderSize', 0); + this.maxHeaderSize = opts.maxHeaderSize; + } + this[kIncomingMessage] = opts.IncomingMessage || IncomingMessage; this[kServerResponse] = opts.ServerResponse || ServerResponse; diff --git a/test/parallel/test-https-max-header-size.js b/test/parallel/test-https-max-header-size.js new file mode 100644 index 00000000000000..50e68dd8b805a1 --- /dev/null +++ b/test/parallel/test-https-max-header-size.js @@ -0,0 +1,123 @@ +'use strict'; + +const common = require('../common'); + +if (!common.hasCrypto) { + common.skip('missing crypto'); +} + +const assert = require('assert'); +const https = require('https'); +const fixtures = require('../common/fixtures'); + + +const options = { + key: fixtures.readKey('agent1-key.pem'), + cert: fixtures.readKey('agent1-cert.pem') +}; + +const maxHeaderSize = 8192; + +const body = 'hello world\n'; +const serverCallback = (req, res) => { + res.writeHead(200, { 'content-type': 'text/plain' }); + res.end(body); +}; + +const commonReqOptions = { + hostname: '127.0.0.1', + path: '/', + method: 'GET', + rejectUnauthorized: false, +}; + +// Test when header size is larger than maxHeaderSize +{ + const server = https.createServer({ + ...options, + maxHeaderSize + }, serverCallback); + + server.listen(0, common.mustCall(() => { + const serverPort = server.address().port; + const reqOptions = { + ...commonReqOptions, + port: serverPort, + headers: { + 'h': 'a'.repeat(maxHeaderSize + 1) + } + }; + + https + .request(reqOptions, common.mustCall((res) => { + assert.strictEqual(res.statusCode, 431); + + res.on('data', () => {}); + + res.on('end', common.mustCall(() => { + server.close(); + })); + })) + .end(); + })); +} + +// Test when header size is within the range +{ + const server = https.createServer({ + ...options, + maxHeaderSize + }, serverCallback); + + server.listen(0, common.mustCall(() => { + const serverPort = server.address().port; + const reqOptions = { + ...commonReqOptions, + port: serverPort, + headers: { + // Some other header overhead + 'h': 'a'.repeat(maxHeaderSize - 200) + } + }; + + https + .request(reqOptions, common.mustCall((res) => { + assert.strictEqual(res.statusCode, 200); + + res.on('data', () => {}); + + res.on('end', common.mustCall(() => { + server.close(); + })); + })) + .end(); + })); +} + + +// Test parameter validation +{ + assert.throws(common.mustCall(() => { + https.createServer({ + ...options, + maxHeaderSize: -1 + }, serverCallback); + }), { + message: 'The value of "maxHeaderSize" is out of range. ' + + 'It must be >= 0 && <= 9007199254740991. Received -1', + code: 'ERR_OUT_OF_RANGE', + name: 'RangeError' + }); + + assert.throws(common.mustCall(() => { + https.createServer({ + ...options, + maxHeaderSize: '' + }, serverCallback); + }), { + message: 'The "maxHeaderSize" argument must be of type number. ' + + 'Received type string (\'\')', + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError' + }); +}