Permalink
Browse files

http2: add ping event

Add a `Http2Session` event whenever a non-ack `PING` is received.

Fixes: #18514

PR-URL: #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>
  • Loading branch information...
jasnell committed Sep 21, 2018
1 parent c67d3d0 commit a0c1326257b9679b056d8611ccdee2d6757b0bf0
Showing with 81 additions and 5 deletions.
  1. +10 −0 doc/api/http2.md
  2. +10 −0 lib/internal/http2/core.js
  3. +1 −0 src/env.h
  4. +12 −5 src/node_http2.cc
  5. +48 −0 test/parallel/test-http2-onping.js
View
@@ -222,6 +222,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
View
@@ -346,6 +346,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
@@ -821,6 +830,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;
View
@@ -229,6 +229,7 @@ struct PackageConfig {
V(onread_string, "onread") \
V(onreadstart_string, "onreadstart") \
V(onreadstop_string, "onreadstop") \
V(onping_string, "onping") \
V(onsettings_string, "onsettings") \
V(onshutdown_string, "onshutdown") \
V(onsignal_string, "onsignal") \
View
@@ -1457,6 +1457,11 @@ void Http2Session::HandleOriginFrame(const nghttp2_frame* frame) {
// Called by OnFrameReceived when a complete PING frame has been received.
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();
@@ -1468,13 +1473,15 @@ 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> arg = Integer::New(isolate, NGHTTP2_ERR_PROTO);
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);
}
}
@@ -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();
}));
}));

0 comments on commit a0c1326

Please sign in to comment.