Skip to content

Commit 10576d6

Browse files
jasnellBethGriggs
authored andcommitted
http2: add ping event
Add a `Http2Session` event whenever a non-ack `PING` is received. Fixes: #18514 Backport-PR-URL: #22850 PR-URL: #23009 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Ujjwal Sharma <[email protected]> Reviewed-By: Anatoli Papirovski <[email protected]> Reviewed-By: Denys Otrishko <[email protected]>
1 parent ca933ce commit 10576d6

File tree

5 files changed

+82
-9
lines changed

5 files changed

+82
-9
lines changed

doc/api/http2.md

+10
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,16 @@ session.on('localSettings', (settings) => {
217217
});
218218
```
219219

220+
#### Event: 'ping'
221+
<!-- YAML
222+
added: REPLACEME
223+
-->
224+
225+
* `payload` {Buffer} The `PING` frame 8-byte payload
226+
227+
The `'ping'` event is emitted whenever a `PING` frame is received from the
228+
connected peer.
229+
220230
#### Event: 'remoteSettings'
221231
<!-- YAML
222232
added: v8.4.0

lib/internal/http2/core.js

+10
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,15 @@ function submitRstStream(code) {
287287
}
288288
}
289289

290+
function onPing(payload) {
291+
const session = this[kOwner];
292+
if (session.destroyed)
293+
return;
294+
session[kUpdateTimer]();
295+
debug(`Http2Session ${sessionName(session[kType])}: new ping received`);
296+
session.emit('ping', payload);
297+
}
298+
290299
// Called when the stream is closed either by sending or receiving an
291300
// RST_STREAM frame, or through a natural end-of-stream.
292301
// If the writable and readable sides of the stream are still open at this
@@ -803,6 +812,7 @@ function setupHandle(socket, type, options) {
803812
handle.error = onSessionInternalError;
804813
handle.onpriority = onPriority;
805814
handle.onsettings = onSettings;
815+
handle.onping = onPing;
806816
handle.onheaders = onSessionHeaders;
807817
handle.onframeerror = onFrameError;
808818
handle.ongoawaydata = onGoawayData;

src/env.h

+1
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ class ModuleWrap;
225225
V(onreadstart_string, "onreadstart") \
226226
V(onreadstop_string, "onreadstop") \
227227
V(onselect_string, "onselect") \
228+
V(onping_string, "onping") \
228229
V(onsettings_string, "onsettings") \
229230
V(onshutdown_string, "onshutdown") \
230231
V(onsignal_string, "onsignal") \

src/node_http2.cc

+13-9
Original file line numberDiff line numberDiff line change
@@ -1468,6 +1468,11 @@ void Http2Session::HandleOriginFrame(const nghttp2_frame* frame) {
14681468

14691469
// Called by OnFrameReceived when a complete PING frame has been received.
14701470
inline void Http2Session::HandlePingFrame(const nghttp2_frame* frame) {
1471+
Isolate* isolate = env()->isolate();
1472+
HandleScope scope(isolate);
1473+
Local<Context> context = env()->context();
1474+
Context::Scope context_scope(context);
1475+
Local<Value> arg;
14711476
bool ack = frame->hd.flags & NGHTTP2_FLAG_ACK;
14721477
if (ack) {
14731478
Http2Ping* ping = PopPing();
@@ -1479,16 +1484,15 @@ inline void Http2Session::HandlePingFrame(const nghttp2_frame* frame) {
14791484
// receive an unsolicited PING ack on a connection. Either the peer
14801485
// is buggy or malicious, and we're not going to tolerate such
14811486
// nonsense.
1482-
Isolate* isolate = env()->isolate();
1483-
HandleScope scope(isolate);
1484-
Local<Context> context = env()->context();
1485-
Context::Scope context_scope(context);
1486-
1487-
Local<Value> argv[1] = {
1488-
Integer::New(isolate, NGHTTP2_ERR_PROTO),
1489-
};
1490-
MakeCallback(env()->error_string(), arraysize(argv), argv);
1487+
arg = Integer::New(isolate, NGHTTP2_ERR_PROTO);
1488+
MakeCallback(env()->error_string(), 1, &arg);
14911489
}
1490+
} else {
1491+
// Notify the session that a ping occurred
1492+
arg = Buffer::Copy(env(),
1493+
reinterpret_cast<const char*>(frame->ping.opaque_data),
1494+
8).ToLocalChecked();
1495+
MakeCallback(env()->onping_string(), 1, &arg);
14921496
}
14931497
}
14941498

test/parallel/test-http2-onping.js

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'use strict';
2+
3+
const {
4+
hasCrypto,
5+
mustCall,
6+
skip
7+
} = require('../common');
8+
if (!hasCrypto)
9+
skip('missing crypto');
10+
11+
const {
12+
deepStrictEqual
13+
} = require('assert');
14+
const {
15+
createServer,
16+
connect
17+
} = require('http2');
18+
19+
const check = Buffer.from([ 1, 2, 3, 4, 5, 6, 7, 8 ]);
20+
21+
const server = createServer();
22+
server.on('stream', mustCall((stream) => {
23+
stream.respond();
24+
stream.end('ok');
25+
}));
26+
server.on('session', mustCall((session) => {
27+
session.on('ping', mustCall((payload) => {
28+
deepStrictEqual(check, payload);
29+
}));
30+
session.ping(check, mustCall());
31+
}));
32+
server.listen(0, mustCall(() => {
33+
const client = connect(`http://localhost:${server.address().port}`);
34+
35+
client.on('ping', mustCall((payload) => {
36+
deepStrictEqual(check, payload);
37+
}));
38+
client.on('connect', mustCall(() => {
39+
client.ping(check, mustCall());
40+
}));
41+
42+
const req = client.request();
43+
req.resume();
44+
req.on('close', mustCall(() => {
45+
client.close();
46+
server.close();
47+
}));
48+
}));

0 commit comments

Comments
 (0)