Skip to content

Commit dfe5684

Browse files
jasnellcjihrig
authored andcommitted
http2: refactor settings handling
Add `Http2Seettings` utility class for handling settings logic and reducing code duplication. PR-URL: #16668 Reviewed-By: Sebastiaan Deckers <[email protected]> Reviewed-By: Anatoli Papirovski <[email protected]> Reviewed-By: Khaidi Chu <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
1 parent 26f1a1d commit dfe5684

File tree

3 files changed

+167
-170
lines changed

3 files changed

+167
-170
lines changed

lib/internal/http2/util.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -255,9 +255,9 @@ function getDefaultSettings() {
255255
function getSettings(session, remote) {
256256
const holder = Object.create(null);
257257
if (remote)
258-
binding.refreshRemoteSettings(session);
258+
session.refreshRemoteSettings();
259259
else
260-
binding.refreshLocalSettings(session);
260+
session.refreshLocalSettings();
261261

262262
holder.headerTableSize =
263263
settingsBuffer[IDX_SETTINGS_HEADER_TABLE_SIZE];

src/node_http2.cc

+126-164
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,117 @@ Http2Options::Http2Options(Environment* env) {
6969
}
7070
}
7171

72+
Http2Settings::Http2Settings(Environment* env) : env_(env) {
73+
entries_.AllocateSufficientStorage(IDX_SETTINGS_COUNT);
74+
AliasedBuffer<uint32_t, v8::Uint32Array>& buffer =
75+
env->http2_state()->settings_buffer;
76+
uint32_t flags = buffer[IDX_SETTINGS_COUNT];
77+
78+
size_t n = 0;
79+
80+
if (flags & (1 << IDX_SETTINGS_HEADER_TABLE_SIZE)) {
81+
uint32_t val = buffer[IDX_SETTINGS_HEADER_TABLE_SIZE];
82+
DEBUG_HTTP2("Setting header table size: %d\n", val);
83+
entries_[n].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
84+
entries_[n].value = val;
85+
n++;
86+
}
87+
88+
if (flags & (1 << IDX_SETTINGS_MAX_CONCURRENT_STREAMS)) {
89+
uint32_t val = buffer[IDX_SETTINGS_MAX_CONCURRENT_STREAMS];
90+
DEBUG_HTTP2("Setting max concurrent streams: %d\n", val);
91+
entries_[n].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
92+
entries_[n].value = val;
93+
n++;
94+
}
95+
96+
if (flags & (1 << IDX_SETTINGS_MAX_FRAME_SIZE)) {
97+
uint32_t val = buffer[IDX_SETTINGS_MAX_FRAME_SIZE];
98+
DEBUG_HTTP2("Setting max frame size: %d\n", val);
99+
entries_[n].settings_id = NGHTTP2_SETTINGS_MAX_FRAME_SIZE;
100+
entries_[n].value = val;
101+
n++;
102+
}
103+
104+
if (flags & (1 << IDX_SETTINGS_INITIAL_WINDOW_SIZE)) {
105+
uint32_t val = buffer[IDX_SETTINGS_INITIAL_WINDOW_SIZE];
106+
DEBUG_HTTP2("Setting initial window size: %d\n", val);
107+
entries_[n].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
108+
entries_[n].value = val;
109+
n++;
110+
}
111+
112+
if (flags & (1 << IDX_SETTINGS_MAX_HEADER_LIST_SIZE)) {
113+
uint32_t val = buffer[IDX_SETTINGS_MAX_HEADER_LIST_SIZE];
114+
DEBUG_HTTP2("Setting max header list size: %d\n", val);
115+
entries_[n].settings_id = NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE;
116+
entries_[n].value = val;
117+
n++;
118+
}
119+
120+
if (flags & (1 << IDX_SETTINGS_ENABLE_PUSH)) {
121+
uint32_t val = buffer[IDX_SETTINGS_ENABLE_PUSH];
122+
DEBUG_HTTP2("Setting enable push: %d\n", val);
123+
entries_[n].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
124+
entries_[n].value = val;
125+
n++;
126+
}
127+
128+
count_ = n;
129+
}
130+
131+
inline Local<Value> Http2Settings::Pack() {
132+
const size_t len = count_ * 6;
133+
Local<Value> buf = Buffer::New(env_, len).ToLocalChecked();
134+
ssize_t ret =
135+
nghttp2_pack_settings_payload(
136+
reinterpret_cast<uint8_t*>(Buffer::Data(buf)), len,
137+
*entries_, count_);
138+
if (ret >= 0)
139+
return buf;
140+
else
141+
return Undefined(env_->isolate());
142+
}
143+
144+
inline void Http2Settings::Update(Environment* env,
145+
Http2Session* session,
146+
get_setting fn) {
147+
AliasedBuffer<uint32_t, v8::Uint32Array>& buffer =
148+
env->http2_state()->settings_buffer;
149+
buffer[IDX_SETTINGS_HEADER_TABLE_SIZE] =
150+
fn(session->session(), NGHTTP2_SETTINGS_HEADER_TABLE_SIZE);
151+
buffer[IDX_SETTINGS_MAX_CONCURRENT_STREAMS] =
152+
fn(session->session(), NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
153+
buffer[IDX_SETTINGS_INITIAL_WINDOW_SIZE] =
154+
fn(session->session(), NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE);
155+
buffer[IDX_SETTINGS_MAX_FRAME_SIZE] =
156+
fn(session->session(), NGHTTP2_SETTINGS_MAX_FRAME_SIZE);
157+
buffer[IDX_SETTINGS_MAX_HEADER_LIST_SIZE] =
158+
fn(session->session(), NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE);
159+
buffer[IDX_SETTINGS_ENABLE_PUSH] =
160+
fn(session->session(), NGHTTP2_SETTINGS_ENABLE_PUSH);
161+
}
162+
163+
164+
inline void Http2Settings::RefreshDefaults(Environment* env) {
165+
AliasedBuffer<uint32_t, v8::Uint32Array>& buffer =
166+
env->http2_state()->settings_buffer;
167+
168+
buffer[IDX_SETTINGS_HEADER_TABLE_SIZE] =
169+
DEFAULT_SETTINGS_HEADER_TABLE_SIZE;
170+
buffer[IDX_SETTINGS_ENABLE_PUSH] =
171+
DEFAULT_SETTINGS_ENABLE_PUSH;
172+
buffer[IDX_SETTINGS_INITIAL_WINDOW_SIZE] =
173+
DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE;
174+
buffer[IDX_SETTINGS_MAX_FRAME_SIZE] =
175+
DEFAULT_SETTINGS_MAX_FRAME_SIZE;
176+
buffer[IDX_SETTINGS_COUNT] =
177+
(1 << IDX_SETTINGS_HEADER_TABLE_SIZE) |
178+
(1 << IDX_SETTINGS_ENABLE_PUSH) |
179+
(1 << IDX_SETTINGS_INITIAL_WINDOW_SIZE) |
180+
(1 << IDX_SETTINGS_MAX_FRAME_SIZE);
181+
}
182+
72183

73184
Http2Session::Http2Session(Environment* env,
74185
Local<Object> wrap,
@@ -178,119 +289,24 @@ void HttpErrorString(const FunctionCallbackInfo<Value>& args) {
178289
// output for an HTTP2-Settings header field.
179290
void PackSettings(const FunctionCallbackInfo<Value>& args) {
180291
Environment* env = Environment::GetCurrent(args);
181-
HandleScope scope(env->isolate());
182-
183-
std::vector<nghttp2_settings_entry> entries;
184-
entries.reserve(6);
185-
186-
AliasedBuffer<uint32_t, v8::Uint32Array>& buffer =
187-
env->http2_state()->settings_buffer;
188-
uint32_t flags = buffer[IDX_SETTINGS_COUNT];
189-
190-
if (flags & (1 << IDX_SETTINGS_HEADER_TABLE_SIZE)) {
191-
DEBUG_HTTP2("Setting header table size: %d\n",
192-
static_cast<uint32_t>(buffer[IDX_SETTINGS_HEADER_TABLE_SIZE]));
193-
entries.push_back({NGHTTP2_SETTINGS_HEADER_TABLE_SIZE,
194-
buffer[IDX_SETTINGS_HEADER_TABLE_SIZE]});
195-
}
196-
197-
if (flags & (1 << IDX_SETTINGS_MAX_CONCURRENT_STREAMS)) {
198-
DEBUG_HTTP2("Setting max concurrent streams: %d\n",
199-
static_cast<uint32_t>(
200-
buffer[IDX_SETTINGS_MAX_CONCURRENT_STREAMS]));
201-
entries.push_back({NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
202-
buffer[IDX_SETTINGS_MAX_CONCURRENT_STREAMS]});
203-
}
204-
205-
if (flags & (1 << IDX_SETTINGS_MAX_FRAME_SIZE)) {
206-
DEBUG_HTTP2("Setting max frame size: %d\n",
207-
static_cast<uint32_t>(buffer[IDX_SETTINGS_MAX_FRAME_SIZE]));
208-
entries.push_back({NGHTTP2_SETTINGS_MAX_FRAME_SIZE,
209-
buffer[IDX_SETTINGS_MAX_FRAME_SIZE]});
210-
}
211-
212-
if (flags & (1 << IDX_SETTINGS_INITIAL_WINDOW_SIZE)) {
213-
DEBUG_HTTP2("Setting initial window size: %d\n",
214-
static_cast<uint32_t>(
215-
buffer[IDX_SETTINGS_INITIAL_WINDOW_SIZE]));
216-
entries.push_back({NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
217-
buffer[IDX_SETTINGS_INITIAL_WINDOW_SIZE]});
218-
}
219-
220-
if (flags & (1 << IDX_SETTINGS_MAX_HEADER_LIST_SIZE)) {
221-
DEBUG_HTTP2("Setting max header list size: %d\n",
222-
static_cast<uint32_t>(
223-
buffer[IDX_SETTINGS_MAX_HEADER_LIST_SIZE]));
224-
entries.push_back({NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
225-
buffer[IDX_SETTINGS_MAX_HEADER_LIST_SIZE]});
226-
}
227-
228-
if (flags & (1 << IDX_SETTINGS_ENABLE_PUSH)) {
229-
DEBUG_HTTP2("Setting enable push: %d\n",
230-
static_cast<uint32_t>(buffer[IDX_SETTINGS_ENABLE_PUSH]));
231-
entries.push_back({NGHTTP2_SETTINGS_ENABLE_PUSH,
232-
buffer[IDX_SETTINGS_ENABLE_PUSH]});
233-
}
234-
235-
const size_t len = entries.size() * 6;
236-
MaybeStackBuffer<char> buf(len);
237-
ssize_t ret =
238-
nghttp2_pack_settings_payload(
239-
reinterpret_cast<uint8_t*>(*buf), len, &entries[0], entries.size());
240-
if (ret >= 0) {
241-
args.GetReturnValue().Set(
242-
Buffer::Copy(env, *buf, len).ToLocalChecked());
243-
}
292+
Http2Settings settings(env);
293+
args.GetReturnValue().Set(settings.Pack());
244294
}
245295

246296
// Used to fill in the spec defined initial values for each setting.
247297
void RefreshDefaultSettings(const FunctionCallbackInfo<Value>& args) {
248298
DEBUG_HTTP2("Http2Session: refreshing default settings\n");
249299
Environment* env = Environment::GetCurrent(args);
250-
AliasedBuffer<uint32_t, v8::Uint32Array>& buffer =
251-
env->http2_state()->settings_buffer;
252-
253-
buffer[IDX_SETTINGS_HEADER_TABLE_SIZE] =
254-
DEFAULT_SETTINGS_HEADER_TABLE_SIZE;
255-
buffer[IDX_SETTINGS_ENABLE_PUSH] =
256-
DEFAULT_SETTINGS_ENABLE_PUSH;
257-
buffer[IDX_SETTINGS_INITIAL_WINDOW_SIZE] =
258-
DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE;
259-
buffer[IDX_SETTINGS_MAX_FRAME_SIZE] =
260-
DEFAULT_SETTINGS_MAX_FRAME_SIZE;
261-
buffer[IDX_SETTINGS_COUNT] =
262-
(1 << IDX_SETTINGS_HEADER_TABLE_SIZE) |
263-
(1 << IDX_SETTINGS_ENABLE_PUSH) |
264-
(1 << IDX_SETTINGS_INITIAL_WINDOW_SIZE) |
265-
(1 << IDX_SETTINGS_MAX_FRAME_SIZE);
300+
Http2Settings::RefreshDefaults(env);
266301
}
267302

268303
template <get_setting fn>
269-
void RefreshSettings(const FunctionCallbackInfo<Value>& args) {
304+
void Http2Session::RefreshSettings(const FunctionCallbackInfo<Value>& args) {
270305
DEBUG_HTTP2("Http2Session: refreshing settings for session\n");
271306
Environment* env = Environment::GetCurrent(args);
272-
#if defined(DEBUG) && DEBUG
273-
CHECK_EQ(args.Length(), 1);
274-
CHECK(args[0]->IsObject());
275-
#endif
276307
Http2Session* session;
277-
ASSIGN_OR_RETURN_UNWRAP(&session, args[0].As<Object>());
278-
nghttp2_session* s = session->session();
279-
280-
AliasedBuffer<uint32_t, v8::Uint32Array>& buffer =
281-
env->http2_state()->settings_buffer;
282-
buffer[IDX_SETTINGS_HEADER_TABLE_SIZE] =
283-
fn(s, NGHTTP2_SETTINGS_HEADER_TABLE_SIZE);
284-
buffer[IDX_SETTINGS_MAX_CONCURRENT_STREAMS] =
285-
fn(s, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
286-
buffer[IDX_SETTINGS_INITIAL_WINDOW_SIZE] =
287-
fn(s, NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE);
288-
buffer[IDX_SETTINGS_MAX_FRAME_SIZE] =
289-
fn(s, NGHTTP2_SETTINGS_MAX_FRAME_SIZE);
290-
buffer[IDX_SETTINGS_MAX_HEADER_LIST_SIZE] =
291-
fn(s, NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE);
292-
buffer[IDX_SETTINGS_ENABLE_PUSH] =
293-
fn(s, NGHTTP2_SETTINGS_ENABLE_PUSH);
308+
ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
309+
Http2Settings::Update(env, session, fn);
294310
}
295311

296312
// Used to fill in the spec defined initial values for each setting.
@@ -460,65 +476,9 @@ void Http2Session::SubmitSettings(const FunctionCallbackInfo<Value>& args) {
460476
ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
461477
Environment* env = session->env();
462478

463-
AliasedBuffer<uint32_t, v8::Uint32Array>& buffer =
464-
env->http2_state()->settings_buffer;
465-
uint32_t flags = buffer[IDX_SETTINGS_COUNT];
466-
467-
std::vector<nghttp2_settings_entry> entries;
468-
entries.reserve(6);
469-
470-
if (flags & (1 << IDX_SETTINGS_HEADER_TABLE_SIZE)) {
471-
DEBUG_HTTP2("Setting header table size: %d\n",
472-
static_cast<uint32_t>(buffer[IDX_SETTINGS_HEADER_TABLE_SIZE]));
473-
entries.push_back({NGHTTP2_SETTINGS_HEADER_TABLE_SIZE,
474-
buffer[IDX_SETTINGS_HEADER_TABLE_SIZE]});
475-
}
476-
477-
if (flags & (1 << IDX_SETTINGS_MAX_CONCURRENT_STREAMS)) {
478-
DEBUG_HTTP2("Setting max concurrent streams: %d\n",
479-
static_cast<uint32_t>(
480-
buffer[IDX_SETTINGS_MAX_CONCURRENT_STREAMS]));
481-
entries.push_back({NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
482-
buffer[IDX_SETTINGS_MAX_CONCURRENT_STREAMS]});
483-
}
484-
485-
if (flags & (1 << IDX_SETTINGS_MAX_FRAME_SIZE)) {
486-
DEBUG_HTTP2("Setting max frame size: %d\n",
487-
static_cast<uint32_t>(buffer[IDX_SETTINGS_MAX_FRAME_SIZE]));
488-
entries.push_back({NGHTTP2_SETTINGS_MAX_FRAME_SIZE,
489-
buffer[IDX_SETTINGS_MAX_FRAME_SIZE]});
490-
}
491-
492-
if (flags & (1 << IDX_SETTINGS_INITIAL_WINDOW_SIZE)) {
493-
DEBUG_HTTP2("Setting initial window size: %d\n",
494-
static_cast<uint32_t>(
495-
buffer[IDX_SETTINGS_INITIAL_WINDOW_SIZE]));
496-
entries.push_back({NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
497-
buffer[IDX_SETTINGS_INITIAL_WINDOW_SIZE]});
498-
}
499-
500-
if (flags & (1 << IDX_SETTINGS_MAX_HEADER_LIST_SIZE)) {
501-
DEBUG_HTTP2("Setting max header list size: %d\n",
502-
static_cast<uint32_t>(
503-
buffer[IDX_SETTINGS_MAX_HEADER_LIST_SIZE]));
504-
entries.push_back({NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
505-
buffer[IDX_SETTINGS_MAX_HEADER_LIST_SIZE]});
506-
}
507-
508-
if (flags & (1 << IDX_SETTINGS_ENABLE_PUSH)) {
509-
DEBUG_HTTP2("Setting enable push: %d\n",
510-
static_cast<uint32_t>(buffer[IDX_SETTINGS_ENABLE_PUSH]));
511-
entries.push_back({NGHTTP2_SETTINGS_ENABLE_PUSH,
512-
buffer[IDX_SETTINGS_ENABLE_PUSH]});
513-
}
514-
515-
if (entries.size() > 0) {
516-
args.GetReturnValue().Set(
517-
session->Nghttp2Session::SubmitSettings(&entries[0], entries.size()));
518-
} else {
519-
args.GetReturnValue().Set(
520-
session->Nghttp2Session::SubmitSettings(nullptr, 0));
521-
}
479+
Http2Settings settings(env);
480+
args.GetReturnValue().Set(
481+
session->Nghttp2Session::SubmitSettings(*settings, settings.length()));
522482
}
523483

524484
void Http2Session::SubmitRstStream(const FunctionCallbackInfo<Value>& args) {
@@ -1327,6 +1287,12 @@ void Initialize(Local<Object> target,
13271287
Http2Session::FlushData);
13281288
env->SetProtoMethod(session, "updateChunksSent",
13291289
Http2Session::UpdateChunksSent);
1290+
env->SetProtoMethod(
1291+
session, "refreshLocalSettings",
1292+
Http2Session::RefreshSettings<nghttp2_session_get_local_settings>);
1293+
env->SetProtoMethod(
1294+
session, "refreshRemoteSettings",
1295+
Http2Session::RefreshSettings<nghttp2_session_get_remote_settings>);
13301296
StreamBase::AddMethods<Http2Session>(env, session,
13311297
StreamBase::kFlagHasWritev |
13321298
StreamBase::kFlagNoShutdown);
@@ -1416,10 +1382,6 @@ HTTP_KNOWN_METHODS(STRING_CONSTANT)
14161382
HTTP_STATUS_CODES(V)
14171383
#undef V
14181384

1419-
env->SetMethod(target, "refreshLocalSettings",
1420-
RefreshSettings<nghttp2_session_get_local_settings>);
1421-
env->SetMethod(target, "refreshRemoteSettings",
1422-
RefreshSettings<nghttp2_session_get_remote_settings>);
14231385
env->SetMethod(target, "refreshDefaultSettings", RefreshDefaultSettings);
14241386
env->SetMethod(target, "refreshSessionState", RefreshSessionState);
14251387
env->SetMethod(target, "refreshStreamState", RefreshStreamState);

0 commit comments

Comments
 (0)