Skip to content

Commit

Permalink
http2: convert Http2Settings to an AsyncWrap
Browse files Browse the repository at this point in the history
PR-URL: #17763
Refs: #17746
Reviewed-By: Matteo Collina <[email protected]>
  • Loading branch information
jasnell committed Dec 22, 2017
1 parent 6100e12 commit bbaea12
Show file tree
Hide file tree
Showing 11 changed files with 269 additions and 164 deletions.
57 changes: 31 additions & 26 deletions lib/internal/http2/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,23 +324,14 @@ function onStreamRead(nread, buf, handle) {

// Called when the remote peer settings have been updated.
// Resets the cached settings.
function onSettings(ack) {
function onSettings() {
const session = this[kOwner];
if (session.destroyed)
return;
session[kUpdateTimer]();
let event = 'remoteSettings';
if (ack) {
debug(`Http2Session ${sessionName(session[kType])}: settings acknowledged`);
if (session[kState].pendingAck > 0)
session[kState].pendingAck--;
session[kLocalSettings] = undefined;
event = 'localSettings';
} else {
debug(`Http2Session ${sessionName(session[kType])}: new settings received`);
session[kRemoteSettings] = undefined;
}
process.nextTick(emit, session, event, session[event]);
debug(`Http2Session ${sessionName(session[kType])}: new settings received`);
session[kRemoteSettings] = undefined;
process.nextTick(emit, session, 'remoteSettings', session.remoteSettings);
}

// If the stream exists, an attempt will be made to emit an event
Expand Down Expand Up @@ -540,15 +531,32 @@ function onSessionInternalError(code) {
this[kOwner].destroy(new NghttpError(code));
}

function settingsCallback(cb, ack, duration) {
this[kState].pendingAck--;
this[kLocalSettings] = undefined;
if (ack) {
debug(`Http2Session ${sessionName(this[kType])}: settings received`);
const settings = this.localSettings;
if (typeof cb === 'function')
cb(null, settings, duration);
this.emit('localSettings', settings);
} else {
debug(`Http2Session ${sessionName(this[kType])}: settings canceled`);
if (typeof cb === 'function')
cb(new errors.Error('ERR_HTTP2_SETTINGS_CANCEL'));
}
}

// Submits a SETTINGS frame to be sent to the remote peer.
function submitSettings(settings) {
function submitSettings(settings, callback) {
if (this.destroyed)
return;
debug(`Http2Session ${sessionName(this[kType])}: submitting settings`);
this[kUpdateTimer]();
this[kLocalSettings] = undefined;
updateSettingsBuffer(settings);
this[kHandle].settings();
if (!this[kHandle].settings(settingsCallback.bind(this, callback))) {
this.destroy(new errors.Error('ERR_HTTP2_MAX_PENDING_SETTINGS_ACK'));
}
}

// Submits a PRIORITY frame to be sent to the remote peer
Expand Down Expand Up @@ -783,7 +791,6 @@ class Http2Session extends EventEmitter {
streams: new Map(),
pendingStreams: new Set(),
pendingAck: 0,
maxPendingAck: Math.max(1, (options.maxPendingAck | 0) || 10),
writeQueueSize: 0
};

Expand Down Expand Up @@ -951,21 +958,19 @@ class Http2Session extends EventEmitter {
}

// Submits a SETTINGS frame to be sent to the remote peer.
settings(settings) {
settings(settings, callback) {
if (this.destroyed)
throw new errors.Error('ERR_HTTP2_INVALID_SESSION');

assertIsObject(settings, 'settings');
settings = validateSettings(settings);
const state = this[kState];
if (state.pendingAck === state.maxPendingAck) {
throw new errors.Error('ERR_HTTP2_MAX_PENDING_SETTINGS_ACK',
this[kState].pendingAck);
}

if (callback && typeof callback !== 'function')
throw new errors.TypeError('ERR_INVALID_CALLBACK');
debug(`Http2Session ${sessionName(this[kType])}: sending settings`);

state.pendingAck++;
const settingsFn = submitSettings.bind(this, settings);
this[kState].pendingAck++;

const settingsFn = submitSettings.bind(this, settings, callback);
if (this.connecting) {
this.once('connect', settingsFn);
return;
Expand Down
8 changes: 7 additions & 1 deletion lib/internal/http2/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ const IDX_OPTIONS_PEER_MAX_CONCURRENT_STREAMS = 3;
const IDX_OPTIONS_PADDING_STRATEGY = 4;
const IDX_OPTIONS_MAX_HEADER_LIST_PAIRS = 5;
const IDX_OPTIONS_MAX_OUTSTANDING_PINGS = 6;
const IDX_OPTIONS_FLAGS = 7;
const IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS = 7;
const IDX_OPTIONS_FLAGS = 8;

function updateOptionsBuffer(options) {
var flags = 0;
Expand Down Expand Up @@ -213,6 +214,11 @@ function updateOptionsBuffer(options) {
optionsBuffer[IDX_OPTIONS_MAX_OUTSTANDING_PINGS] =
options.maxOutstandingPings;
}
if (typeof options.maxOutstandingSettings === 'number') {
flags |= (1 << IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS);
optionsBuffer[IDX_OPTIONS_MAX_OUTSTANDING_SETTINGS] =
Math.max(1, options.maxOutstandingSettings);
}
optionsBuffer[IDX_OPTIONS_FLAGS] = flags;
}

Expand Down
1 change: 1 addition & 0 deletions src/async_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ namespace node {
V(HTTP2SESSION) \
V(HTTP2STREAM) \
V(HTTP2PING) \
V(HTTP2SETTINGS) \
V(HTTPPARSER) \
V(JSSTREAM) \
V(PIPECONNECTWRAP) \
Expand Down
1 change: 1 addition & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ class ModuleWrap;
V(host_import_module_dynamically_callback, v8::Function) \
V(http2ping_constructor_template, v8::ObjectTemplate) \
V(http2stream_constructor_template, v8::ObjectTemplate) \
V(http2settings_constructor_template, v8::ObjectTemplate) \
V(inspector_console_api_object, v8::Object) \
V(module_load_list_array, v8::Array) \
V(pbkdf2_constructor_template, v8::ObjectTemplate) \
Expand Down
Loading

0 comments on commit bbaea12

Please sign in to comment.