+ add maxHeaderSize property (max_header_size.patch) (CVE-2018-12121.patch - CVE-2018-12121, bsc#1117626) + A timeout of 40 seconds now applies to servers receiving HTTP headers. This value can be adjusted with server.headersTimeout. Where headers are not completely received within this period, the socket is destroyed on the next received chunk. In conjunction with server.setTimeout(), this aids in protecting against excessive resource retention and possible Denial of Service. (CVE-2018-12122.patch - CVE-2018-12122, bsc#1117627) (CVE-2018-12116.patch - CVE-2018-12116, bsc#1117630) (CVE-2018-12123.patch - CVE-2018-12123, bnc#1117629) OBS-URL: https://build.opensuse.org/package/show/devel:languages:nodejs/nodejs4?expand=0&rev=101
699 lines
23 KiB
Diff
699 lines
23 KiB
Diff
Ported from:
|
|
|
|
From 59f83d689641d5030743ee4f3e453e754843e188 Mon Sep 17 00:00:00 2001
|
|
From: cjihrig <cjihrig@gmail.com>
|
|
Date: Thu, 29 Nov 2018 17:29:53 -0500
|
|
Subject: [PATCH] deps: cherry-pick http_parser_set_max_header_size
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
This commit adds http_parser_set_max_header_size() to the
|
|
http-parser for overriding the compile time maximum HTTP
|
|
header size.
|
|
|
|
Backport-PR-URL: https://github.com/nodejs/node/pull/25173
|
|
PR-URL: https://github.com/nodejs/node/pull/24811
|
|
Fixes: https://github.com/nodejs/node/issues/24692
|
|
Refs: https://github.com/nodejs/http-parser/pull/453
|
|
Reviewed-By: Anna Henningsen <anna@addaleax.net>
|
|
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
|
|
Reviewed-By: Myles Borins <myles.borins@gmail.com>
|
|
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
|
|
Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com>
|
|
Reviewed-By: James M Snell <jasnell@gmail.com>
|
|
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
|
|
|
|
|
|
|
|
From c0c4de71f0fb7b55804a9d2110dded0493fc7c3e Mon Sep 17 00:00:00 2001
|
|
From: cjihrig <cjihrig@gmail.com>
|
|
Date: Wed, 5 Dec 2018 19:59:12 -0500
|
|
Subject: [PATCH] http: add maxHeaderSize property
|
|
|
|
This commit exposes the value of --max-http-header-size
|
|
as a property of the http module.
|
|
|
|
Backport-PR-URL: https://github.com/nodejs/node/pull/25218
|
|
PR-URL: https://github.com/nodejs/node/pull/24860
|
|
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
|
|
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
|
|
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
|
|
Reviewed-By: Shelley Vohr <codebytere@gmail.com>
|
|
Reviewed-By: James M Snell <jasnell@gmail.com>
|
|
|
|
|
|
From f233b160c9b8d5126b4e4845d1661c718d14d39f Mon Sep 17 00:00:00 2001
|
|
From: cjihrig <cjihrig@gmail.com>
|
|
Date: Mon, 3 Dec 2018 12:27:46 -0500
|
|
Subject: [PATCH] cli: add --max-http-header-size flag
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Allow the maximum size of HTTP headers to be overridden from
|
|
the command line.
|
|
|
|
Backport-PR-URL: https://github.com/nodejs/node/pull/25173
|
|
co-authored-by: Matteo Collina <hello@matteocollina.com>
|
|
PR-URL: https://github.com/nodejs/node/pull/24811
|
|
Fixes: https://github.com/nodejs/node/issues/24692
|
|
Reviewed-By: Anna Henningsen <anna@addaleax.net>
|
|
Reviewed-By: Myles Borins <myles.borins@gmail.com>
|
|
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
|
|
Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com>
|
|
Reviewed-By: James M Snell <jasnell@gmail.com>
|
|
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
|
|
|
|
|
|
|
|
From 8a3e0c069747cb6a7e1889de92304856224fee72 Mon Sep 17 00:00:00 2001
|
|
From: Matteo Collina <hello@matteocollina.com>
|
|
Date: Fri, 14 Dec 2018 12:30:01 +0100
|
|
Subject: [PATCH] http: fix regression of binary upgrade response body
|
|
|
|
See: https://github.com/nodejs/node/issues/24958
|
|
|
|
PR-URL: https://github.com/nodejs/node/pull/25036
|
|
Reviewed-By: Myles Borins <myles.borins@gmail.com>
|
|
|
|
Index: node-v4.9.1/deps/http_parser/http_parser.c
|
|
===================================================================
|
|
--- node-v4.9.1.orig/deps/http_parser/http_parser.c
|
|
+++ node-v4.9.1/deps/http_parser/http_parser.c
|
|
@@ -25,6 +25,8 @@
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
|
|
+static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE;
|
|
+
|
|
#ifndef ULLONG_MAX
|
|
# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
|
|
#endif
|
|
@@ -137,20 +139,20 @@ do {
|
|
} while (0)
|
|
|
|
/* Don't allow the total size of the HTTP headers (including the status
|
|
- * line) to exceed HTTP_MAX_HEADER_SIZE. This check is here to protect
|
|
+ * line) to exceed max_header_size. This check is here to protect
|
|
* embedders against denial-of-service attacks where the attacker feeds
|
|
* us a never-ending header that the embedder keeps buffering.
|
|
*
|
|
* This check is arguably the responsibility of embedders but we're doing
|
|
* it on the embedder's behalf because most won't bother and this way we
|
|
- * make the web a little safer. HTTP_MAX_HEADER_SIZE is still far bigger
|
|
+ * make the web a little safer. max_header_size is still far bigger
|
|
* than any reasonable request or response so this should never affect
|
|
* day-to-day operation.
|
|
*/
|
|
#define COUNT_HEADER_SIZE(V) \
|
|
do { \
|
|
parser->nread += (V); \
|
|
- if (UNLIKELY(parser->nread > (HTTP_MAX_HEADER_SIZE))) { \
|
|
+ if (UNLIKELY(parser->nread > max_header_size)) { \
|
|
SET_ERRNO(HPE_HEADER_OVERFLOW); \
|
|
goto error; \
|
|
} \
|
|
@@ -1471,7 +1473,7 @@ reexecute:
|
|
const char* p_lf;
|
|
size_t limit = data + len - p;
|
|
|
|
- limit = MIN(limit, HTTP_MAX_HEADER_SIZE);
|
|
+ limit = MIN(limit, max_header_size);
|
|
|
|
p_cr = (const char*) memchr(p, CR, limit);
|
|
p_lf = (const char*) memchr(p, LF, limit);
|
|
@@ -2438,3 +2440,8 @@ http_parser_version(void) {
|
|
HTTP_PARSER_VERSION_MINOR * 0x00100 |
|
|
HTTP_PARSER_VERSION_PATCH * 0x00001;
|
|
}
|
|
+
|
|
+void
|
|
+http_parser_set_max_header_size(uint32_t size) {
|
|
+ max_header_size = size;
|
|
+}
|
|
Index: node-v4.9.1/deps/http_parser/http_parser.h
|
|
===================================================================
|
|
--- node-v4.9.1.orig/deps/http_parser/http_parser.h
|
|
+++ node-v4.9.1/deps/http_parser/http_parser.h
|
|
@@ -427,6 +427,9 @@ void http_parser_pause(http_parser *pars
|
|
/* Checks if this is the final chunk of the body. */
|
|
int http_body_is_final(const http_parser *parser);
|
|
|
|
+/* Change the maximum header size provided at compile time. */
|
|
+void http_parser_set_max_header_size(uint32_t size);
|
|
+
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
Index: node-v4.9.1/doc/api/http.md
|
|
===================================================================
|
|
--- node-v4.9.1.orig/doc/api/http.md
|
|
+++ node-v4.9.1/doc/api/http.md
|
|
@@ -1330,6 +1330,16 @@ added: v0.5.9
|
|
Global instance of Agent which is used as the default for all http client
|
|
requests.
|
|
|
|
+## http.maxHeaderSize
|
|
+<!-- YAML
|
|
+added: REPLACEME
|
|
+-->
|
|
+
|
|
+* {number}
|
|
+
|
|
+Read-only property specifying the maximum allowed size of HTTP headers in bytes.
|
|
+Defaults to 8KB. Configurable using the [`--max-http-header-size`][] CLI option.
|
|
+
|
|
## http.request(options[, callback])
|
|
<!-- YAML
|
|
added: v0.3.6
|
|
@@ -1439,6 +1449,7 @@ There are a few special headers that sho
|
|
* Sending an Authorization header will override using the `auth` option
|
|
to compute basic authentication.
|
|
|
|
+[`--max-http-header-size`]: cli.html#cli_max_http_header_size_size
|
|
[`'checkContinue'`]: #http_event_checkcontinue
|
|
[`'listening'`]: net.html#net_event_listening
|
|
[`'response'`]: #http_event_response
|
|
Index: node-v4.9.1/lib/http.js
|
|
===================================================================
|
|
--- node-v4.9.1.orig/lib/http.js
|
|
+++ node-v4.9.1/lib/http.js
|
|
@@ -19,6 +19,8 @@ const server = require('_http_server');
|
|
exports.ServerResponse = server.ServerResponse;
|
|
exports.STATUS_CODES = server.STATUS_CODES;
|
|
|
|
+let maxHeaderSize;
|
|
+
|
|
|
|
const agent = require('_http_agent');
|
|
const Agent = exports.Agent = agent.Agent;
|
|
@@ -92,8 +94,21 @@ Client.prototype.request = function(meth
|
|
return c;
|
|
};
|
|
|
|
+
|
|
exports.Client = internalUtil.deprecate(Client, 'http.Client is deprecated.');
|
|
|
|
exports.createClient = internalUtil.deprecate(function(port, host) {
|
|
return new Client(port, host);
|
|
}, 'http.createClient is deprecated. Use http.request instead.');
|
|
+
|
|
+Object.defineProperty(module.exports, 'maxHeaderSize', {
|
|
+ configurable: true,
|
|
+ enumerable: true,
|
|
+ get() {
|
|
+ if (maxHeaderSize === undefined) {
|
|
+ maxHeaderSize = process.binding('config').maxHTTPHeaderSize;
|
|
+ }
|
|
+
|
|
+ return maxHeaderSize;
|
|
+ }
|
|
+});
|
|
Index: node-v4.9.1/test/parallel/test-http-max-header-size.js
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ node-v4.9.1/test/parallel/test-http-max-header-size.js
|
|
@@ -0,0 +1,11 @@
|
|
+'use strict';
|
|
+
|
|
+require('../common');
|
|
+const assert = require('assert');
|
|
+const spawnSync = require('child_process').spawnSync;
|
|
+const http = require('http');
|
|
+
|
|
+assert.strictEqual(http.maxHeaderSize, 8 * 1024);
|
|
+const child = spawnSync(process.execPath, ['--max-http-header-size=10', '-p',
|
|
+ 'require("http").maxHeaderSize']);
|
|
+assert.strictEqual(+child.stdout.toString().trim(), 10);
|
|
Index: node-v4.9.1/doc/api/cli.md
|
|
===================================================================
|
|
--- node-v4.9.1.orig/doc/api/cli.md
|
|
+++ node-v4.9.1/doc/api/cli.md
|
|
@@ -177,6 +177,12 @@ added: v0.11.15
|
|
|
|
Specify ICU data load path. (overrides `NODE_ICU_DATA`)
|
|
|
|
+### `--max-http-header-size=size`
|
|
+<!-- YAML
|
|
+added: REPLACEME
|
|
+-->
|
|
+
|
|
+Specify the maximum size, in bytes, of HTTP headers. Defaults to 8KB.
|
|
|
|
## Environment Variables
|
|
|
|
Index: node-v4.9.1/doc/node.1
|
|
===================================================================
|
|
--- node-v4.9.1.orig/doc/node.1
|
|
+++ node-v4.9.1/doc/node.1
|
|
@@ -92,6 +92,10 @@ Preload the specified module at startup.
|
|
rules. \fImodule\fR may be either a path to a file, or a node module name.
|
|
|
|
.TP
|
|
+.BR \-\-max\-http\-header-size \fI=size\fR
|
|
+Specify the maximum size of HTTP headers in bytes. Defaults to 8KB.
|
|
+
|
|
+.TP
|
|
.BR \-\-no\-deprecation
|
|
Silence deprecation warnings.
|
|
|
|
Index: node-v4.9.1/src/node_config.cc
|
|
===================================================================
|
|
--- node-v4.9.1.orig/src/node_config.cc
|
|
+++ node-v4.9.1/src/node_config.cc
|
|
@@ -9,6 +9,7 @@ namespace node {
|
|
|
|
using v8::Context;
|
|
using v8::Local;
|
|
+using v8::Number;
|
|
using v8::Object;
|
|
using v8::Value;
|
|
using v8::ReadOnly;
|
|
@@ -25,13 +26,25 @@ using v8::ReadOnly;
|
|
True(env->isolate()), ReadOnly).FromJust(); \
|
|
} while (0)
|
|
|
|
+#define READONLY_PROPERTY(obj, name, value) \
|
|
+ do { \
|
|
+ obj->DefineOwnProperty(env->context(), \
|
|
+ FIXED_ONE_BYTE_STRING(env->isolate(), name), \
|
|
+ value, ReadOnly).FromJust(); \
|
|
+ } while (0)
|
|
+
|
|
void InitConfig(Local<Object> target,
|
|
Local<Value> unused,
|
|
Local<Context> context) {
|
|
-#ifdef NODE_FIPS_MODE
|
|
Environment* env = Environment::GetCurrent(context);
|
|
+#ifdef NODE_FIPS_MODE
|
|
READONLY_BOOLEAN_PROPERTY("fipsMode");
|
|
#endif
|
|
+
|
|
+ READONLY_PROPERTY(target,
|
|
+ "maxHTTPHeaderSize",
|
|
+ Number::New(env->isolate(), max_http_header_size));
|
|
+
|
|
}
|
|
|
|
} // namespace node
|
|
Index: node-v4.9.1/src/node_http_parser.cc
|
|
===================================================================
|
|
--- node-v4.9.1.orig/src/node_http_parser.cc
|
|
+++ node-v4.9.1/src/node_http_parser.cc
|
|
@@ -611,8 +611,6 @@ class Parser : public AsyncWrap {
|
|
size_t nparsed =
|
|
http_parser_execute(&parser_, &settings, data, len);
|
|
|
|
- enum http_errno err = HTTP_PARSER_ERRNO(&parser_);
|
|
-
|
|
Save();
|
|
|
|
// Unassign the 'buffer_' variable
|
|
@@ -627,7 +625,9 @@ class Parser : public AsyncWrap {
|
|
Local<Integer> nparsed_obj = Integer::New(env()->isolate(), nparsed);
|
|
// If there was a parse error in one of the callbacks
|
|
// TODO(bnoordhuis) What if there is an error on EOF?
|
|
- if ((!parser_.upgrade && nparsed != len) || err != HPE_OK) {
|
|
+ if (!parser_.upgrade && nparsed != len) {
|
|
+ enum http_errno err = HTTP_PARSER_ERRNO(&parser_);
|
|
+
|
|
Local<Value> e = Exception::Error(env()->parse_error_string());
|
|
Local<Object> obj = e->ToObject(env()->isolate());
|
|
obj->Set(env()->bytes_parsed_string(), nparsed_obj);
|
|
@@ -723,6 +723,9 @@ const struct http_parser_settings Parser
|
|
nullptr // on_chunk_complete
|
|
};
|
|
|
|
+void InitMaxHttpHeaderSizeOnce() {
|
|
+ http_parser_set_max_header_size(max_http_header_size);
|
|
+}
|
|
|
|
void InitHttpParser(Local<Object> target,
|
|
Local<Value> unused,
|
|
@@ -767,6 +770,8 @@ void InitHttpParser(Local<Object> target
|
|
|
|
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"),
|
|
t->GetFunction());
|
|
+ static uv_once_t init_once = UV_ONCE_INIT;
|
|
+ uv_once(&init_once, InitMaxHttpHeaderSizeOnce);
|
|
}
|
|
|
|
} // namespace node
|
|
Index: node-v4.9.1/test/sequential/test-http-max-http-headers.js
|
|
===================================================================
|
|
--- node-v4.9.1.orig/test/sequential/test-http-max-http-headers.js
|
|
+++ node-v4.9.1/test/sequential/test-http-max-http-headers.js
|
|
@@ -1,10 +1,17 @@
|
|
'use strict';
|
|
+// Flags: --expose_internals
|
|
|
|
const assert = require('assert');
|
|
const common = require('../common');
|
|
const http = require('http');
|
|
const net = require('net');
|
|
-const MAX = 8 * 1024; // 8KB
|
|
+const MAX = +(process.argv[2] || 8 * 1024); // Command line option, or 8KB.
|
|
+
|
|
+assert(process.binding('config').maxHTTPHeaderSize,
|
|
+ 'The option should exist on process.binding(\'config\')');
|
|
+
|
|
+console.log('pid is', process.pid);
|
|
+console.log('max header size is', process.binding('config').maxHTTPHeaderSize);
|
|
|
|
// Verify that we cannot receive more than 8KB of headers.
|
|
|
|
@@ -28,19 +35,15 @@ function fillHeaders(headers, currentSiz
|
|
headers += 'a'.repeat(MAX - headers.length - 3);
|
|
// Generate valid headers
|
|
if (valid) {
|
|
- // TODO(mcollina): understand why -9 is needed instead of -1
|
|
- headers = headers.slice(0, -9);
|
|
+ // TODO(mcollina): understand why -32 is needed instead of -1
|
|
+ headers = headers.slice(0, -32);
|
|
}
|
|
return headers + '\r\n\r\n';
|
|
}
|
|
|
|
-const timeout = common.platformTimeout(10);
|
|
-
|
|
function writeHeaders(socket, headers) {
|
|
const array = [];
|
|
-
|
|
- // this is off from 1024 so that \r\n does not get split
|
|
- const chunkSize = 1000;
|
|
+ const chunkSize = 100;
|
|
let last = 0;
|
|
|
|
for (let i = 0; i < headers.length / chunkSize; i++) {
|
|
@@ -55,19 +58,25 @@ function writeHeaders(socket, headers) {
|
|
next();
|
|
|
|
function next() {
|
|
- if (socket.write(array.shift())) {
|
|
- if (array.length === 0) {
|
|
- socket.end();
|
|
- } else {
|
|
- setTimeout(next, timeout);
|
|
- }
|
|
+ if (socket.destroyed) {
|
|
+ console.log('socket was destroyed early, data left to write:',
|
|
+ array.join('').length);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ const chunk = array.shift();
|
|
+
|
|
+ if (chunk) {
|
|
+ console.log('writing chunk of size', chunk.length);
|
|
+ socket.write(chunk, next);
|
|
} else {
|
|
- socket.once('drain', next);
|
|
+ socket.end();
|
|
}
|
|
}
|
|
}
|
|
|
|
function test1() {
|
|
+ console.log('test1');
|
|
let headers =
|
|
'HTTP/1.1 200 OK\r\n' +
|
|
'Content-Length: 0\r\n' +
|
|
@@ -82,6 +91,9 @@ function test1() {
|
|
writeHeaders(sock, headers);
|
|
sock.resume();
|
|
});
|
|
+
|
|
+ // The socket might error but that's ok
|
|
+ sock.on('error', () => {});
|
|
});
|
|
|
|
server.listen(0, common.mustCall(() => {
|
|
@@ -90,17 +102,17 @@ function test1() {
|
|
|
|
client.on('error', common.mustCall((err) => {
|
|
assert.strictEqual(err.code, 'HPE_HEADER_OVERFLOW');
|
|
- server.close();
|
|
- setImmediate(test2);
|
|
+ server.close(test2);
|
|
}));
|
|
}));
|
|
}
|
|
|
|
const test2 = common.mustCall(() => {
|
|
+ console.log('test2');
|
|
let headers =
|
|
'GET / HTTP/1.1\r\n' +
|
|
'Host: localhost\r\n' +
|
|
- 'Agent: node\r\n' +
|
|
+ 'Agent: nod2\r\n' +
|
|
'X-CRASH: ';
|
|
|
|
// /, Host, localhost, Agent, node, X-CRASH, a...
|
|
@@ -109,7 +121,7 @@ const test2 = common.mustCall(() => {
|
|
|
|
const server = http.createServer(common.mustNotCall());
|
|
|
|
- server.on('clientError', common.mustCall((err) => {
|
|
+ server.once('clientError', common.mustCall((err) => {
|
|
assert.strictEqual(err.code, 'HPE_HEADER_OVERFLOW');
|
|
}));
|
|
|
|
@@ -121,34 +133,46 @@ const test2 = common.mustCall(() => {
|
|
});
|
|
|
|
finished(client, common.mustCall((err) => {
|
|
- server.close();
|
|
- setImmediate(test3);
|
|
+ server.close(test3);
|
|
}));
|
|
}));
|
|
});
|
|
|
|
const test3 = common.mustCall(() => {
|
|
+ console.log('test3');
|
|
let headers =
|
|
'GET / HTTP/1.1\r\n' +
|
|
'Host: localhost\r\n' +
|
|
- 'Agent: node\r\n' +
|
|
+ 'Agent: nod3\r\n' +
|
|
'X-CRASH: ';
|
|
|
|
// /, Host, localhost, Agent, node, X-CRASH, a...
|
|
const currentSize = 1 + 4 + 9 + 5 + 4 + 7;
|
|
headers = fillHeaders(headers, currentSize, true);
|
|
|
|
+ console.log('writing', headers.length);
|
|
+
|
|
const server = http.createServer(common.mustCall((req, res) => {
|
|
- res.end('hello world');
|
|
- setImmediate(server.close.bind(server));
|
|
+ res.end('hello from test3 server');
|
|
+ server.close();
|
|
}));
|
|
|
|
+ server.on('clientError', (err) => {
|
|
+ console.log(err.code);
|
|
+ if (err.code === 'HPE_HEADER_OVERFLOW') {
|
|
+ console.log(err.rawPacket.toString('hex'));
|
|
+ }
|
|
+ });
|
|
+ server.on('clientError', common.mustNotCall());
|
|
+
|
|
server.listen(0, common.mustCall(() => {
|
|
const client = net.connect(server.address().port);
|
|
client.on('connect', () => {
|
|
writeHeaders(client, headers);
|
|
client.resume();
|
|
});
|
|
+
|
|
+ client.pipe(process.stdout);
|
|
}));
|
|
});
|
|
|
|
Index: node-v4.9.1/test/sequential/test-set-http-max-http-headers.js
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ node-v4.9.1/test/sequential/test-set-http-max-http-headers.js
|
|
@@ -0,0 +1,104 @@
|
|
+'use strict';
|
|
+
|
|
+const common = require('../common');
|
|
+const assert = require('assert');
|
|
+const spawn = require('child_process').spawn;
|
|
+const path = require('path');
|
|
+const testName = path.join(__dirname, 'test-http-max-http-headers.js');
|
|
+
|
|
+const timeout = common.platformTimeout(100);
|
|
+
|
|
+const tests = [];
|
|
+
|
|
+function test(fn) {
|
|
+ tests.push(fn);
|
|
+}
|
|
+
|
|
+test(function(cb) {
|
|
+ console.log('running subtest expecting failure');
|
|
+
|
|
+ // Validate that the test fails if the max header size is too small.
|
|
+ const args = ['--expose-internals',
|
|
+ '--max-http-header-size=1024',
|
|
+ testName];
|
|
+ const cp = spawn(process.execPath, args, { stdio: 'inherit' });
|
|
+
|
|
+ cp.on('close', common.mustCall((code, signal) => {
|
|
+ assert.strictEqual(code, 1);
|
|
+ assert.strictEqual(signal, null);
|
|
+ cb();
|
|
+ }));
|
|
+});
|
|
+
|
|
+test(function(cb) {
|
|
+ console.log('running subtest expecting success');
|
|
+
|
|
+ const env = Object.assign({}, process.env, {
|
|
+ NODE_DEBUG: 'http'
|
|
+ });
|
|
+
|
|
+ // Validate that the test fails if the max header size is too small.
|
|
+ // Validate that the test now passes if the same limit becomes large enough.
|
|
+ const args = ['--expose-internals',
|
|
+ '--max-http-header-size=1024',
|
|
+ testName,
|
|
+ '1024'];
|
|
+ const cp = spawn(process.execPath, args, {
|
|
+ env,
|
|
+ stdio: 'inherit'
|
|
+ });
|
|
+
|
|
+ cp.on('close', common.mustCall((code, signal) => {
|
|
+ assert.strictEqual(code, 0);
|
|
+ assert.strictEqual(signal, null);
|
|
+ cb();
|
|
+ }));
|
|
+});
|
|
+
|
|
+// Next, repeat the same checks using NODE_OPTIONS if it is supported.
|
|
+if (process.config.variables.node_without_node_options) {
|
|
+ const env = Object.assign({}, process.env, {
|
|
+ NODE_OPTIONS: '--max-http-header-size=1024'
|
|
+ });
|
|
+
|
|
+ test(function(cb) {
|
|
+ console.log('running subtest expecting failure');
|
|
+
|
|
+ // Validate that the test fails if the max header size is too small.
|
|
+ const args = ['--expose-internals', testName];
|
|
+ const cp = spawn(process.execPath, args, { env, stdio: 'inherit' });
|
|
+
|
|
+ cp.on('close', common.mustCall((code, signal) => {
|
|
+ assert.strictEqual(code, 1);
|
|
+ assert.strictEqual(signal, null);
|
|
+ cb();
|
|
+ }));
|
|
+ });
|
|
+
|
|
+ test(function(cb) {
|
|
+ // Validate that the test now passes if the same limit
|
|
+ // becomes large enough.
|
|
+ const args = ['--expose-internals', testName, '1024'];
|
|
+ const cp = spawn(process.execPath, args, { env, stdio: 'inherit' });
|
|
+
|
|
+ cp.on('close', common.mustCall((code, signal) => {
|
|
+ assert.strictEqual(code, 0);
|
|
+ assert.strictEqual(signal, null);
|
|
+ cb();
|
|
+ }));
|
|
+ });
|
|
+}
|
|
+
|
|
+function runTest() {
|
|
+ const fn = tests.shift();
|
|
+
|
|
+ if (!fn) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ fn(() => {
|
|
+ setTimeout(runTest, timeout);
|
|
+ });
|
|
+}
|
|
+
|
|
+runTest();
|
|
Index: node-v4.9.1/src/node_internals.h
|
|
===================================================================
|
|
--- node-v4.9.1.orig/src/node_internals.h
|
|
+++ node-v4.9.1/src/node_internals.h
|
|
@@ -30,6 +30,9 @@ struct sockaddr;
|
|
|
|
namespace node {
|
|
|
|
+// Set in node.cc by ParseArgs when --max-http-header-size is used
|
|
+extern uint64_t max_http_header_size;
|
|
+
|
|
// Forward declaration
|
|
class Environment;
|
|
|
|
Index: node-v4.9.1/src/node.cc
|
|
===================================================================
|
|
--- node-v4.9.1.orig/src/node.cc
|
|
+++ node-v4.9.1/src/node.cc
|
|
@@ -161,6 +161,8 @@ unsigned int reverted = 0;
|
|
static const char* icu_data_dir = nullptr;
|
|
#endif
|
|
|
|
+uint64_t max_http_header_size = 8 * 1024;
|
|
+
|
|
// used by C++ modules as well
|
|
bool no_deprecation = false;
|
|
|
|
@@ -3409,6 +3411,8 @@ static void PrintHelp() {
|
|
" --trace-deprecation show stack traces on deprecations\n"
|
|
" --throw-deprecation throw an exception anytime a deprecated "
|
|
"function is used\n"
|
|
+ " --max-http-header-size Specify the maximum size of HTTP\n"
|
|
+ " headers in bytes. Defaults to 8KB.\n"
|
|
" --trace-sync-io show stack trace when use of sync IO\n"
|
|
" is detected after the first tick\n"
|
|
" --track-heap-objects track heap object allocations for heap "
|
|
@@ -3558,6 +3562,8 @@ static void ParseArgs(int* argc,
|
|
short_circuit = true;
|
|
} else if (strcmp(arg, "--zero-fill-buffers") == 0) {
|
|
zero_fill_all_buffers = true;
|
|
+ } else if (strncmp(arg, "--max-http-header-size=", 23) == 0) {
|
|
+ max_http_header_size = atoi(arg + 23);
|
|
} else if (strcmp(arg, "--v8-options") == 0) {
|
|
new_v8_argv[new_v8_argc] = "--help";
|
|
new_v8_argc += 1;
|
|
Index: node-v4.9.1/test/common.js
|
|
===================================================================
|
|
--- node-v4.9.1.orig/test/common.js
|
|
+++ node-v4.9.1/test/common.js
|
|
@@ -410,6 +410,26 @@ exports.mustCall = function(fn, expected
|
|
};
|
|
};
|
|
|
|
+exports.getCallSite = function getCallSite(top) {
|
|
+ const originalStackFormatter = Error.prepareStackTrace;
|
|
+ Error.prepareStackTrace = (err, stack) =>
|
|
+ `${stack[0].getFileName()}:${stack[0].getLineNumber()}`;
|
|
+ const err = new Error();
|
|
+ Error.captureStackTrace(err, top);
|
|
+ // with the V8 Error API, the stack is not formatted until it is accessed
|
|
+ err.stack;
|
|
+ Error.prepareStackTrace = originalStackFormatter;
|
|
+ return err.stack;
|
|
+};
|
|
+
|
|
+exports.mustNotCall = function(msg) {
|
|
+ const callSite = exports.getCallSite(exports.mustNotCall);
|
|
+ return function mustNotCall() {
|
|
+ assert.fail(
|
|
+ `${msg || 'function should not have been called'} at ${callSite}`);
|
|
+ };
|
|
+};
|
|
+
|
|
var etcServicesFileName = path.join('/etc', 'services');
|
|
if (exports.isWindows) {
|
|
etcServicesFileName = path.join(process.env.SystemRoot, 'System32', 'drivers',
|