summaryrefslogtreecommitdiff
path: root/src/node_http2.cc
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2019-08-10 00:51:51 +0200
committerMichaƫl Zasso <targos@protonmail.com>2019-08-15 09:50:22 +0200
commitc44ee7a14a400c8bdc80b31848234f5f55351690 (patch)
tree9d9b4def9ffddcf56057caabcdf2212c55cce92d /src/node_http2.cc
parent8dae8d12dff4c3b6454fb36c91cef2f9f8d663df (diff)
downloadandroid-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.cc29
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);