Skip to content

Commit a0a14c8

Browse files
addaleaxBethGriggs
authored andcommitted
src: pass along errors from http2 object creation
[This backport applied to v10.x cleanly.] Backport-PR-URL: #29123 PR-URL: #25822 Reviewed-By: Gireesh Punathil <[email protected]>
1 parent 00f153d commit a0a14c8

File tree

2 files changed

+87
-62
lines changed

2 files changed

+87
-62
lines changed

src/node_http2.cc

+71-54
Original file line numberDiff line numberDiff line change
@@ -228,27 +228,18 @@ void Http2Session::Http2Settings::Init() {
228228
count_ = n;
229229
}
230230

231-
Http2Session::Http2Settings::Http2Settings(Environment* env,
232-
Http2Session* session, uint64_t start_time)
233-
: AsyncWrap(env,
234-
env->http2settings_constructor_template()
235-
->NewInstance(env->context())
236-
.ToLocalChecked(),
237-
PROVIDER_HTTP2SETTINGS),
238-
session_(session),
239-
startTime_(start_time) {
240-
Init();
241-
}
242-
243-
244-
Http2Session::Http2Settings::Http2Settings(Environment* env)
245-
: Http2Settings(env, nullptr, 0) {}
246-
247231
// The Http2Settings class is used to configure a SETTINGS frame that is
248232
// to be sent to the connected peer. The settings are set using a TypedArray
249233
// that is shared with the JavaScript side.
250-
Http2Session::Http2Settings::Http2Settings(Http2Session* session)
251-
: Http2Settings(session->env(), session, uv_hrtime()) {}
234+
Http2Session::Http2Settings::Http2Settings(Environment* env,
235+
Http2Session* session,
236+
Local<Object> obj,
237+
uint64_t start_time)
238+
: AsyncWrap(env, obj, PROVIDER_HTTP2SETTINGS),
239+
session_(session),
240+
startTime_(start_time) {
241+
Init();
242+
}
252243

253244
// Generates a Buffer that contains the serialized payload of a SETTINGS
254245
// frame. This can be used, for instance, to create the Base64-encoded
@@ -916,13 +907,14 @@ int Http2Session::OnBeginHeadersCallback(nghttp2_session* handle,
916907
// The common case is that we're creating a new stream. The less likely
917908
// case is that we're receiving a set of trailers
918909
if (LIKELY(stream == nullptr)) {
919-
if (UNLIKELY(!session->CanAddStream())) {
910+
if (UNLIKELY(!session->CanAddStream() ||
911+
Http2Stream::New(session, id, frame->headers.cat) ==
912+
nullptr)) {
920913
// Too many concurrent streams being opened
921914
nghttp2_submit_rst_stream(**session, NGHTTP2_FLAG_NONE, id,
922915
NGHTTP2_ENHANCE_YOUR_CALM);
923916
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
924917
}
925-
new Http2Stream(session, id, frame->headers.cat);
926918
} else if (!stream->IsDestroyed()) {
927919
stream->StartHeaders(frame->headers.cat);
928920
}
@@ -1789,7 +1781,7 @@ Http2Stream* Http2Session::SubmitRequest(
17891781
*ret = nghttp2_submit_request(session_, prispec, nva, len, *prov, nullptr);
17901782
CHECK_NE(*ret, NGHTTP2_ERR_NOMEM);
17911783
if (LIKELY(*ret > 0))
1792-
stream = new Http2Stream(this, *ret, NGHTTP2_HCAT_HEADERS, options);
1784+
stream = Http2Stream::New(this, *ret, NGHTTP2_HCAT_HEADERS, options);
17931785
return stream;
17941786
}
17951787

@@ -1875,20 +1867,30 @@ void Http2Session::Consume(Local<External> external) {
18751867
Debug(this, "i/o stream consumed");
18761868
}
18771869

1878-
1879-
Http2Stream::Http2Stream(
1880-
Http2Session* session,
1881-
int32_t id,
1882-
nghttp2_headers_category category,
1883-
int options) : AsyncWrap(session->env(),
1884-
session->env()->http2stream_constructor_template()
1885-
->NewInstance(session->env()->context())
1886-
.ToLocalChecked(),
1887-
AsyncWrap::PROVIDER_HTTP2STREAM),
1888-
StreamBase(session->env()),
1889-
session_(session),
1890-
id_(id),
1891-
current_headers_category_(category) {
1870+
Http2Stream* Http2Stream::New(Http2Session* session,
1871+
int32_t id,
1872+
nghttp2_headers_category category,
1873+
int options) {
1874+
Local<Object> obj;
1875+
if (!session->env()
1876+
->http2stream_constructor_template()
1877+
->NewInstance(session->env()->context())
1878+
.ToLocal(&obj)) {
1879+
return nullptr;
1880+
}
1881+
return new Http2Stream(session, obj, id, category, options);
1882+
}
1883+
1884+
Http2Stream::Http2Stream(Http2Session* session,
1885+
Local<Object> obj,
1886+
int32_t id,
1887+
nghttp2_headers_category category,
1888+
int options)
1889+
: AsyncWrap(session->env(), obj, AsyncWrap::PROVIDER_HTTP2STREAM),
1890+
StreamBase(session->env()),
1891+
session_(session),
1892+
id_(id),
1893+
current_headers_category_(category) {
18921894
MakeWeak();
18931895
statistics_.start_time = uv_hrtime();
18941896

@@ -2132,7 +2134,7 @@ Http2Stream* Http2Stream::SubmitPushPromise(nghttp2_nv* nva,
21322134
CHECK_NE(*ret, NGHTTP2_ERR_NOMEM);
21332135
Http2Stream* stream = nullptr;
21342136
if (*ret > 0)
2135-
stream = new Http2Stream(session_, *ret, NGHTTP2_HCAT_HEADERS, options);
2137+
stream = Http2Stream::New(session_, *ret, NGHTTP2_HCAT_HEADERS, options);
21362138

21372139
return stream;
21382140
}
@@ -2354,7 +2356,14 @@ void HttpErrorString(const FunctionCallbackInfo<Value>& args) {
23542356
// output for an HTTP2-Settings header field.
23552357
void PackSettings(const FunctionCallbackInfo<Value>& args) {
23562358
Environment* env = Environment::GetCurrent(args);
2357-
Http2Session::Http2Settings settings(env);
2359+
// TODO(addaleax): We should not be creating a full AsyncWrap for this.
2360+
Local<Object> obj;
2361+
if (!env->http2settings_constructor_template()
2362+
->NewInstance(env->context())
2363+
.ToLocal(&obj)) {
2364+
return;
2365+
}
2366+
Http2Session::Http2Settings settings(env, nullptr, obj);
23582367
args.GetReturnValue().Set(settings.Pack());
23592368
}
23602369

@@ -2483,7 +2492,7 @@ void Http2Session::Request(const FunctionCallbackInfo<Value>& args) {
24832492
session->Http2Session::SubmitRequest(*priority, *list, list.length(),
24842493
&ret, options);
24852494

2486-
if (ret <= 0) {
2495+
if (ret <= 0 || stream == nullptr) {
24872496
Debug(session, "could not submit request: %s", nghttp2_strerror(ret));
24882497
return args.GetReturnValue().Set(ret);
24892498
}
@@ -2656,7 +2665,7 @@ void Http2Stream::PushPromise(const FunctionCallbackInfo<Value>& args) {
26562665
int32_t ret = 0;
26572666
Http2Stream* stream = parent->SubmitPushPromise(*list, list.length(),
26582667
&ret, options);
2659-
if (ret <= 0) {
2668+
if (ret <= 0 || stream == nullptr) {
26602669
Debug(parent, "failed to create push stream: %d", ret);
26612670
return args.GetReturnValue().Set(ret);
26622671
}
@@ -2792,9 +2801,15 @@ void Http2Session::Ping(const FunctionCallbackInfo<Value>& args) {
27922801
CHECK_EQ(Buffer::Length(args[0]), 8);
27932802
}
27942803

2795-
Http2Session::Http2Ping* ping = new Http2Ping(session);
2796-
Local<Object> obj = ping->object();
2797-
obj->Set(env->context(), env->ondone_string(), args[1]).FromJust();
2804+
Local<Object> obj;
2805+
if (!env->http2ping_constructor_template()
2806+
->NewInstance(env->context())
2807+
.ToLocal(&obj)) {
2808+
return;
2809+
}
2810+
if (obj->Set(env->context(), env->ondone_string(), args[1]).IsNothing())
2811+
return;
2812+
Http2Session::Http2Ping* ping = new Http2Ping(session, obj);
27982813

27992814
// To prevent abuse, we strictly limit the number of unacknowledged PING
28002815
// frames that may be sent at any given time. This is configurable in the
@@ -2818,10 +2833,17 @@ void Http2Session::Settings(const FunctionCallbackInfo<Value>& args) {
28182833
Http2Session* session;
28192834
ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
28202835

2821-
Http2Session::Http2Settings* settings = new Http2Settings(session);
2822-
Local<Object> obj = settings->object();
2823-
obj->Set(env->context(), env->ondone_string(), args[0]).FromJust();
2836+
Local<Object> obj;
2837+
if (!env->http2settings_constructor_template()
2838+
->NewInstance(env->context())
2839+
.ToLocal(&obj)) {
2840+
return;
2841+
}
2842+
if (obj->Set(env->context(), env->ondone_string(), args[0]).IsNothing())
2843+
return;
28242844

2845+
Http2Session::Http2Settings* settings =
2846+
new Http2Settings(session->env(), session, obj, 0);
28252847
if (!session->AddSettings(settings)) {
28262848
settings->Done(false);
28272849
return args.GetReturnValue().Set(false);
@@ -2868,15 +2890,10 @@ bool Http2Session::AddSettings(Http2Session::Http2Settings* settings) {
28682890
return true;
28692891
}
28702892

2871-
Http2Session::Http2Ping::Http2Ping(
2872-
Http2Session* session)
2873-
: AsyncWrap(session->env(),
2874-
session->env()->http2ping_constructor_template()
2875-
->NewInstance(session->env()->context())
2876-
.ToLocalChecked(),
2877-
AsyncWrap::PROVIDER_HTTP2PING),
2878-
session_(session),
2879-
startTime_(uv_hrtime()) { }
2893+
Http2Session::Http2Ping::Http2Ping(Http2Session* session, Local<Object> obj)
2894+
: AsyncWrap(session->env(), obj, AsyncWrap::PROVIDER_HTTP2PING),
2895+
session_(session),
2896+
startTime_(uv_hrtime()) {}
28802897

28812898
void Http2Session::Http2Ping::Send(uint8_t* payload) {
28822899
uint8_t data[8];

src/node_http2.h

+16-8
Original file line numberDiff line numberDiff line change
@@ -444,10 +444,11 @@ class Http2StreamListener : public StreamListener {
444444
class Http2Stream : public AsyncWrap,
445445
public StreamBase {
446446
public:
447-
Http2Stream(Http2Session* session,
448-
int32_t id,
449-
nghttp2_headers_category category = NGHTTP2_HCAT_HEADERS,
450-
int options = 0);
447+
static Http2Stream* New(
448+
Http2Session* session,
449+
int32_t id,
450+
nghttp2_headers_category category = NGHTTP2_HCAT_HEADERS,
451+
int options = 0);
451452
~Http2Stream() override;
452453

453454
nghttp2_stream* operator*();
@@ -604,6 +605,12 @@ class Http2Stream : public AsyncWrap,
604605
Statistics statistics_ = {};
605606

606607
private:
608+
Http2Stream(Http2Session* session,
609+
v8::Local<v8::Object> obj,
610+
int32_t id,
611+
nghttp2_headers_category category,
612+
int options);
613+
607614
Http2Session* session_ = nullptr; // The Parent HTTP/2 Session
608615
int32_t id_ = 0; // The Stream Identifier
609616
int32_t code_ = NGHTTP2_NO_ERROR; // The RST_STREAM code (if any)
@@ -1080,7 +1087,7 @@ class Http2StreamPerformanceEntry : public PerformanceEntry {
10801087

10811088
class Http2Session::Http2Ping : public AsyncWrap {
10821089
public:
1083-
explicit Http2Ping(Http2Session* session);
1090+
explicit Http2Ping(Http2Session* session, v8::Local<v8::Object> obj);
10841091

10851092
void MemoryInfo(MemoryTracker* tracker) const override {
10861093
tracker->TrackField("session", session_);
@@ -1104,8 +1111,10 @@ class Http2Session::Http2Ping : public AsyncWrap {
11041111
// structs.
11051112
class Http2Session::Http2Settings : public AsyncWrap {
11061113
public:
1107-
explicit Http2Settings(Environment* env);
1108-
explicit Http2Settings(Http2Session* session);
1114+
Http2Settings(Environment* env,
1115+
Http2Session* session,
1116+
v8::Local<v8::Object> obj,
1117+
uint64_t start_time = uv_hrtime());
11091118

11101119
void MemoryInfo(MemoryTracker* tracker) const override {
11111120
tracker->TrackField("session", session_);
@@ -1129,7 +1138,6 @@ class Http2Session::Http2Settings : public AsyncWrap {
11291138
get_setting fn);
11301139

11311140
private:
1132-
Http2Settings(Environment* env, Http2Session* session, uint64_t start_time);
11331141
void Init();
11341142
Http2Session* session_;
11351143
uint64_t startTime_;

0 commit comments

Comments
 (0)