diff options
author | Gerhard Stoebich <18708370+Flarna@users.noreply.github.com> | 2019-04-23 00:57:12 +0200 |
---|---|---|
committer | Anna Henningsen <anna@addaleax.net> | 2019-05-03 16:02:55 +0200 |
commit | 8876ac5c358114f0f88424f6737ca4b89fc9e6c7 (patch) | |
tree | 5b0804517e873f3c08b236104b11f26dd752f941 /src | |
parent | 8dae89b396df64e6a9e44cb94efe27809a5a3d89 (diff) | |
download | android-node-v8-8876ac5c358114f0f88424f6737ca4b89fc9e6c7.tar.gz android-node-v8-8876ac5c358114f0f88424f6737ca4b89fc9e6c7.tar.bz2 android-node-v8-8876ac5c358114f0f88424f6737ca4b89fc9e6c7.zip |
async_hooks: fixup do not reuse HTTPParser
Fix some issues introduced/not fixed via
https://github.com/nodejs/node/pull/25094:
* Init hook is not emitted for a reused HTTPParser
* HTTPParser was still used as resource in init hook
* type used in init hook was always HTTPINCOMINGMESSAGE even for client
requests
* some tests have not been adapted to new resource names
With this change the async hooks init event is emitted during a call
to Initialize() as the type and resource object is available at this
time. As a result Initialize() must be called now which could be seen
as breaking change even HTTPParser is not part of documented API.
It was needed to put the ClientRequest instance into a wrapper object
instead passing it directly as async resource otherwise
test-domain-multi fails. I think this is because adding an EventEmitter
to a Domain adds a property 'domain' and the presence of this changes
the context propagation in domains.
Besides that tests still refering to resource HTTPParser have been
updated/improved.
Fixes: https://github.com/nodejs/node/issues/27467
Fixes: https://github.com/nodejs/node/issues/26961
Refs: https://github.com/nodejs/node/pull/25094
PR-URL: https://github.com/nodejs/node/pull/27477
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/async_wrap.cc | 31 | ||||
-rw-r--r-- | src/async_wrap.h | 17 | ||||
-rw-r--r-- | src/node_http_parser_impl.h | 18 |
3 files changed, 40 insertions, 26 deletions
diff --git a/src/async_wrap.cc b/src/async_wrap.cc index e822255265..0c84b06fdd 100644 --- a/src/async_wrap.cc +++ b/src/async_wrap.cc @@ -178,7 +178,7 @@ void AsyncWrap::EmitAfter(Environment* env, double async_id) { class PromiseWrap : public AsyncWrap { public: PromiseWrap(Environment* env, Local<Object> object, bool silent) - : AsyncWrap(env, object, PROVIDER_PROMISE, -1, silent) { + : AsyncWrap(env, object, PROVIDER_PROMISE, kInvalidAsyncId, silent) { MakeWeak(); } @@ -388,7 +388,7 @@ static void RegisterDestroyHook(const FunctionCallbackInfo<Value>& args) { void AsyncWrap::GetAsyncId(const FunctionCallbackInfo<Value>& args) { AsyncWrap* wrap; - args.GetReturnValue().Set(-1); + args.GetReturnValue().Set(kInvalidAsyncId); ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); args.GetReturnValue().Set(wrap->get_async_id()); } @@ -415,10 +415,15 @@ void AsyncWrap::AsyncReset(const FunctionCallbackInfo<Value>& args) { AsyncWrap* wrap; ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); double execution_async_id = - args[0]->IsNumber() ? args[0].As<Number>()->Value() : -1; + args[0]->IsNumber() ? args[0].As<Number>()->Value() : kInvalidAsyncId; wrap->AsyncReset(execution_async_id); } +void AsyncWrap::EmitDestroy() { + AsyncWrap::EmitDestroy(env(), async_id_); + // Ensure no double destroy is emitted via AsyncReset(). + async_id_ = kInvalidAsyncId; +} void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo<Value>& args) { CHECK(args[0]->IsNumber()); @@ -481,7 +486,7 @@ void AsyncWrap::Initialize(Local<Object> target, // kDefaultTriggerAsyncId: Write the id of the resource responsible for a // handle's creation just before calling the new handle's constructor. // After the new handle is constructed kDefaultTriggerAsyncId is set back - // to -1. + // to kInvalidAsyncId. FORCE_SET_TARGET_FIELD(target, "async_id_fields", env->async_hooks()->async_id_fields().GetJSArray()); @@ -569,10 +574,16 @@ AsyncWrap::AsyncWrap(Environment* env, AsyncReset(execution_async_id, silent); } +AsyncWrap::AsyncWrap(Environment* env, v8::Local<v8::Object> object) + : BaseObject(env, object), + provider_type_(PROVIDER_NONE) { + CHECK_GE(object->InternalFieldCount(), 1); +} + AsyncWrap::~AsyncWrap() { EmitTraceEventDestroy(); - EmitDestroy(env(), get_async_id()); + EmitDestroy(); } void AsyncWrap::EmitTraceEventDestroy() { @@ -612,16 +623,18 @@ void AsyncWrap::AsyncReset(double execution_async_id, bool silent) { // the resource is pulled out of the pool and put back into use. void AsyncWrap::AsyncReset(Local<Object> resource, double execution_async_id, bool silent) { - if (async_id_ != -1) { + CHECK_NE(provider_type(), PROVIDER_NONE); + + if (async_id_ != kInvalidAsyncId) { // This instance was in use before, we have already emitted an init with // its previous async_id and need to emit a matching destroy for that // before generating a new async_id. - EmitDestroy(env(), async_id_); + EmitDestroy(); } // Now we can assign a new async_id_ to this instance. - async_id_ = - execution_async_id == -1 ? env()->new_async_id() : execution_async_id; + async_id_ = execution_async_id == kInvalidAsyncId ? env()->new_async_id() + : execution_async_id; trigger_async_id_ = env()->get_default_trigger_async_id(); switch (provider_type()) { diff --git a/src/async_wrap.h b/src/async_wrap.h index bcd37bb0c0..20134f4a7b 100644 --- a/src/async_wrap.h +++ b/src/async_wrap.h @@ -109,12 +109,18 @@ class AsyncWrap : public BaseObject { AsyncWrap(Environment* env, v8::Local<v8::Object> object, ProviderType provider, - double execution_async_id = -1); + double execution_async_id = kInvalidAsyncId); + + // This constructor creates a reuseable instance where user is responsible + // to call set_provider_type() and AsyncReset() before use. + AsyncWrap(Environment* env, v8::Local<v8::Object> object); ~AsyncWrap() override; AsyncWrap() = delete; + static constexpr double kInvalidAsyncId = -1; + static v8::Local<v8::FunctionTemplate> GetConstructorTemplate( Environment* env); @@ -141,6 +147,8 @@ class AsyncWrap : public BaseObject { static void EmitAfter(Environment* env, double async_id); static void EmitPromiseResolve(Environment* env, double async_id); + void EmitDestroy(); + void EmitTraceEventBefore(); static void EmitTraceEventAfter(ProviderType type, double async_id); void EmitTraceEventDestroy(); @@ -155,10 +163,11 @@ class AsyncWrap : public BaseObject { inline double get_trigger_async_id() const; void AsyncReset(v8::Local<v8::Object> resource, - double execution_async_id = -1, + double execution_async_id = kInvalidAsyncId, bool silent = false); - void AsyncReset(double execution_async_id = -1, bool silent = false); + void AsyncReset(double execution_async_id = kInvalidAsyncId, + bool silent = false); // Only call these within a valid HandleScope. v8::MaybeLocal<v8::Value> MakeCallback(const v8::Local<v8::Function> cb, @@ -210,7 +219,7 @@ class AsyncWrap : public BaseObject { bool silent); ProviderType provider_type_; // Because the values may be Reset(), cannot be made const. - double async_id_ = -1; + double async_id_ = kInvalidAsyncId; double trigger_async_id_; }; diff --git a/src/node_http_parser_impl.h b/src/node_http_parser_impl.h index a8a8db5547..a354c6fcc5 100644 --- a/src/node_http_parser_impl.h +++ b/src/node_http_parser_impl.h @@ -154,14 +154,10 @@ struct StringPtr { class Parser : public AsyncWrap, public StreamListener { public: - Parser(Environment* env, Local<Object> wrap, parser_type_t type) - : AsyncWrap(env, wrap, - type == HTTP_REQUEST ? - AsyncWrap::PROVIDER_HTTPINCOMINGMESSAGE : - AsyncWrap::PROVIDER_HTTPCLIENTREQUEST), + Parser(Environment* env, Local<Object> wrap) + : AsyncWrap(env, wrap), current_buffer_len_(0), current_buffer_data_(nullptr) { - Init(type); } @@ -426,11 +422,7 @@ class Parser : public AsyncWrap, public StreamListener { static void New(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); - CHECK(args[0]->IsInt32()); - 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); + new Parser(env, args.This()); } @@ -443,14 +435,13 @@ class Parser : public AsyncWrap, public StreamListener { static void Free(const FunctionCallbackInfo<Value>& args) { - Environment* env = Environment::GetCurrent(args); Parser* parser; ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder()); // Since the Parser destructor isn't going to run the destroy() callbacks // it needs to be triggered manually. parser->EmitTraceEventDestroy(); - parser->EmitDestroy(env, parser->get_async_id()); + parser->EmitDestroy(); } @@ -526,6 +517,7 @@ class Parser : public AsyncWrap, public StreamListener { : AsyncWrap::PROVIDER_HTTPCLIENTREQUEST); parser->set_provider_type(provider); + parser->AsyncReset(args[1].As<Object>()); parser->Init(type); } |