Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
devel:languages:nodejs
nodejs4
max_header_size.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File max_header_size.patch of Package nodejs4
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',
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor