http: make parser choice a runtime flag

Add a `--http-parser=llhttp` vs `--http-parser=traditional`
command line switch, to make testing and comparing the new
llhttp-based implementation easier.

PR-URL: https://github.com/nodejs/node/pull/24739
Refs: https://github.com/nodejs/node/issues/24730
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Matheus Marchini <mat@mmarchini.me>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
This commit is contained in:
Anna Henningsen 2018-11-30 07:39:02 +01:00 committed by Daniel Bevenius
parent 7bcbf044dd
commit aa943d098e
29 changed files with 157 additions and 85 deletions

View File

@ -187,7 +187,7 @@ parser.add_option('--openssl-system-ca-path',
parser.add_option('--experimental-http-parser', parser.add_option('--experimental-http-parser',
action='store_true', action='store_true',
dest='experimental_http_parser', dest='experimental_http_parser',
help='use llhttp instead of http_parser') help='use llhttp instead of http_parser by default')
shared_optgroup.add_option('--shared-http-parser', shared_optgroup.add_option('--shared-http-parser',
action='store_true', action='store_true',

View File

@ -119,6 +119,22 @@ added: v6.0.0
Force FIPS-compliant crypto on startup. (Cannot be disabled from script code.) Force FIPS-compliant crypto on startup. (Cannot be disabled from script code.)
(Same requirements as `--enable-fips`.) (Same requirements as `--enable-fips`.)
### `--http-parser=library`
<!-- YAML
added: REPLACEME
-->
Chooses an HTTP parser library. Available values are:
- `llhttp` for https://llhttp.org/
- `legacy` for https://github.com/nodejs/http-parser
The default is `legacy`, unless otherwise specified when building Node.js.
This flag exists to aid in experimentation with the internal implementation of
the Node.js http parser.
This flag is likely to become a no-op and removed at some point in the future.
### `--icu-data-dir=file` ### `--icu-data-dir=file`
<!-- YAML <!-- YAML
added: v0.11.15 added: v0.11.15

View File

@ -97,6 +97,12 @@ Enable experimental ES module support in VM module.
.It Fl -experimental-worker .It Fl -experimental-worker
Enable experimental worker threads using worker_threads module. Enable experimental worker threads using worker_threads module.
. .
.It Fl -http-parser Ns = Ns Ar library
Chooses an HTTP parser library. Available values are
.Sy llhttp
or
.Sy legacy .
.
.It Fl -force-fips .It Fl -force-fips
Force FIPS-compliant crypto on startup Force FIPS-compliant crypto on startup
(Cannot be disabled from script code). (Cannot be disabled from script code).

View File

@ -24,14 +24,14 @@
const util = require('util'); const util = require('util');
const net = require('net'); const net = require('net');
const url = require('url'); const url = require('url');
const { HTTPParser } = internalBinding('http_parser');
const assert = require('assert').ok; const assert = require('assert').ok;
const { const {
_checkIsHttpToken: checkIsHttpToken, _checkIsHttpToken: checkIsHttpToken,
debug, debug,
freeParser, freeParser,
httpSocketSetup, httpSocketSetup,
parsers parsers,
HTTPParser,
} = require('_http_common'); } = require('_http_common');
const { OutgoingMessage } = require('_http_outgoing'); const { OutgoingMessage } = require('_http_outgoing');
const Agent = require('_http_agent'); const Agent = require('_http_agent');

View File

@ -21,7 +21,11 @@
'use strict'; 'use strict';
const { methods, HTTPParser } = internalBinding('http_parser'); const { getOptionValue } = require('internal/options');
const { methods, HTTPParser } =
getOptionValue('--http-parser') === 'legacy' ?
internalBinding('http_parser') : internalBinding('http_parser_llhttp');
const { FreeList } = require('internal/freelist'); const { FreeList } = require('internal/freelist');
const { ondrain } = require('internal/http'); const { ondrain } = require('internal/http');
@ -243,5 +247,6 @@ module.exports = {
httpSocketSetup, httpSocketSetup,
methods, methods,
parsers, parsers,
kIncomingMessage kIncomingMessage,
HTTPParser
}; };

View File

@ -23,7 +23,6 @@
const util = require('util'); const util = require('util');
const net = require('net'); const net = require('net');
const { HTTPParser } = internalBinding('http_parser');
const assert = require('assert').ok; const assert = require('assert').ok;
const { const {
parsers, parsers,
@ -34,6 +33,7 @@ const {
chunkExpression, chunkExpression,
httpSocketSetup, httpSocketSetup,
kIncomingMessage, kIncomingMessage,
HTTPParser,
_checkInvalidHeaderChar: checkInvalidHeaderChar _checkInvalidHeaderChar: checkInvalidHeaderChar
} = require('_http_common'); } = require('_http_common');
const { OutgoingMessage } = require('_http_outgoing'); const { OutgoingMessage } = require('_http_outgoing');

View File

@ -127,7 +127,7 @@ const handleConversion = {
if (freeParser === undefined) if (freeParser === undefined)
freeParser = require('_http_common').freeParser; freeParser = require('_http_common').freeParser;
if (HTTPParser === undefined) if (HTTPParser === undefined)
HTTPParser = internalBinding('http_parser').HTTPParser; HTTPParser = require('_http_common').HTTPParser;
// In case of an HTTP connection socket, release the associated // In case of an HTTP connection socket, release the associated
// resources // resources

View File

@ -355,7 +355,8 @@
'src/node_encoding.cc', 'src/node_encoding.cc',
'src/node_errors.cc', 'src/node_errors.cc',
'src/node_file.cc', 'src/node_file.cc',
'src/node_http_parser.cc', 'src/node_http_parser_llhttp.cc',
'src/node_http_parser_traditional.cc',
'src/node_http2.cc', 'src/node_http2.cc',
'src/node_i18n.cc', 'src/node_i18n.cc',
'src/node_messaging.cc', 'src/node_messaging.cc',
@ -426,6 +427,7 @@
'src/node_contextify.h', 'src/node_contextify.h',
'src/node_errors.h', 'src/node_errors.h',
'src/node_file.h', 'src/node_file.h',
'src/node_http_parser_impl.h',
'src/node_http2.h', 'src/node_http2.h',
'src/node_http2_state.h', 'src/node_http2_state.h',
'src/node_i18n.h', 'src/node_i18n.h',

View File

@ -164,12 +164,14 @@
}], }],
[ 'node_experimental_http_parser=="true"', { [ 'node_experimental_http_parser=="true"', {
'defines': [ 'NODE_EXPERIMENTAL_HTTP' ], 'defines': [ 'NODE_EXPERIMENTAL_HTTP_DEFAULT' ],
'dependencies': [ 'deps/llhttp/llhttp.gyp:llhttp' ], } ],
}, {
'conditions': [ [ 'node_shared_http_parser=="false"', { [ 'node_shared_http_parser=="false"', {
'dependencies': [ 'deps/http_parser/http_parser.gyp:http_parser' ], 'dependencies': [
} ] ], 'deps/http_parser/http_parser.gyp:http_parser',
'deps/llhttp/llhttp.gyp:llhttp'
],
} ], } ],
[ 'node_shared_cares=="false"', { [ 'node_shared_cares=="false"', {

View File

@ -1,6 +1,10 @@
#include "inspector_socket.h" #include "inspector_socket.h"
#ifdef NODE_EXPERIMENTAL_HTTP_DEFAULT
#define NODE_EXPERIMENTAL_HTTP
#endif
#include "http_parser_adaptor.h" #include "http_parser_adaptor.h"
#include "util-inl.h" #include "util-inl.h"
#define NODE_WANT_INTERNALS 1 #define NODE_WANT_INTERNALS 1
@ -433,13 +437,13 @@ class HttpHandler : public ProtocolHandler {
explicit HttpHandler(InspectorSocket* inspector, TcpHolder::Pointer tcp) explicit HttpHandler(InspectorSocket* inspector, TcpHolder::Pointer tcp)
: ProtocolHandler(inspector, std::move(tcp)), : ProtocolHandler(inspector, std::move(tcp)),
parsing_value_(false) { parsing_value_(false) {
#ifdef NODE_EXPERIMENTAL_HTTP #ifdef NODE_EXPERIMENTAL_HTTP_DEFAULT
llhttp_init(&parser_, HTTP_REQUEST, &parser_settings); llhttp_init(&parser_, HTTP_REQUEST, &parser_settings);
llhttp_settings_init(&parser_settings); llhttp_settings_init(&parser_settings);
#else /* !NODE_EXPERIMENTAL_HTTP */ #else /* !NODE_EXPERIMENTAL_HTTP_DEFAULT */
http_parser_init(&parser_, HTTP_REQUEST); http_parser_init(&parser_, HTTP_REQUEST);
http_parser_settings_init(&parser_settings); http_parser_settings_init(&parser_settings);
#endif /* NODE_EXPERIMENTAL_HTTP */ #endif /* NODE_EXPERIMENTAL_HTTP_DEFAULT */
parser_settings.on_header_field = OnHeaderField; parser_settings.on_header_field = OnHeaderField;
parser_settings.on_header_value = OnHeaderValue; parser_settings.on_header_value = OnHeaderValue;
parser_settings.on_message_complete = OnMessageComplete; parser_settings.on_message_complete = OnMessageComplete;
@ -484,17 +488,17 @@ class HttpHandler : public ProtocolHandler {
void OnData(std::vector<char>* data) override { void OnData(std::vector<char>* data) override {
parser_errno_t err; parser_errno_t err;
#ifdef NODE_EXPERIMENTAL_HTTP #ifdef NODE_EXPERIMENTAL_HTTP_DEFAULT
err = llhttp_execute(&parser_, data->data(), data->size()); err = llhttp_execute(&parser_, data->data(), data->size());
if (err == HPE_PAUSED_UPGRADE) { if (err == HPE_PAUSED_UPGRADE) {
err = HPE_OK; err = HPE_OK;
llhttp_resume_after_upgrade(&parser_); llhttp_resume_after_upgrade(&parser_);
} }
#else /* !NODE_EXPERIMENTAL_HTTP */ #else /* !NODE_EXPERIMENTAL_HTTP_DEFAULT */
http_parser_execute(&parser_, &parser_settings, data->data(), data->size()); http_parser_execute(&parser_, &parser_settings, data->data(), data->size());
err = HTTP_PARSER_ERRNO(&parser_); err = HTTP_PARSER_ERRNO(&parser_);
#endif /* NODE_EXPERIMENTAL_HTTP */ #endif /* NODE_EXPERIMENTAL_HTTP_DEFAULT */
data->clear(); data->clear();
if (err != HPE_OK) { if (err != HPE_OK) {
CancelHandshake(); CancelHandshake();

View File

@ -36,6 +36,7 @@
V(heap_utils) \ V(heap_utils) \
V(http2) \ V(http2) \
V(http_parser) \ V(http_parser) \
V(http_parser_llhttp) \
V(inspector) \ V(inspector) \
V(js_stream) \ V(js_stream) \
V(messaging) \ V(messaging) \

View File

@ -19,6 +19,12 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE. // USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file is included from 2 files, node_http_parser_traditional.cc
// and node_http_parser_llhttp.cc.
#ifndef SRC_NODE_HTTP_PARSER_IMPL_H_
#define SRC_NODE_HTTP_PARSER_IMPL_H_
#include "node.h" #include "node.h"
#include "node_buffer.h" #include "node_buffer.h"
#include "node_internals.h" #include "node_internals.h"
@ -47,7 +53,7 @@
namespace node { namespace node {
namespace { namespace { // NOLINT(build/namespaces)
using v8::Array; using v8::Array;
using v8::Boolean; using v8::Boolean;
@ -910,10 +916,10 @@ const parser_settings_t Parser::settings = {
}; };
void Initialize(Local<Object> target, void InitializeHttpParser(Local<Object> target,
Local<Value> unused, Local<Value> unused,
Local<Context> context, Local<Context> context,
void* priv) { void* priv) {
Environment* env = Environment::GetCurrent(context); Environment* env = Environment::GetCurrent(context);
Local<FunctionTemplate> t = env->NewFunctionTemplate(Parser::New); Local<FunctionTemplate> t = env->NewFunctionTemplate(Parser::New);
t->InstanceTemplate()->SetInternalFieldCount(1); t->InstanceTemplate()->SetInternalFieldCount(1);
@ -964,4 +970,4 @@ void Initialize(Local<Object> target,
} // anonymous namespace } // anonymous namespace
} // namespace node } // namespace node
NODE_MODULE_CONTEXT_AWARE_INTERNAL(http_parser, node::Initialize) #endif // SRC_NODE_HTTP_PARSER_IMPL_H_

View File

@ -0,0 +1,17 @@
#define NODE_EXPERIMENTAL_HTTP 1
#include "node_http_parser_impl.h"
namespace node {
const char* llhttp_version =
NODE_STRINGIFY(LLHTTP_VERSION_MAJOR)
"."
NODE_STRINGIFY(LLHTTP_VERSION_MINOR)
"."
NODE_STRINGIFY(LLHTTP_VERSION_PATCH);
} // namespace node
NODE_MODULE_CONTEXT_AWARE_INTERNAL(http_parser_llhttp,
node::InitializeHttpParser)

View File

@ -0,0 +1,18 @@
#ifdef NODE_EXPERIMENTAL_HTTP
#undef NODE_EXPERIMENTAL_HTTP
#endif
#include "node_http_parser_impl.h"
namespace node {
const char* http_parser_version =
NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR)
"."
NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR)
"."
NODE_STRINGIFY(HTTP_PARSER_VERSION_PATCH);
} // namespace node
NODE_MODULE_CONTEXT_AWARE_INTERNAL(http_parser, node::InitializeHttpParser)

View File

@ -697,6 +697,9 @@ static inline const char* errno_string(int errorno) {
extern double prog_start_time; extern double prog_start_time;
extern const char* llhttp_version;
extern const char* http_parser_version;
void Abort(const v8::FunctionCallbackInfo<v8::Value>& args); void Abort(const v8::FunctionCallbackInfo<v8::Value>& args);
void Chdir(const v8::FunctionCallbackInfo<v8::Value>& args); void Chdir(const v8::FunctionCallbackInfo<v8::Value>& args);
void CPUUsage(const v8::FunctionCallbackInfo<v8::Value>& args); void CPUUsage(const v8::FunctionCallbackInfo<v8::Value>& args);

View File

@ -11,12 +11,6 @@
#include "node_crypto.h" #include "node_crypto.h"
#endif #endif
#ifdef NODE_EXPERIMENTAL_HTTP
#include "llhttp.h"
#else /* !NODE_EXPERIMENTAL_HTTP */
#include "http_parser.h"
#endif /* NODE_EXPERIMENTAL_HTTP */
namespace node { namespace node {
namespace per_process { namespace per_process {
@ -32,14 +26,8 @@ Metadata::Versions::Versions() {
modules = NODE_STRINGIFY(NODE_MODULE_VERSION); modules = NODE_STRINGIFY(NODE_MODULE_VERSION);
nghttp2 = NGHTTP2_VERSION; nghttp2 = NGHTTP2_VERSION;
napi = NODE_STRINGIFY(NAPI_VERSION); napi = NODE_STRINGIFY(NAPI_VERSION);
llhttp = llhttp_version;
#ifdef NODE_EXPERIMENTAL_HTTP http_parser = http_parser_version;
llhttp = NODE_STRINGIFY(LLHTTP_VERSION_MAJOR) "." NODE_STRINGIFY(
LLHTTP_VERSION_MINOR) "." NODE_STRINGIFY(LLHTTP_VERSION_PATCH);
#else /* !NODE_EXPERIMENTAL_HTTP */
http_parser = NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR) "." NODE_STRINGIFY(
HTTP_PARSER_VERSION_MINOR) "." NODE_STRINGIFY(HTTP_PARSER_VERSION_PATCH);
#endif /* NODE_EXPERIMENTAL_HTTP */
#if HAVE_OPENSSL #if HAVE_OPENSSL
openssl = crypto::GetOpenSSLVersion(); openssl = crypto::GetOpenSSLVersion();

View File

@ -15,13 +15,9 @@ namespace node {
V(ares) \ V(ares) \
V(modules) \ V(modules) \
V(nghttp2) \ V(nghttp2) \
V(napi) V(napi) \
V(llhttp) \
#ifdef NODE_EXPERIMENTAL_HTTP V(http_parser) \
#define NODE_VERSIONS_KEY_HTTP(V) V(llhttp)
#else /* !NODE_EXPERIMENTAL_HTTP */
#define NODE_VERSIONS_KEY_HTTP(V) V(http_parser)
#endif /* NODE_EXPERIMENTAL_HTTP */
#if HAVE_OPENSSL #if HAVE_OPENSSL
#define NODE_VERSIONS_KEY_CRYPTO(V) V(openssl) #define NODE_VERSIONS_KEY_CRYPTO(V) V(openssl)
@ -31,7 +27,6 @@ namespace node {
#define NODE_VERSIONS_KEYS(V) \ #define NODE_VERSIONS_KEYS(V) \
NODE_VERSIONS_KEYS_BASE(V) \ NODE_VERSIONS_KEYS_BASE(V) \
NODE_VERSIONS_KEY_HTTP(V) \
NODE_VERSIONS_KEY_CRYPTO(V) NODE_VERSIONS_KEY_CRYPTO(V)
class Metadata { class Metadata {

View File

@ -39,6 +39,11 @@ void EnvironmentOptions::CheckOptions(std::vector<std::string>* errors) {
if (syntax_check_only && has_eval_string) { if (syntax_check_only && has_eval_string) {
errors->push_back("either --check or --eval can be used, not both"); errors->push_back("either --check or --eval can be used, not both");
} }
if (http_parser != "legacy" && http_parser != "llhttp") {
errors->push_back("invalid value for --http-parser");
}
debug_options->CheckOptions(errors); debug_options->CheckOptions(errors);
} }
@ -102,6 +107,15 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
&EnvironmentOptions::experimental_worker, &EnvironmentOptions::experimental_worker,
kAllowedInEnvironment); kAllowedInEnvironment);
AddOption("--expose-internals", "", &EnvironmentOptions::expose_internals); AddOption("--expose-internals", "", &EnvironmentOptions::expose_internals);
AddOption("--http-parser",
"Select which HTTP parser to use; either 'legacy' or 'llhttp' "
#ifdef NODE_EXPERIMENTAL_HTTP_DEFAULT
"(default: llhttp).",
#else
"(default: legacy).",
#endif
&EnvironmentOptions::http_parser,
kAllowedInEnvironment);
AddOption("--loader", AddOption("--loader",
"(with --experimental-modules) use the specified file as a " "(with --experimental-modules) use the specified file as a "
"custom loader", "custom loader",

View File

@ -72,6 +72,12 @@ class EnvironmentOptions : public Options {
bool experimental_vm_modules = false; bool experimental_vm_modules = false;
bool experimental_worker = false; bool experimental_worker = false;
bool expose_internals = false; bool expose_internals = false;
std::string http_parser =
#ifdef NODE_EXPERIMENTAL_HTTP_DEFAULT
"llhttp";
#else
"legacy";
#endif
bool no_deprecation = false; bool no_deprecation = false;
bool no_force_async_hooks_checks = false; bool no_force_async_hooks_checks = false;
bool no_warnings = false; bool no_warnings = false;

View File

@ -10,13 +10,7 @@ const { checkInvocations } = require('./hook-checks');
const hooks = initHooks(); const hooks = initHooks();
hooks.enable(); hooks.enable();
// The hooks.enable() must come before require('internal/test/binding') const { HTTPParser } = require('_http_common');
// because internal/test/binding schedules a process warning on nextTick.
// If this order is not preserved, the hooks check will fail because it
// will not be notified about the nextTick creation but will see the
// callback event.
const { internalBinding } = require('internal/test/binding');
const { HTTPParser } = internalBinding('http_parser');
const REQUEST = HTTPParser.REQUEST; const REQUEST = HTTPParser.REQUEST;

View File

@ -11,13 +11,7 @@ const hooks = initHooks();
hooks.enable(); hooks.enable();
// The hooks.enable() must come before require('internal/test/binding') const { HTTPParser } = require('_http_common');
// because internal/test/binding schedules a process warning on nextTick.
// If this order is not preserved, the hooks check will fail because it
// will not be notified about the nextTick creation but will see the
// callback event.
const { internalBinding } = require('internal/test/binding');
const { HTTPParser } = internalBinding('http_parser');
const RESPONSE = HTTPParser.RESPONSE; const RESPONSE = HTTPParser.RESPONSE;
const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0; const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;

View File

@ -2,12 +2,11 @@
// Run this program with valgrind or efence with --expose_gc to expose the // Run this program with valgrind or efence with --expose_gc to expose the
// problem. // problem.
// Flags: --expose_gc --expose-internals // Flags: --expose_gc
require('../common'); require('../common');
const assert = require('assert'); const assert = require('assert');
const { internalBinding } = require('internal/test/binding'); const { HTTPParser } = require('_http_common');
const { HTTPParser } = internalBinding('http_parser');
const kOnHeaders = HTTPParser.kOnHeaders | 0; const kOnHeaders = HTTPParser.kOnHeaders | 0;
const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0; const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;

View File

@ -3,6 +3,7 @@
'use strict'; 'use strict';
const { internalBinding } = require('internal/test/binding'); const { internalBinding } = require('internal/test/binding');
const { getOptionValue } = require('internal/options');
// Monkey patch before requiring anything // Monkey patch before requiring anything
class DummyParser { class DummyParser {
@ -11,7 +12,11 @@ class DummyParser {
} }
} }
DummyParser.REQUEST = Symbol(); DummyParser.REQUEST = Symbol();
internalBinding('http_parser').HTTPParser = DummyParser;
const binding =
getOptionValue('--http-parser') === 'legacy' ?
internalBinding('http_parser') : internalBinding('http_parser_llhttp');
binding.HTTPParser = DummyParser;
const common = require('../common'); const common = require('../common');
const assert = require('assert'); const assert = require('assert');

View File

@ -19,14 +19,11 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE. // USE OR OTHER DEALINGS IN THE SOFTWARE.
// Flags: --expose-internals
'use strict'; 'use strict';
const { mustCall, mustNotCall } = require('../common'); const { mustCall, mustNotCall } = require('../common');
const assert = require('assert'); const assert = require('assert');
const { internalBinding } = require('internal/test/binding'); const { methods, HTTPParser } = require('_http_common');
const { methods, HTTPParser } = internalBinding('http_parser');
const { REQUEST, RESPONSE } = HTTPParser; const { REQUEST, RESPONSE } = HTTPParser;
const kOnHeaders = HTTPParser.kOnHeaders | 0; const kOnHeaders = HTTPParser.kOnHeaders | 0;

View File

@ -3,7 +3,8 @@ const common = require('../common');
const assert = require('assert'); const assert = require('assert');
const expected_keys = ['ares', 'modules', 'node', const expected_keys = ['ares', 'modules', 'node',
'uv', 'v8', 'zlib', 'nghttp2', 'napi']; 'uv', 'v8', 'zlib', 'nghttp2', 'napi',
'http_parser', 'llhttp'];
if (common.hasCrypto) { if (common.hasCrypto) {
expected_keys.push('openssl'); expected_keys.push('openssl');
@ -16,9 +17,6 @@ if (common.hasIntl) {
expected_keys.push('unicode'); expected_keys.push('unicode');
} }
expected_keys.push(
process.versions.llhttp === undefined ? 'http_parser' : 'llhttp');
expected_keys.sort(); expected_keys.sort();
const actual_keys = Object.keys(process.versions).sort(); const actual_keys = Object.keys(process.versions).sort();
@ -27,8 +25,8 @@ assert.deepStrictEqual(actual_keys, expected_keys);
const commonTemplate = /^\d+\.\d+\.\d+(?:-.*)?$/; const commonTemplate = /^\d+\.\d+\.\d+(?:-.*)?$/;
assert(commonTemplate.test(process.versions.ares)); assert(commonTemplate.test(process.versions.ares));
assert(commonTemplate.test(process.versions.llhttp === undefined ? assert(commonTemplate.test(process.versions.llhttp));
process.versions.http_parser : process.versions.llhttp)); assert(commonTemplate.test(process.versions.http_parser));
assert(commonTemplate.test(process.versions.node)); assert(commonTemplate.test(process.versions.node));
assert(commonTemplate.test(process.versions.uv)); assert(commonTemplate.test(process.versions.uv));
assert(commonTemplate.test(process.versions.zlib)); assert(commonTemplate.test(process.versions.zlib));

View File

@ -36,9 +36,10 @@ proc.once('exit', common.mustCall(() => {
assert(traces.some((trace) => assert(traces.some((trace) =>
trace.name === 'node' && trace.name === 'node' &&
(trace.args.process.versions.http_parser === trace.args.process.versions.http_parser ===
process.versions.http_parser || process.versions.http_parser &&
trace.args.process.versions.llhttp === process.versions.llhttp) && trace.args.process.versions.llhttp ===
process.versions.llhttp &&
trace.args.process.versions.node === trace.args.process.versions.node ===
process.versions.node && process.versions.node &&
trace.args.process.versions.v8 === trace.args.process.versions.v8 ===

View File

@ -148,7 +148,7 @@ if (common.hasCrypto) { // eslint-disable-line node-core/crypto-check
{ {
const { HTTPParser } = internalBinding('http_parser'); const { HTTPParser } = require('_http_common');
testInitialized(new HTTPParser(HTTPParser.REQUEST), 'HTTPParser'); testInitialized(new HTTPParser(HTTPParser.REQUEST), 'HTTPParser');
} }

View File

@ -1,11 +1,13 @@
// Flags: --expose-internals
'use strict'; 'use strict';
const assert = require('assert');
const common = require('../common'); const common = require('../common');
const assert = require('assert');
const http = require('http'); const http = require('http');
const net = require('net'); const net = require('net');
const MAX = 8 * 1024; // 8KB const MAX = 8 * 1024; // 8KB
const { getOptionValue } = require('internal/options');
// Verify that we cannot receive more than 8KB of headers. // Verify that we cannot receive more than 8KB of headers.
function once(cb) { function once(cb) {
@ -27,7 +29,7 @@ function finished(client, callback) {
function fillHeaders(headers, currentSize, valid = false) { function fillHeaders(headers, currentSize, valid = false) {
// llhttp counts actual header name/value sizes, excluding the whitespace and // llhttp counts actual header name/value sizes, excluding the whitespace and
// stripped chars. // stripped chars.
if (process.versions.hasOwnProperty('llhttp')) { if (getOptionValue('--http-parser') === 'llhttp') {
// OK, Content-Length, 0, X-CRASH, aaa... // OK, Content-Length, 0, X-CRASH, aaa...
headers += 'a'.repeat(MAX - currentSize); headers += 'a'.repeat(MAX - currentSize);
} else { } else {

View File

@ -6,9 +6,8 @@
const common = require('../common'); const common = require('../common');
const assert = require('assert'); const assert = require('assert');
const httpCommon = require('_http_common'); const httpCommon = require('_http_common');
const { internalBinding } = require('internal/test/binding');
const is_reused_symbol = require('internal/freelist').symbols.is_reused_symbol; const is_reused_symbol = require('internal/freelist').symbols.is_reused_symbol;
const { HTTPParser } = internalBinding('http_parser'); const { HTTPParser } = require('_http_common');
const net = require('net'); const net = require('net');
const COUNT = httpCommon.parsers.max + 1; const COUNT = httpCommon.parsers.max + 1;