http2: add ping event
Add a `Http2Session` event whenever a non-ack `PING` is received. Fixes: https://github.com/nodejs/node/issues/18514 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>
This commit is contained in:
parent
c67d3d0c3c
commit
a0c1326257
@ -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'
|
#### Event: 'remoteSettings'
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
added: v8.4.0
|
added: v8.4.0
|
||||||
|
@ -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
|
// Called when the stream is closed either by sending or receiving an
|
||||||
// RST_STREAM frame, or through a natural end-of-stream.
|
// RST_STREAM frame, or through a natural end-of-stream.
|
||||||
// If the writable and readable sides of the stream are still open at this
|
// 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.error = onSessionInternalError;
|
||||||
handle.onpriority = onPriority;
|
handle.onpriority = onPriority;
|
||||||
handle.onsettings = onSettings;
|
handle.onsettings = onSettings;
|
||||||
|
handle.onping = onPing;
|
||||||
handle.onheaders = onSessionHeaders;
|
handle.onheaders = onSessionHeaders;
|
||||||
handle.onframeerror = onFrameError;
|
handle.onframeerror = onFrameError;
|
||||||
handle.ongoawaydata = onGoawayData;
|
handle.ongoawaydata = onGoawayData;
|
||||||
|
@ -229,6 +229,7 @@ struct PackageConfig {
|
|||||||
V(onread_string, "onread") \
|
V(onread_string, "onread") \
|
||||||
V(onreadstart_string, "onreadstart") \
|
V(onreadstart_string, "onreadstart") \
|
||||||
V(onreadstop_string, "onreadstop") \
|
V(onreadstop_string, "onreadstop") \
|
||||||
|
V(onping_string, "onping") \
|
||||||
V(onsettings_string, "onsettings") \
|
V(onsettings_string, "onsettings") \
|
||||||
V(onshutdown_string, "onshutdown") \
|
V(onshutdown_string, "onshutdown") \
|
||||||
V(onsignal_string, "onsignal") \
|
V(onsignal_string, "onsignal") \
|
||||||
|
@ -1457,6 +1457,11 @@ void Http2Session::HandleOriginFrame(const nghttp2_frame* frame) {
|
|||||||
|
|
||||||
// Called by OnFrameReceived when a complete PING frame has been received.
|
// Called by OnFrameReceived when a complete PING frame has been received.
|
||||||
void Http2Session::HandlePingFrame(const nghttp2_frame* frame) {
|
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;
|
bool ack = frame->hd.flags & NGHTTP2_FLAG_ACK;
|
||||||
if (ack) {
|
if (ack) {
|
||||||
Http2Ping* ping = PopPing();
|
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
|
// receive an unsolicited PING ack on a connection. Either the peer
|
||||||
// is buggy or malicious, and we're not going to tolerate such
|
// is buggy or malicious, and we're not going to tolerate such
|
||||||
// nonsense.
|
// nonsense.
|
||||||
Isolate* isolate = env()->isolate();
|
arg = Integer::New(isolate, NGHTTP2_ERR_PROTO);
|
||||||
HandleScope scope(isolate);
|
|
||||||
Local<Context> context = env()->context();
|
|
||||||
Context::Scope context_scope(context);
|
|
||||||
Local<Value> arg = Integer::New(isolate, NGHTTP2_ERR_PROTO);
|
|
||||||
MakeCallback(env()->error_string(), 1, &arg);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
48
test/parallel/test-http2-onping.js
Normal file
48
test/parallel/test-http2-onping.js
Normal file
@ -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();
|
||||||
|
}));
|
||||||
|
}));
|
Loading…
x
Reference in New Issue
Block a user