Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http2: add Http2Session.lastReceivedTime #23010

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions doc/api/http2.md
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,18 @@ added: v9.4.0
Transmits a `GOAWAY` frame to the connected peer *without* shutting down the
`Http2Session`.

#### http2session.getLastReceivedTime()
<!-- YAML
added: REPLACEME
-->

* Returns: {number}

Returns a timestamp indicating the moment the most recently received
communication of any kind was received from the connected peer. A value of `0`
indicates that the session is still open but no data has yet been received.
A value of `undefined` indicates that the session is no longer valid.

#### http2session.localSettings
<!-- YAML
added: v8.4.0
Expand Down
4 changes: 4 additions & 0 deletions lib/internal/http2/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,10 @@ class Http2Session extends EventEmitter {
return !!(this[kState].flags & SESSION_FLAGS_DESTROYED);
}

getLastReceivedTime() {
return !this.destroyed ? this[kHandle].getLastReceivedTime() : undefined;
}

// Resets the timeout counter
[kUpdateTimer]() {
if (this.destroyed)
Expand Down
11 changes: 11 additions & 0 deletions src/node_http2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,14 @@ ssize_t Http2Session::OnCallbackPadding(size_t frameLen,
return retval;
}

// last_received_ts_ tracks the last time data was received by this
// Http2Session object from the underlying i/o
void Http2Session::GetLastReceivedTime(
const FunctionCallbackInfo<Value>& args) {
Http2Session* session;
ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
args.GetReturnValue().Set(session->LastReceivedTime());
}

// Write data received from the i/o stream to the underlying nghttp2_session.
// On each call to nghttp2_session_mem_recv, nghttp2 will begin calling the
Expand All @@ -866,6 +874,7 @@ ssize_t Http2Session::Write(const uv_buf_t* bufs, size_t nbufs) {
// Note that nghttp2_session_mem_recv is a synchronous operation that
// will trigger a number of other callbacks. Those will, in turn have
// multiple side effects.
last_received_ts_ = uv_hrtime();
for (size_t n = 0; n < nbufs; n++) {
Debug(this, "receiving %d bytes [wants data? %d]",
bufs[n].len,
Expand Down Expand Up @@ -2987,6 +2996,8 @@ void Initialize(Local<Object> target,
session->SetClassName(http2SessionClassName);
session->InstanceTemplate()->SetInternalFieldCount(1);
AsyncWrap::AddWrapMethods(env, session);
env->SetProtoMethod(session, "getLastReceivedTime",
Http2Session::GetLastReceivedTime);
env->SetProtoMethod(session, "origin", Http2Session::Origin);
env->SetProtoMethod(session, "altsvc", Http2Session::AltSvc);
env->SetProtoMethod(session, "ping", Http2Session::Ping);
Expand Down
5 changes: 5 additions & 0 deletions src/node_http2.h
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,7 @@ class Http2Session : public AsyncWrap, public StreamListener {
static void Ping(const FunctionCallbackInfo<Value>& args);
static void AltSvc(const FunctionCallbackInfo<Value>& args);
static void Origin(const FunctionCallbackInfo<Value>& args);
static void GetLastReceivedTime(const FunctionCallbackInfo<Value>& args);

template <get_setting fn>
static void RefreshSettings(const FunctionCallbackInfo<Value>& args);
Expand Down Expand Up @@ -828,6 +829,8 @@ class Http2Session : public AsyncWrap, public StreamListener {
// this session now, and may outlive it.
void StopTrackingRcbuf(nghttp2_rcbuf* buf);

double LastReceivedTime() { return last_received_ts_ / 1e6; }

// Returns the current session memory including memory allocated by nghttp2,
// the current outbound storage queue, and pending writes.
uint64_t GetCurrentSessionMemory() {
Expand Down Expand Up @@ -992,6 +995,8 @@ class Http2Session : public AsyncWrap, public StreamListener {
std::vector<uint8_t> outgoing_storage_;
std::vector<int32_t> pending_rst_streams_;

uint64_t last_received_ts_ = 0;

void CopyDataIntoOutgoing(const uint8_t* src, size_t src_length);
void ClearOutgoing(int status);

Expand Down
35 changes: 35 additions & 0 deletions test/parallel/test-http2-session-lastreceivedtime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use strict';

const {
hasCrypto,
mustCall,
skip
} = require('../common');
if (!hasCrypto)
skip('missing crypto');
const {
createServer,
connect
} = require('http2');
const assert = require('assert');

const server = createServer();
server.on('stream', mustCall((stream) => {
assert(stream.session.getLastReceivedTime() > 0);
stream.respond();
stream.end('ok');
}));

server.listen(0, mustCall(() => {
const client = connect(`http://localhost:${server.address().port}`);

const req = client.request();
req.on('response', mustCall(() => {
assert(client.getLastReceivedTime() > 0);
}));
req.resume();
req.on('close', mustCall(() => {
server.close();
client.close();
}));
}));