summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFedor Indutny <fedor@indutny.com>2018-10-29 22:06:09 -0400
committerFedor Indutny <fedor@indutny.com>2018-11-10 17:54:21 -0500
commitd4654d89be0c20f8ca1e153d074a236348618b00 (patch)
treef6aa2013a63ad85987bdef23fa82f1eade6d08ee /src
parentd3f02d0da3d574b91a15d3ace10e76014b7574fc (diff)
downloadandroid-node-v8-d4654d89be0c20f8ca1e153d074a236348618b00.tar.gz
android-node-v8-d4654d89be0c20f8ca1e153d074a236348618b00.tar.bz2
android-node-v8-d4654d89be0c20f8ca1e153d074a236348618b00.zip
deps: introduce `llhttp`
llhttp is modern, written in human-readable TypeScript, verifiable, and is very easy to maintain. See: https://github.com/indutny/llhttp PR-URL: https://github.com/nodejs/node/pull/24059 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Rod Vagg <rod@vagg.org> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'src')
-rw-r--r--src/env.h1
-rw-r--r--src/http_parser_adaptor.h24
-rw-r--r--src/inspector_socket.cc34
-rw-r--r--src/node.cc46
-rw-r--r--src/node_http_parser.cc229
5 files changed, 266 insertions, 68 deletions
diff --git a/src/env.h b/src/env.h
index a7ea3de82f..aec2f8fde4 100644
--- a/src/env.h
+++ b/src/env.h
@@ -265,6 +265,7 @@ constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
V(raw_string, "raw") \
V(read_host_object_string, "_readHostObject") \
V(readable_string, "readable") \
+ V(reason_string, "reason") \
V(refresh_string, "refresh") \
V(regexp_string, "regexp") \
V(rename_string, "rename") \
diff --git a/src/http_parser_adaptor.h b/src/http_parser_adaptor.h
new file mode 100644
index 0000000000..6d786bd095
--- /dev/null
+++ b/src/http_parser_adaptor.h
@@ -0,0 +1,24 @@
+#ifndef SRC_HTTP_PARSER_ADAPTOR_H_
+#define SRC_HTTP_PARSER_ADAPTOR_H_
+
+#ifdef NODE_EXPERIMENTAL_HTTP
+# include "llhttp.h"
+
+typedef llhttp_type_t parser_type_t;
+typedef llhttp_errno_t parser_errno_t;
+typedef llhttp_settings_t parser_settings_t;
+typedef llhttp_t parser_t;
+
+#else /* !NODE_EXPERIMENTAL_HTTP */
+# include "http_parser.h"
+
+typedef enum http_parser_type parser_type_t;
+typedef enum http_errno parser_errno_t;
+typedef http_parser_settings parser_settings_t;
+typedef http_parser parser_t;
+
+#define HPE_USER HPE_UNKNOWN
+
+#endif /* NODE_EXPERIMENTAL_HTTP */
+
+#endif /* SRC_HTTP_PARSER_ADAPTOR_H_ */
diff --git a/src/inspector_socket.cc b/src/inspector_socket.cc
index dc36359b5c..8c2d0a5a22 100644
--- a/src/inspector_socket.cc
+++ b/src/inspector_socket.cc
@@ -1,6 +1,6 @@
#include "inspector_socket.h"
-#include "http_parser.h"
+#include "http_parser_adaptor.h"
#include "util-inl.h"
#define NODE_WANT_INTERNALS 1
@@ -433,8 +433,13 @@ class HttpHandler : public ProtocolHandler {
explicit HttpHandler(InspectorSocket* inspector, TcpHolder::Pointer tcp)
: ProtocolHandler(inspector, std::move(tcp)),
parsing_value_(false) {
+#ifdef NODE_EXPERIMENTAL_HTTP
+ llhttp_init(&parser_, HTTP_REQUEST, &parser_settings);
+ llhttp_settings_init(&parser_settings);
+#else /* !NODE_EXPERIMENTAL_HTTP */
http_parser_init(&parser_, HTTP_REQUEST);
http_parser_settings_init(&parser_settings);
+#endif /* NODE_EXPERIMENTAL_HTTP */
parser_settings.on_header_field = OnHeaderField;
parser_settings.on_header_value = OnHeaderValue;
parser_settings.on_message_complete = OnMessageComplete;
@@ -478,9 +483,20 @@ class HttpHandler : public ProtocolHandler {
}
void OnData(std::vector<char>* data) override {
+ parser_errno_t err;
+#ifdef NODE_EXPERIMENTAL_HTTP
+ err = llhttp_execute(&parser_, data->data(), data->size());
+
+ if (err == HPE_PAUSED_UPGRADE) {
+ err = HPE_OK;
+ llhttp_resume_after_upgrade(&parser_);
+ }
+#else /* !NODE_EXPERIMENTAL_HTTP */
http_parser_execute(&parser_, &parser_settings, data->data(), data->size());
+ err = HTTP_PARSER_ERRNO(&parser_);
+#endif /* NODE_EXPERIMENTAL_HTTP */
data->clear();
- if (parser_.http_errno != HPE_OK) {
+ if (err != HPE_OK) {
CancelHandshake();
}
// Event handling may delete *this
@@ -517,14 +533,14 @@ class HttpHandler : public ProtocolHandler {
handler->inspector()->SwitchProtocol(nullptr);
}
- static int OnHeaderValue(http_parser* parser, const char* at, size_t length) {
+ static int OnHeaderValue(parser_t* parser, const char* at, size_t length) {
HttpHandler* handler = From(parser);
handler->parsing_value_ = true;
handler->headers_[handler->current_header_].append(at, length);
return 0;
}
- static int OnHeaderField(http_parser* parser, const char* at, size_t length) {
+ static int OnHeaderField(parser_t* parser, const char* at, size_t length) {
HttpHandler* handler = From(parser);
if (handler->parsing_value_) {
handler->parsing_value_ = false;
@@ -534,17 +550,17 @@ class HttpHandler : public ProtocolHandler {
return 0;
}
- static int OnPath(http_parser* parser, const char* at, size_t length) {
+ static int OnPath(parser_t* parser, const char* at, size_t length) {
HttpHandler* handler = From(parser);
handler->path_.append(at, length);
return 0;
}
- static HttpHandler* From(http_parser* parser) {
+ static HttpHandler* From(parser_t* parser) {
return node::ContainerOf(&HttpHandler::parser_, parser);
}
- static int OnMessageComplete(http_parser* parser) {
+ static int OnMessageComplete(parser_t* parser) {
// Event needs to be fired after the parser is done.
HttpHandler* handler = From(parser);
handler->events_.push_back(
@@ -581,8 +597,8 @@ class HttpHandler : public ProtocolHandler {
}
bool parsing_value_;
- http_parser parser_;
- http_parser_settings parser_settings;
+ parser_t parser_;
+ parser_settings_t parser_settings;
std::vector<HttpEvent> events_;
std::string current_header_;
std::map<std::string, std::string> headers_;
diff --git a/src/node.cc b/src/node.cc
index b612ef3c34..0ee788460e 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -53,7 +53,11 @@
#include "async_wrap-inl.h"
#include "env-inl.h"
#include "handle_wrap.h"
-#include "http_parser.h"
+#ifdef NODE_EXPERIMENTAL_HTTP
+# include "llhttp.h"
+#else /* !NODE_EXPERIMENTAL_HTTP */
+# include "http_parser.h"
+#endif /* NODE_EXPERIMENTAL_HTTP */
#include "nghttp2/nghttp2ver.h"
#include "req_wrap-inl.h"
#include "string_bytes.h"
@@ -179,6 +183,22 @@ static node_module* modlist_internal;
static node_module* modlist_linked;
static node_module* modlist_addon;
+#ifdef NODE_EXPERIMENTAL_HTTP
+static const char llhttp_version[] =
+ NODE_STRINGIFY(LLHTTP_VERSION_MAJOR)
+ "."
+ NODE_STRINGIFY(LLHTTP_VERSION_MINOR)
+ "."
+ NODE_STRINGIFY(LLHTTP_VERSION_PATCH);
+#else /* !NODE_EXPERIMENTAL_HTTP */
+static const char http_parser_version[] =
+ NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR)
+ "."
+ NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR)
+ "."
+ NODE_STRINGIFY(HTTP_PARSER_VERSION_PATCH);
+#endif /* NODE_EXPERIMENTAL_HTTP */
+
// Bit flag used to track security reverts (see node_revert.h)
unsigned int reverted = 0;
@@ -217,17 +237,15 @@ class NodeTraceStateObserver :
auto trace_process = tracing::TracedValue::Create();
trace_process->BeginDictionary("versions");
- const char http_parser_version[] =
- NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR)
- "."
- NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR)
- "."
- NODE_STRINGIFY(HTTP_PARSER_VERSION_PATCH);
+#ifdef NODE_EXPERIMENTAL_HTTP
+ trace_process->SetString("llhttp", llhttp_version);
+#else /* !NODE_EXPERIMENTAL_HTTP */
+ trace_process->SetString("http_parser", http_parser_version);
+#endif /* NODE_EXPERIMENTAL_HTTP */
const char node_napi_version[] = NODE_STRINGIFY(NAPI_VERSION);
const char node_modules_version[] = NODE_STRINGIFY(NODE_MODULE_VERSION);
- trace_process->SetString("http_parser", http_parser_version);
trace_process->SetString("node", NODE_VERSION_STRING);
trace_process->SetString("v8", V8::GetVersion());
trace_process->SetString("uv", uv_version_string());
@@ -1344,14 +1362,16 @@ void SetupProcessObject(Environment* env,
Local<Object> versions = Object::New(env->isolate());
READONLY_PROPERTY(process, "versions", versions);
- const char http_parser_version[] = NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR)
- "."
- NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR)
- "."
- NODE_STRINGIFY(HTTP_PARSER_VERSION_PATCH);
+#ifdef NODE_EXPERIMENTAL_HTTP
+ READONLY_PROPERTY(versions,
+ "llhttp",
+ FIXED_ONE_BYTE_STRING(env->isolate(), llhttp_version));
+#else /* !NODE_EXPERIMENTAL_HTTP */
READONLY_PROPERTY(versions,
"http_parser",
FIXED_ONE_BYTE_STRING(env->isolate(), http_parser_version));
+#endif /* NODE_EXPERIMENTAL_HTTP */
+
// +1 to get rid of the leading 'v'
READONLY_PROPERTY(versions,
"node",
diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc
index b82710480d..482c7263ca 100644
--- a/src/node_http_parser.cc
+++ b/src/node_http_parser.cc
@@ -25,7 +25,6 @@
#include "async_wrap-inl.h"
#include "env-inl.h"
-#include "http_parser.h"
#include "stream_base-inl.h"
#include "util-inl.h"
#include "v8.h"
@@ -33,6 +32,8 @@
#include <stdlib.h> // free()
#include <string.h> // strdup()
+#include "http_parser_adaptor.h"
+
// This is a binding to http_parser (https://github.com/nodejs/http-parser)
// The goal is to decouple sockets from parsing for more javascript-level
// agility. A Buffer is read from a socket and passed to parser.execute().
@@ -148,7 +149,7 @@ struct StringPtr {
class Parser : public AsyncWrap, public StreamListener {
public:
- Parser(Environment* env, Local<Object> wrap, enum http_parser_type type)
+ Parser(Environment* env, Local<Object> wrap, parser_type_t type)
: AsyncWrap(env, wrap, AsyncWrap::PROVIDER_HTTPPARSER),
current_buffer_len_(0),
current_buffer_data_(nullptr) {
@@ -172,18 +173,33 @@ class Parser : public AsyncWrap, public StreamListener {
int on_url(const char* at, size_t length) {
+ int rv = TrackHeader(length);
+ if (rv != 0) {
+ return rv;
+ }
+
url_.Update(at, length);
return 0;
}
int on_status(const char* at, size_t length) {
+ int rv = TrackHeader(length);
+ if (rv != 0) {
+ return rv;
+ }
+
status_message_.Update(at, length);
return 0;
}
int on_header_field(const char* at, size_t length) {
+ int rv = TrackHeader(length);
+ if (rv != 0) {
+ return rv;
+ }
+
if (num_fields_ == num_values_) {
// start of new field name
num_fields_++;
@@ -206,6 +222,11 @@ class Parser : public AsyncWrap, public StreamListener {
int on_header_value(const char* at, size_t length) {
+ int rv = TrackHeader(length);
+ if (rv != 0) {
+ return rv;
+ }
+
if (num_values_ != num_fields_) {
// start of new header value
num_values_++;
@@ -222,6 +243,10 @@ class Parser : public AsyncWrap, public StreamListener {
int on_headers_complete() {
+#ifdef NODE_EXPERIMENTAL_HTTP
+ header_nread_ = 0;
+#endif /* NODE_EXPERIMENTAL_HTTP */
+
// Arguments for the on-headers-complete javascript callback. This
// list needs to be kept in sync with the actual argument list for
// `parserOnHeadersComplete` in lib/_http_common.js.
@@ -279,8 +304,15 @@ class Parser : public AsyncWrap, public StreamListener {
argv[A_VERSION_MAJOR] = Integer::New(env()->isolate(), parser_.http_major);
argv[A_VERSION_MINOR] = Integer::New(env()->isolate(), parser_.http_minor);
+ bool should_keep_alive;
+#ifdef NODE_EXPERIMENTAL_HTTP
+ should_keep_alive = llhttp_should_keep_alive(&parser_);
+#else /* !NODE_EXPERIMENTAL_HTTP */
+ should_keep_alive = http_should_keep_alive(&parser_);
+#endif /* NODE_EXPERIMENTAL_HTTP */
+
argv[A_SHOULD_KEEP_ALIVE] =
- Boolean::New(env()->isolate(), http_should_keep_alive(&parser_));
+ Boolean::New(env()->isolate(), should_keep_alive);
argv[A_UPGRADE] = Boolean::New(env()->isolate(), parser_.upgrade);
@@ -332,7 +364,10 @@ class Parser : public AsyncWrap, public StreamListener {
if (r.IsEmpty()) {
got_exception_ = true;
- return -1;
+#ifdef NODE_EXPERIMENTAL_HTTP
+ llhttp_set_error_reason(&parser_, "JS Exception");
+#endif /* NODE_EXPERIMENTAL_HTTP */
+ return HPE_USER;
}
return 0;
@@ -357,18 +392,33 @@ class Parser : public AsyncWrap, public StreamListener {
if (r.IsEmpty()) {
got_exception_ = true;
- return -1;
+ return HPE_USER;
}
return 0;
}
+#ifdef NODE_EXPERIMENTAL_HTTP
+ // Reset nread for the next chunk
+ int on_chunk_header() {
+ header_nread_ = 0;
+ return 0;
+ }
+
+
+ // Reset nread for the next chunk
+ int on_chunk_complete() {
+ header_nread_ = 0;
+ return 0;
+ }
+#endif /* NODE_EXPERIMENTAL_HTTP */
+
static void New(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(args[0]->IsInt32());
- http_parser_type type =
- static_cast<http_parser_type>(args[0].As<Int32>()->Value());
+ parser_type_t type =
+ static_cast<parser_type_t>(args[0].As<Int32>()->Value());
CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
new Parser(env, args.This(), type);
}
@@ -434,30 +484,11 @@ class Parser : public AsyncWrap, public StreamListener {
static void Finish(const FunctionCallbackInfo<Value>& args) {
- Environment* env = Environment::GetCurrent(args);
-
Parser* parser;
ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
CHECK(parser->current_buffer_.IsEmpty());
- parser->got_exception_ = false;
-
- int rv = http_parser_execute(&(parser->parser_), &settings, nullptr, 0);
-
- if (parser->got_exception_)
- return;
-
- if (rv != 0) {
- enum http_errno err = HTTP_PARSER_ERRNO(&parser->parser_);
-
- Local<Value> e = Exception::Error(env->parse_error_string());
- Local<Object> obj = e.As<Object>();
- obj->Set(env->bytes_parsed_string(), Integer::New(env->isolate(), 0));
- obj->Set(env->code_string(),
- OneByteString(env->isolate(), http_errno_name(err)));
-
- args.GetReturnValue().Set(e);
- }
+ parser->Execute(nullptr, 0);
}
@@ -467,8 +498,8 @@ class Parser : public AsyncWrap, public StreamListener {
CHECK(args[0]->IsInt32());
CHECK(args[1]->IsBoolean());
bool isReused = args[1]->IsTrue();
- http_parser_type type =
- static_cast<http_parser_type>(args[0].As<Int32>()->Value());
+ parser_type_t type =
+ static_cast<parser_type_t>(args[0].As<Int32>()->Value());
CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE);
Parser* parser;
@@ -492,7 +523,21 @@ class Parser : public AsyncWrap, public StreamListener {
ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder());
// Should always be called from the same context.
CHECK_EQ(env, parser->env());
+
+#ifdef NODE_EXPERIMENTAL_HTTP
+ if (parser->execute_depth_) {
+ parser->pending_pause_ = should_pause;
+ return;
+ }
+
+ if (should_pause) {
+ llhttp_pause(&parser->parser_);
+ } else {
+ llhttp_resume(&parser->parser_);
+ }
+#else /* !NODE_EXPERIMENTAL_HTTP */
http_parser_pause(&parser->parser_, should_pause);
+#endif /* NODE_EXPERIMENTAL_HTTP */
}
@@ -602,10 +647,46 @@ class Parser : public AsyncWrap, public StreamListener {
current_buffer_data_ = data;
got_exception_ = false;
- size_t nparsed =
- http_parser_execute(&parser_, &settings, data, len);
+ parser_errno_t err;
+
+#ifdef NODE_EXPERIMENTAL_HTTP
+ // Do not allow re-entering `http_parser_execute()`
+ CHECK_EQ(execute_depth_, 0);
+
+ execute_depth_++;
+ if (data == nullptr) {
+ err = llhttp_finish(&parser_);
+ } else {
+ err = llhttp_execute(&parser_, data, len);
+ Save();
+ }
+ execute_depth_--;
+
+ // Calculate bytes read and resume after Upgrade/CONNECT pause
+ size_t nread = len;
+ if (err != HPE_OK) {
+ nread = llhttp_get_error_pos(&parser_) - data;
+
+ // This isn't a real pause, just a way to stop parsing early.
+ if (err == HPE_PAUSED_UPGRADE) {
+ err = HPE_OK;
+ llhttp_resume_after_upgrade(&parser_);
+ }
+ }
+
+ // Apply pending pause
+ if (pending_pause_) {
+ pending_pause_ = false;
+ llhttp_pause(&parser_);
+ }
+#else /* !NODE_EXPERIMENTAL_HTTP */
+ size_t nread = http_parser_execute(&parser_, &settings, data, len);
+ if (data != nullptr) {
+ Save();
+ }
- Save();
+ err = HTTP_PARSER_ERRNO(&parser_);
+#endif /* NODE_EXPERIMENTAL_HTTP */
// Unassign the 'buffer_' variable
current_buffer_.Clear();
@@ -616,22 +697,29 @@ class Parser : public AsyncWrap, public StreamListener {
if (got_exception_)
return scope.Escape(Local<Value>());
- Local<Integer> nparsed_obj = Integer::New(env()->isolate(), nparsed);
+ Local<Integer> nread_obj = Integer::New(env()->isolate(), nread);
+
// 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) {
- enum http_errno err = HTTP_PARSER_ERRNO(&parser_);
-
+ if (!parser_.upgrade && err != HPE_OK) {
Local<Value> e = Exception::Error(env()->parse_error_string());
Local<Object> obj = e->ToObject(env()->isolate()->GetCurrentContext())
.ToLocalChecked();
- obj->Set(env()->bytes_parsed_string(), nparsed_obj);
+ obj->Set(env()->bytes_parsed_string(), nread_obj);
+#ifdef NODE_EXPERIMENTAL_HTTP
+ obj->Set(env()->code_string(),
+ OneByteString(env()->isolate(), llhttp_errno_name(err)));
+ obj->Set(env()->reason_string(),
+ OneByteString(env()->isolate(), parser_.reason));
+#else /* !NODE_EXPERIMENTAL_HTTP */
obj->Set(env()->code_string(),
OneByteString(env()->isolate(), http_errno_name(err)));
+#endif /* NODE_EXPERIMENTAL_HTTP */
return scope.Escape(e);
}
- return scope.Escape(nparsed_obj);
+
+ return scope.Escape(nread_obj);
}
Local<Array> CreateHeaders() {
@@ -684,8 +772,12 @@ class Parser : public AsyncWrap, public StreamListener {
}
- void Init(enum http_parser_type type) {
+ void Init(parser_type_t type) {
+#ifdef NODE_EXPERIMENTAL_HTTP
+ llhttp_init(&parser_, type, &settings);
+#else /* !NODE_EXPERIMENTAL_HTTP */
http_parser_init(&parser_, type);
+#endif /* NODE_EXPERIMENTAL_HTTP */
url_.Reset();
status_message_.Reset();
num_fields_ = 0;
@@ -695,7 +787,35 @@ class Parser : public AsyncWrap, public StreamListener {
}
- http_parser parser_;
+ int TrackHeader(size_t len) {
+#ifdef NODE_EXPERIMENTAL_HTTP
+ header_nread_ += len;
+ if (header_nread_ >= kMaxHeaderSize) {
+ llhttp_set_error_reason(&parser_, "Headers overflow");
+ return HPE_USER;
+ }
+#endif /* NODE_EXPERIMENTAL_HTTP */
+ return 0;
+ }
+
+
+ int MaybePause() {
+#ifdef NODE_EXPERIMENTAL_HTTP
+ CHECK_NE(execute_depth_, 0);
+
+ if (!pending_pause_) {
+ return 0;
+ }
+
+ pending_pause_ = false;
+ llhttp_set_error_reason(&parser_, "Paused in callback");
+ return HPE_PAUSED;
+#else /* !NODE_EXPERIMENTAL_HTTP */
+ return 0;
+#endif /* NODE_EXPERIMENTAL_HTTP */
+ }
+
+ parser_t parser_;
StringPtr fields_[32]; // header fields
StringPtr values_[32]; // header values
StringPtr url_;
@@ -707,25 +827,37 @@ class Parser : public AsyncWrap, public StreamListener {
Local<Object> current_buffer_;
size_t current_buffer_len_;
char* current_buffer_data_;
+#ifdef NODE_EXPERIMENTAL_HTTP
+ unsigned int execute_depth_ = 0;
+ bool pending_pause_ = false;
+ uint64_t header_nread_ = 0;
+#endif /* NODE_EXPERIMENTAL_HTTP */
// These are helper functions for filling `http_parser_settings`, which turn
// a member function of Parser into a C-style HTTP parser callback.
template <typename Parser, Parser> struct Proxy;
template <typename Parser, typename ...Args, int (Parser::*Member)(Args...)>
struct Proxy<int (Parser::*)(Args...), Member> {
- static int Raw(http_parser* p, Args ... args) {
+ static int Raw(parser_t* p, Args ... args) {
Parser* parser = ContainerOf(&Parser::parser_, p);
- return (parser->*Member)(std::forward<Args>(args)...);
+ int rv = (parser->*Member)(std::forward<Args>(args)...);
+ if (rv == 0) {
+ rv = parser->MaybePause();
+ }
+ return rv;
}
};
typedef int (Parser::*Call)();
typedef int (Parser::*DataCall)(const char* at, size_t length);
- static const struct http_parser_settings settings;
+ static const parser_settings_t settings;
+#ifdef NODE_EXPERIMENTAL_HTTP
+ static const uint64_t kMaxHeaderSize = 80 * 1024;
+#endif /* NODE_EXPERIMENTAL_HTTP */
};
-const struct http_parser_settings Parser::settings = {
+const parser_settings_t Parser::settings = {
Proxy<Call, &Parser::on_message_begin>::Raw,
Proxy<DataCall, &Parser::on_url>::Raw,
Proxy<DataCall, &Parser::on_status>::Raw,
@@ -734,8 +866,13 @@ const struct http_parser_settings Parser::settings = {
Proxy<Call, &Parser::on_headers_complete>::Raw,
Proxy<DataCall, &Parser::on_body>::Raw,
Proxy<Call, &Parser::on_message_complete>::Raw,
- nullptr, // on_chunk_header
- nullptr // on_chunk_complete
+#ifdef NODE_EXPERIMENTAL_HTTP
+ Proxy<Call, &Parser::on_chunk_header>::Raw,
+ Proxy<Call, &Parser::on_chunk_complete>::Raw,
+#else /* !NODE_EXPERIMENTAL_HTTP */
+ nullptr,
+ nullptr,
+#endif /* NODE_EXPERIMENTAL_HTTP */
};