diff options
author | Anna Henningsen <anna@addaleax.net> | 2019-08-10 00:51:51 +0200 |
---|---|---|
committer | Michaƫl Zasso <targos@protonmail.com> | 2019-08-15 09:50:22 +0200 |
commit | c44ee7a14a400c8bdc80b31848234f5f55351690 (patch) | |
tree | 9d9b4def9ffddcf56057caabcdf2212c55cce92d /src/node_http2.cc | |
parent | 8dae8d12dff4c3b6454fb36c91cef2f9f8d663df (diff) | |
download | android-node-v8-c44ee7a14a400c8bdc80b31848234f5f55351690.tar.gz android-node-v8-c44ee7a14a400c8bdc80b31848234f5f55351690.tar.bz2 android-node-v8-c44ee7a14a400c8bdc80b31848234f5f55351690.zip |
http2: only call into JS when necessary for session events
For some JS events, it only makes sense to call into JS when there
are listeners for the event in question.
The overhead is noticeable if a lot of these events are emitted during
the lifetime of a session. To reduce this overhead, keep track of
whether any/how many JS listeners are present, and if there are none,
skip calls into JS altogether.
This is part of performance improvements to mitigate CVE-2019-9513.
PR-URL: https://github.com/nodejs/node/pull/29122
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'src/node_http2.cc')
-rw-r--r-- | src/node_http2.cc | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/src/node_http2.cc b/src/node_http2.cc index 9d6c37373f..265d1ce357 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -25,6 +25,7 @@ using v8::ObjectTemplate; using v8::String; using v8::Uint32; using v8::Uint32Array; +using v8::Uint8Array; using v8::Undefined; using node::performance::PerformanceEntry; @@ -639,6 +640,15 @@ Http2Session::Http2Session(Environment* env, outgoing_storage_.reserve(4096); outgoing_buffers_.reserve(32); + + { + // Make the js_fields_ property accessible to JS land. + Local<ArrayBuffer> ab = + ArrayBuffer::New(env->isolate(), js_fields_, kSessionUint8FieldCount); + Local<Uint8Array> uint8_arr = + Uint8Array::New(ab, 0, kSessionUint8FieldCount); + USE(wrap->Set(env->context(), env->fields_string(), uint8_arr)); + } } Http2Session::~Http2Session() { @@ -1033,7 +1043,8 @@ int Http2Session::OnFrameNotSent(nghttp2_session* handle, // Do not report if the frame was not sent due to the session closing if (error_code == NGHTTP2_ERR_SESSION_CLOSING || error_code == NGHTTP2_ERR_STREAM_CLOSED || - error_code == NGHTTP2_ERR_STREAM_CLOSING) { + error_code == NGHTTP2_ERR_STREAM_CLOSING || + session->js_fields_[kSessionFrameErrorListenerCount] == 0) { return 0; } @@ -1316,6 +1327,7 @@ void Http2Session::HandleHeadersFrame(const nghttp2_frame* frame) { // are considered advisory only, so this has no real effect other than to // simply let user code know that the priority has changed. void Http2Session::HandlePriorityFrame(const nghttp2_frame* frame) { + if (js_fields_[kSessionPriorityListenerCount] == 0) return; Isolate* isolate = env()->isolate(); HandleScope scope(isolate); Local<Context> context = env()->context(); @@ -1380,6 +1392,7 @@ void Http2Session::HandleGoawayFrame(const nghttp2_frame* frame) { // Called by OnFrameReceived when a complete ALTSVC frame has been received. void Http2Session::HandleAltSvcFrame(const nghttp2_frame* frame) { + if (!(js_fields_[kBitfield] & (1 << kSessionHasAltsvcListeners))) return; Isolate* isolate = env()->isolate(); HandleScope scope(isolate); Local<Context> context = env()->context(); @@ -1458,6 +1471,7 @@ void Http2Session::HandlePingFrame(const nghttp2_frame* frame) { return; } + if (!(js_fields_[kBitfield] & (1 << kSessionHasPingListeners))) return; // Notify the session that a ping occurred arg = Buffer::Copy(env(), reinterpret_cast<const char*>(frame->ping.opaque_data), @@ -1469,6 +1483,9 @@ void Http2Session::HandlePingFrame(const nghttp2_frame* frame) { void Http2Session::HandleSettingsFrame(const nghttp2_frame* frame) { bool ack = frame->hd.flags & NGHTTP2_FLAG_ACK; if (!ack) { + js_fields_[kBitfield] &= ~(1 << kSessionRemoteSettingsIsUpToDate); + if (!(js_fields_[kBitfield] & (1 << kSessionHasRemoteSettingsListeners))) + return; // This is not a SETTINGS acknowledgement, notify and return MakeCallback(env()->http2session_on_settings_function(), 0, nullptr); return; @@ -2981,6 +2998,16 @@ void Initialize(Local<Object> target, NODE_DEFINE_CONSTANT(target, PADDING_BUF_MAX_PAYLOAD_LENGTH); NODE_DEFINE_CONSTANT(target, PADDING_BUF_RETURN_VALUE); + NODE_DEFINE_CONSTANT(target, kBitfield); + NODE_DEFINE_CONSTANT(target, kSessionPriorityListenerCount); + NODE_DEFINE_CONSTANT(target, kSessionFrameErrorListenerCount); + NODE_DEFINE_CONSTANT(target, kSessionUint8FieldCount); + + NODE_DEFINE_CONSTANT(target, kSessionHasRemoteSettingsListeners); + NODE_DEFINE_CONSTANT(target, kSessionRemoteSettingsIsUpToDate); + NODE_DEFINE_CONSTANT(target, kSessionHasPingListeners); + NODE_DEFINE_CONSTANT(target, kSessionHasAltsvcListeners); + // Method to fetch the nghttp2 string description of an nghttp2 error code env->SetMethod(target, "nghttp2ErrorString", HttpErrorString); |