diff options
author | James M Snell <jasnell@gmail.com> | 2018-09-22 00:14:04 +0300 |
---|---|---|
committer | Beth Griggs <Bethany.Griggs@uk.ibm.com> | 2018-10-17 02:07:24 +0300 |
commit | 10576d6e772eb4a0002d63327563cfb0a09625e5 (patch) | |
tree | 9ab8d65c856345e8130dc9aed573e7d352abf8eb | |
parent | ca933ce5778364b46d6a8ad6dd4dca456119b948 (diff) |
http2: add ping event
Add a `Http2Session` event whenever a non-ack `PING` is received.
Fixes: https://github.com/nodejs/node/issues/18514
Backport-PR-URL: https://github.com/nodejs/node/pull/22850
PR-URL: https://github.com/nodejs/node/pull/23009
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com>
Reviewed-By: Anatoli Papirovski <apapirovski@mac.com>
Reviewed-By: Denys Otrishko <shishugi@gmail.com>
-rw-r--r-- | doc/api/http2.md | 10 | ||||
-rw-r--r-- | lib/internal/http2/core.js | 10 | ||||
-rw-r--r-- | src/env.h | 1 | ||||
-rw-r--r-- | src/node_http2.cc | 22 | ||||
-rw-r--r-- | test/parallel/test-http2-onping.js | 48 |
5 files changed, 82 insertions, 9 deletions
diff --git a/doc/api/http2.md b/doc/api/http2.md index 349e2b9b710..ebb89c1bd4c 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -217,6 +217,16 @@ session.on('localSettings', (settings) => { }); ``` +#### Event: 'ping' +<!-- YAML +added: REPLACEME +--> + +* `payload` {Buffer} The `PING` frame 8-byte payload + +The `'ping'` event is emitted whenever a `PING` frame is received from the +connected peer. + #### Event: 'remoteSettings' <!-- YAML added: v8.4.0 diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index dadbaefa9ce..4c184fcfe18 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -287,6 +287,15 @@ function submitRstStream(code) { } } +function onPing(payload) { + const session = this[kOwner]; + if (session.destroyed) + return; + session[kUpdateTimer](); + debug(`Http2Session ${sessionName(session[kType])}: new ping received`); + session.emit('ping', payload); +} + // Called when the stream is closed either by sending or receiving an // RST_STREAM frame, or through a natural end-of-stream. // If the writable and readable sides of the stream are still open at this @@ -803,6 +812,7 @@ function setupHandle(socket, type, options) { handle.error = onSessionInternalError; handle.onpriority = onPriority; handle.onsettings = onSettings; + handle.onping = onPing; handle.onheaders = onSessionHeaders; handle.onframeerror = onFrameError; handle.ongoawaydata = onGoawayData; diff --git a/src/env.h b/src/env.h index 8afedb7044e..e378869b4cc 100644 --- a/src/env.h +++ b/src/env.h @@ -225,6 +225,7 @@ class ModuleWrap; V(onreadstart_string, "onreadstart") \ V(onreadstop_string, "onreadstop") \ V(onselect_string, "onselect") \ + V(onping_string, "onping") \ V(onsettings_string, "onsettings") \ V(onshutdown_string, "onshutdown") \ V(onsignal_string, "onsignal") \ diff --git a/src/node_http2.cc b/src/node_http2.cc index 3dad804aa48..49238dcae2d 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -1468,6 +1468,11 @@ void Http2Session::HandleOriginFrame(const nghttp2_frame* frame) { // Called by OnFrameReceived when a complete PING frame has been received. inline void Http2Session::HandlePingFrame(const nghttp2_frame* frame) { + Isolate* isolate = env()->isolate(); + HandleScope scope(isolate); + Local<Context> context = env()->context(); + Context::Scope context_scope(context); + Local<Value> arg; bool ack = frame->hd.flags & NGHTTP2_FLAG_ACK; if (ack) { Http2Ping* ping = PopPing(); @@ -1479,16 +1484,15 @@ inline void Http2Session::HandlePingFrame(const nghttp2_frame* frame) { // receive an unsolicited PING ack on a connection. Either the peer // is buggy or malicious, and we're not going to tolerate such // nonsense. - Isolate* isolate = env()->isolate(); - HandleScope scope(isolate); - Local<Context> context = env()->context(); - Context::Scope context_scope(context); - - Local<Value> argv[1] = { - Integer::New(isolate, NGHTTP2_ERR_PROTO), - }; - MakeCallback(env()->error_string(), arraysize(argv), argv); + arg = Integer::New(isolate, NGHTTP2_ERR_PROTO); + MakeCallback(env()->error_string(), 1, &arg); } + } else { + // Notify the session that a ping occurred + arg = Buffer::Copy(env(), + reinterpret_cast<const char*>(frame->ping.opaque_data), + 8).ToLocalChecked(); + MakeCallback(env()->onping_string(), 1, &arg); } } diff --git a/test/parallel/test-http2-onping.js b/test/parallel/test-http2-onping.js new file mode 100644 index 00000000000..134a94ddb8f --- /dev/null +++ b/test/parallel/test-http2-onping.js @@ -0,0 +1,48 @@ +'use strict'; + +const { + hasCrypto, + mustCall, + skip +} = require('../common'); +if (!hasCrypto) + skip('missing crypto'); + +const { + deepStrictEqual +} = require('assert'); +const { + createServer, + connect +} = require('http2'); + +const check = Buffer.from([ 1, 2, 3, 4, 5, 6, 7, 8 ]); + +const server = createServer(); +server.on('stream', mustCall((stream) => { + stream.respond(); + stream.end('ok'); +})); +server.on('session', mustCall((session) => { + session.on('ping', mustCall((payload) => { + deepStrictEqual(check, payload); + })); + session.ping(check, mustCall()); +})); +server.listen(0, mustCall(() => { + const client = connect(`http://localhost:${server.address().port}`); + + client.on('ping', mustCall((payload) => { + deepStrictEqual(check, payload); + })); + client.on('connect', mustCall(() => { + client.ping(check, mustCall()); + })); + + const req = client.request(); + req.resume(); + req.on('close', mustCall(() => { + client.close(); + server.close(); + })); +})); |