10 using v8::Float64Array;
15 using v8::Uint32Array;
78 Freelist<nghttp2_data_chunk_t, FREELIST_MAX>
85 Freelist<nghttp2_data_chunks_t, FREELIST_MAX>
88 Nghttp2Session::Callbacks Nghttp2Session::callback_struct_saved[2] = {
92 Http2Options::Http2Options(Environment* env) {
93 nghttp2_option_new(&options_);
95 uint32_t* buffer = env->http2_state_buffer()->options_buffer;
99 nghttp2_option_set_max_deflate_dynamic_table_size(
105 nghttp2_option_set_max_reserved_remote_streams(
111 nghttp2_option_set_max_send_header_block_length(
117 nghttp2_option_set_peer_max_concurrent_streams(options_, 100);
119 nghttp2_option_set_peer_max_concurrent_streams(
125 padding_strategy_type strategy =
126 static_cast<padding_strategy_type
>(
128 SetPaddingStrategy(strategy);
132 void Http2Session::OnFreeSession() {
136 ssize_t Http2Session::OnMaxFrameSizePadding(
size_t frameLen,
137 size_t maxPayloadLen) {
138 DEBUG_HTTP2(
"Http2Session: using max frame size padding\n");
139 return maxPayloadLen;
142 ssize_t Http2Session::OnCallbackPadding(
size_t frameLen,
143 size_t maxPayloadLen) {
144 DEBUG_HTTP2(
"Http2Session: using callback padding\n");
145 Isolate* isolate = env()->isolate();
146 Local<Context> context = env()->context();
148 HandleScope handle_scope(isolate);
149 Context::Scope context_scope(context);
151 if (
object()->Has(context, env()->ongetpadding_string()).FromJust()) {
152 uint32_t* buffer = env()->http2_state_buffer()->padding_buffer;
157 retval = retval <= maxPayloadLen ? retval : maxPayloadLen;
158 retval = retval >= frameLen ? retval : frameLen;
159 CHECK_GE(retval, frameLen);
160 CHECK_LE(retval, maxPayloadLen);
166 void Http2Session::SetNextStreamID(
const FunctionCallbackInfo<Value>& args) {
167 Environment* env = Environment::GetCurrent(args);
168 Http2Session* session;
169 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
170 nghttp2_session*
s = session->session();
171 int32_t
id = args[0]->Int32Value(env->context()).ToChecked();
172 DEBUG_HTTP2(
"Http2Session: setting next stream id to %d\n",
id);
173 nghttp2_session_set_next_stream_id(s,
id);
177 Environment* env = Environment::GetCurrent(args);
178 uint32_t val = args[0]->Uint32Value(env->context()).ToChecked();
179 args.GetReturnValue().Set(
180 OneByteString(env->isolate(), nghttp2_strerror(val)));
187 Environment* env = Environment::GetCurrent(args);
188 HandleScope scope(env->isolate());
190 std::vector<nghttp2_settings_entry> entries;
193 uint32_t* buffer = env->http2_state_buffer()->settings_buffer;
197 DEBUG_HTTP2(
"Setting header table size: %d\n",
199 entries.push_back({NGHTTP2_SETTINGS_HEADER_TABLE_SIZE,
204 DEBUG_HTTP2(
"Setting max concurrent streams: %d\n",
206 entries.push_back({NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
211 DEBUG_HTTP2(
"Setting max frame size: %d\n",
213 entries.push_back({NGHTTP2_SETTINGS_MAX_FRAME_SIZE,
218 DEBUG_HTTP2(
"Setting initial window size: %d\n",
220 entries.push_back({NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
225 DEBUG_HTTP2(
"Setting max header list size: %d\n",
227 entries.push_back({NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
232 DEBUG_HTTP2(
"Setting enable push: %d\n",
234 entries.push_back({NGHTTP2_SETTINGS_ENABLE_PUSH,
238 const size_t len = entries.size() * 6;
239 MaybeStackBuffer<char>
buf(len);
241 nghttp2_pack_settings_payload(
242 reinterpret_cast<uint8_t*>(*buf), len, &entries[0], entries.size());
244 args.GetReturnValue().Set(
251 DEBUG_HTTP2(
"Http2Session: refreshing default settings\n");
252 Environment* env = Environment::GetCurrent(args);
253 uint32_t* buffer = env->http2_state_buffer()->settings_buffer;
255 DEFAULT_SETTINGS_HEADER_TABLE_SIZE;
257 DEFAULT_SETTINGS_ENABLE_PUSH;
259 DEFAULT_SETTINGS_INITIAL_WINDOW_SIZE;
261 DEFAULT_SETTINGS_MAX_FRAME_SIZE;
269 template <get_setting fn>
271 DEBUG_HTTP2(
"Http2Session: refreshing settings for session\n");
272 Environment* env = Environment::GetCurrent(args);
273 CHECK_EQ(args.Length(), 1);
274 CHECK(args[0]->IsObject());
275 Http2Session* session;
276 ASSIGN_OR_RETURN_UNWRAP(&session, args[0].As<Object>());
277 nghttp2_session*
s = session->session();
279 uint32_t* buffer = env->http2_state_buffer()->settings_buffer;
281 fn(s, NGHTTP2_SETTINGS_HEADER_TABLE_SIZE);
283 fn(s, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
285 fn(s, NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE);
287 fn(s, NGHTTP2_SETTINGS_MAX_FRAME_SIZE);
289 fn(s, NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE);
291 fn(s, NGHTTP2_SETTINGS_ENABLE_PUSH);
296 DEBUG_HTTP2(
"Http2Session: refreshing session state\n");
297 Environment* env = Environment::GetCurrent(args);
298 CHECK_EQ(args.Length(), 1);
299 CHECK(args[0]->IsObject());
300 double* buffer = env->http2_state_buffer()->session_state_buffer;
301 Http2Session* session;
302 ASSIGN_OR_RETURN_UNWRAP(&session, args[0].As<Object>());
303 nghttp2_session*
s = session->session();
306 nghttp2_session_get_effective_local_window_size(s);
308 nghttp2_session_get_effective_recv_data_length(s);
310 nghttp2_session_get_next_stream_id(s);
312 nghttp2_session_get_local_window_size(s);
314 nghttp2_session_get_last_proc_stream_id(s);
316 nghttp2_session_get_remote_window_size(s);
318 nghttp2_session_get_outbound_queue_size(s);
320 nghttp2_session_get_hd_deflate_dynamic_table_size(s);
322 nghttp2_session_get_hd_inflate_dynamic_table_size(s);
326 Environment* env = Environment::GetCurrent(args);
327 CHECK_EQ(args.Length(), 2);
328 CHECK(args[0]->IsObject());
329 CHECK(args[1]->IsNumber());
330 int32_t
id = args[1]->Int32Value(env->context()).ToChecked();
331 DEBUG_HTTP2(
"Http2Session: refreshing stream %d state\n",
id);
332 Http2Session* session;
333 ASSIGN_OR_RETURN_UNWRAP(&session, args[0].As<Object>());
334 nghttp2_session*
s = session->session();
335 Nghttp2Stream* stream;
337 double* buffer = env->http2_state_buffer()->stream_state_buffer;
339 if ((stream = session->FindStream(
id)) ==
nullptr) {
348 nghttp2_stream* str =
349 nghttp2_session_find_stream(s, stream->id());
351 if (str ==
nullptr) {
360 nghttp2_stream_get_state(str);
362 nghttp2_stream_get_weight(str);
364 nghttp2_stream_get_sum_dependency_weight(str);
366 nghttp2_session_get_stream_local_close(s,
id);
368 nghttp2_session_get_stream_remote_close(s,
id);
370 nghttp2_session_get_stream_local_window_size(s,
id);
375 Environment* env = Environment::GetCurrent(args);
376 CHECK(args.IsConstructCall());
378 int val = args[0]->IntegerValue(env->context()).ToChecked();
379 nghttp2_session_type type =
static_cast<nghttp2_session_type
>(val);
380 DEBUG_HTTP2(
"Http2Session: creating a session of type: %d\n", type);
381 new Http2Session(env, args.This(), type);
386 void Http2Session::Consume(
const FunctionCallbackInfo<Value>& args) {
387 Http2Session* session;
388 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
389 CHECK(args[0]->IsExternal());
390 session->Consume(args[0].As<External>());
393 void Http2Session::Destroy(
const FunctionCallbackInfo<Value>& args) {
394 Http2Session* session;
395 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
396 DEBUG_HTTP2(
"Http2Session: destroying session %d\n", session->type());
397 Environment* env = Environment::GetCurrent(args);
398 Local<Context> context = env->context();
400 bool skipUnconsume = args[0]->BooleanValue(context).ToChecked();
403 session->Unconsume();
407 void Http2Session::Destroying(
const FunctionCallbackInfo<Value>& args) {
408 Http2Session* session;
409 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
410 DEBUG_HTTP2(
"Http2Session: preparing to destroy session %d\n",
412 session->MarkDestroying();
415 void Http2Session::SubmitPriority(
const FunctionCallbackInfo<Value>& args) {
416 Environment* env = Environment::GetCurrent(args);
417 Http2Session* session;
418 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
419 Local<Context> context = env->context();
421 nghttp2_priority_spec spec;
422 int32_t
id = args[0]->Int32Value(context).ToChecked();
423 int32_t parent = args[1]->Int32Value(context).ToChecked();
424 int32_t weight = args[2]->Int32Value(context).ToChecked();
425 bool exclusive = args[3]->BooleanValue(context).ToChecked();
426 bool silent = args[4]->BooleanValue(context).ToChecked();
427 DEBUG_HTTP2(
"Http2Session: submitting priority for stream %d: " 428 "parent: %d, weight: %d, exclusive: %d, silent: %d\n",
429 id, parent, weight, exclusive, silent);
434 Nghttp2Stream* stream;
435 if (!(stream = session->FindStream(
id))) {
437 return args.GetReturnValue().Set(NGHTTP2_ERR_INVALID_STREAM_ID);
439 nghttp2_priority_spec_init(&spec, parent, weight, exclusive ? 1 : 0);
441 args.GetReturnValue().Set(stream->SubmitPriority(&spec, silent));
444 void Http2Session::SubmitSettings(
const FunctionCallbackInfo<Value>& args) {
445 Http2Session* session;
446 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
447 Environment* env = session->env();
449 uint32_t* buffer = env->http2_state_buffer()->settings_buffer;
452 std::vector<nghttp2_settings_entry> entries;
456 DEBUG_HTTP2(
"Setting header table size: %d\n",
458 entries.push_back({NGHTTP2_SETTINGS_HEADER_TABLE_SIZE,
463 DEBUG_HTTP2(
"Setting max concurrent streams: %d\n",
465 entries.push_back({NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
470 DEBUG_HTTP2(
"Setting max frame size: %d\n",
472 entries.push_back({NGHTTP2_SETTINGS_MAX_FRAME_SIZE,
477 DEBUG_HTTP2(
"Setting initial window size: %d\n",
479 entries.push_back({NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE,
484 DEBUG_HTTP2(
"Setting max header list size: %d\n",
486 entries.push_back({NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE,
491 DEBUG_HTTP2(
"Setting enable push: %d\n",
493 entries.push_back({NGHTTP2_SETTINGS_ENABLE_PUSH,
497 if (entries.size() > 0) {
498 args.GetReturnValue().Set(
499 session->Nghttp2Session::SubmitSettings(&entries[0], entries.size()));
501 args.GetReturnValue().Set(
502 session->Nghttp2Session::SubmitSettings(
nullptr, 0));
506 void Http2Session::SubmitRstStream(
const FunctionCallbackInfo<Value>& args) {
507 Environment* env = Environment::GetCurrent(args);
508 Local<Context> context = env->context();
509 CHECK(args[0]->IsNumber());
510 CHECK(args[1]->IsNumber());
512 Http2Session* session;
513 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
515 int32_t
id = args[0]->Int32Value(context).ToChecked();
516 uint32_t code = args[1]->Uint32Value(context).ToChecked();
518 Nghttp2Stream* stream;
519 if (!(stream = session->FindStream(
id))) {
521 return args.GetReturnValue().Set(NGHTTP2_ERR_INVALID_STREAM_ID);
523 DEBUG_HTTP2(
"Http2Session: sending rst_stream for stream %d, code: %d\n",
525 args.GetReturnValue().Set(stream->SubmitRstStream(code));
528 void Http2Session::SubmitRequest(
const FunctionCallbackInfo<Value>& args) {
534 CHECK(args[0]->IsArray());
536 Http2Session* session;
537 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
538 Environment* env = session->env();
539 Local<Context> context = env->context();
540 Isolate* isolate = env->isolate();
542 Local<Array> headers = args[0].As<Array>();
543 bool endStream = args[1]->BooleanValue(context).ToChecked();
544 int32_t parent = args[2]->Int32Value(context).ToChecked();
545 int32_t weight = args[3]->Int32Value(context).ToChecked();
546 bool exclusive = args[4]->BooleanValue(context).ToChecked();
547 bool getTrailers = args[5]->BooleanValue(context).ToChecked();
549 DEBUG_HTTP2(
"Http2Session: submitting request: headers: %d, end-stream: %d, " 550 "parent: %d, weight: %d, exclusive: %d\n", headers->Length(),
551 endStream, parent, weight, exclusive);
553 nghttp2_priority_spec prispec;
554 nghttp2_priority_spec_init(&prispec, parent, weight, exclusive ? 1 : 0);
556 Headers list(isolate, context, headers);
558 int32_t ret = session->Nghttp2Session::SubmitRequest(&prispec,
559 *list, list.length(),
562 DEBUG_HTTP2(
"Http2Session: request submitted, response: %d\n", ret);
563 args.GetReturnValue().Set(ret);
566 void Http2Session::SubmitResponse(
const FunctionCallbackInfo<Value>& args) {
567 CHECK(args[0]->IsNumber());
568 CHECK(args[1]->IsArray());
570 Http2Session* session;
571 Nghttp2Stream* stream;
573 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
574 Environment* env = session->env();
575 Local<Context> context = env->context();
576 Isolate* isolate = env->isolate();
578 int32_t
id = args[0]->Int32Value(context).ToChecked();
579 Local<Array> headers = args[1].As<Array>();
580 bool endStream = args[2]->BooleanValue(context).ToChecked();
581 bool getTrailers = args[3]->BooleanValue(context).ToChecked();
583 DEBUG_HTTP2(
"Http2Session: submitting response for stream %d: headers: %d, " 584 "end-stream: %d\n",
id, headers->Length(), endStream);
586 if (!(stream = session->FindStream(
id))) {
587 return args.GetReturnValue().Set(NGHTTP2_ERR_INVALID_STREAM_ID);
590 Headers list(isolate, context, headers);
592 args.GetReturnValue().Set(
593 stream->SubmitResponse(*list, list.length(), endStream, getTrailers));
596 void Http2Session::SubmitFile(
const FunctionCallbackInfo<Value>& args) {
597 CHECK(args[0]->IsNumber());
598 CHECK(args[1]->IsNumber());
599 CHECK(args[2]->IsArray());
600 CHECK(args[3]->IsNumber());
601 CHECK(args[4]->IsNumber());
603 Http2Session* session;
604 Nghttp2Stream* stream;
606 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
607 Environment* env = session->env();
608 Local<Context> context = env->context();
609 Isolate* isolate = env->isolate();
611 int32_t
id = args[0]->Int32Value(context).ToChecked();
612 int fd = args[1]->Int32Value(context).ToChecked();
613 Local<Array> headers = args[2].As<Array>();
615 int64_t offset = args[3]->IntegerValue(context).ToChecked();
616 int64_t length = args[4]->IntegerValue(context).ToChecked();
617 bool getTrailers = args[5]->BooleanValue(context).ToChecked();
621 DEBUG_HTTP2(
"Http2Session: submitting file %d for stream %d: headers: %d, " 622 "end-stream: %d\n", fd,
id, headers->Length());
624 if (!(stream = session->FindStream(
id))) {
625 return args.GetReturnValue().Set(NGHTTP2_ERR_INVALID_STREAM_ID);
628 Headers list(isolate, context, headers);
630 args.GetReturnValue().Set(stream->SubmitFile(fd, *list, list.length(),
631 offset, length, getTrailers));
634 void Http2Session::SendHeaders(
const FunctionCallbackInfo<Value>& args) {
635 CHECK(args[0]->IsNumber());
636 CHECK(args[1]->IsArray());
638 Http2Session* session;
639 Nghttp2Stream* stream;
641 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
642 Environment* env = session->env();
643 Local<Context> context = env->context();
644 Isolate* isolate = env->isolate();
646 int32_t
id = args[0]->Int32Value(env->context()).ToChecked();
647 Local<Array> headers = args[1].As<Array>();
649 DEBUG_HTTP2(
"Http2Session: sending informational headers for stream %d, " 650 "count: %d\n",
id, headers->Length());
652 if (!(stream = session->FindStream(
id))) {
653 return args.GetReturnValue().Set(NGHTTP2_ERR_INVALID_STREAM_ID);
656 Headers list(isolate, context, headers);
658 args.GetReturnValue().Set(stream->SubmitInfo(*list, list.length()));
661 void Http2Session::ShutdownStream(
const FunctionCallbackInfo<Value>& args) {
662 Environment* env = Environment::GetCurrent(args);
663 CHECK(args[0]->IsNumber());
664 Http2Session* session;
665 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
666 Nghttp2Stream* stream;
667 int32_t
id = args[0]->Int32Value(env->context()).ToChecked();
668 DEBUG_HTTP2(
"Http2Session: shutting down stream %d\n",
id);
669 if (!(stream = session->FindStream(
id))) {
670 return args.GetReturnValue().Set(NGHTTP2_ERR_INVALID_STREAM_ID);
676 void Http2Session::StreamReadStart(
const FunctionCallbackInfo<Value>& args) {
677 Environment* env = Environment::GetCurrent(args);
678 CHECK(args[0]->IsNumber());
679 Http2Session* session;
680 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
681 Nghttp2Stream* stream;
682 int32_t
id = args[0]->Int32Value(env->context()).ToChecked();
683 if (!(stream = session->FindStream(
id))) {
684 return args.GetReturnValue().Set(NGHTTP2_ERR_INVALID_STREAM_ID);
690 void Http2Session::StreamReadStop(
const FunctionCallbackInfo<Value>& args) {
691 Environment* env = Environment::GetCurrent(args);
692 CHECK(args[0]->IsNumber());
693 Http2Session* session;
694 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
695 Nghttp2Stream* stream;
696 int32_t
id = args[0]->Int32Value(env->context()).ToChecked();
697 if (!(stream = session->FindStream(
id))) {
698 return args.GetReturnValue().Set(NGHTTP2_ERR_INVALID_STREAM_ID);
703 void Http2Session::SendShutdownNotice(
704 const FunctionCallbackInfo<Value>& args) {
705 Http2Session* session;
706 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
707 session->SubmitShutdownNotice();
710 void Http2Session::SubmitGoaway(
const FunctionCallbackInfo<Value>& args) {
711 Http2Session* session;
712 Environment* env = Environment::GetCurrent(args);
713 Local<Context> context = env->context();
714 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
716 uint32_t errorCode = args[0]->Uint32Value(context).ToChecked();
717 int32_t lastStreamID = args[1]->Int32Value(context).ToChecked();
718 Local<Value> opaqueData = args[2];
720 uint8_t*
data = NULL;
723 if (opaqueData->BooleanValue(context).ToChecked()) {
724 THROW_AND_RETURN_UNLESS_BUFFER(env, opaqueData);
725 SPREAD_BUFFER_ARG(opaqueData,
buf);
726 data =
reinterpret_cast<uint8_t*
>(buf_data);
730 DEBUG_HTTP2(
"Http2Session: initiating immediate shutdown. " 731 "last-stream-id: %d, code: %d, opaque-data: %d\n",
732 lastStreamID, errorCode, length);
733 int status = nghttp2_submit_goaway(session->session(),
738 args.GetReturnValue().Set(status);
741 void Http2Session::DestroyStream(
const FunctionCallbackInfo<Value>& args) {
742 Environment* env = Environment::GetCurrent(args);
743 Http2Session* session;
744 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
746 CHECK_EQ(args.Length(), 1);
747 CHECK(args[0]->IsNumber());
748 int32_t
id = args[0]->Int32Value(env->context()).ToChecked();
749 DEBUG_HTTP2(
"Http2Session: destroy stream %d\n",
id);
750 Nghttp2Stream* stream;
751 if (!(stream = session->FindStream(
id))) {
752 return args.GetReturnValue().Set(NGHTTP2_ERR_INVALID_STREAM_ID);
757 void Http2Session::SubmitPushPromise(
const FunctionCallbackInfo<Value>& args) {
758 Http2Session* session;
759 Environment* env = Environment::GetCurrent(args);
760 Local<Context> context = env->context();
761 Isolate* isolate = env->isolate();
762 ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
764 CHECK(args[0]->IsNumber());
765 CHECK(args[1]->IsArray());
767 Nghttp2Stream* parent;
768 int32_t
id = args[0]->Int32Value(context).ToChecked();
769 Local<Array> headers = args[1].As<Array>();
770 bool endStream = args[2]->BooleanValue(context).ToChecked();
772 DEBUG_HTTP2(
"Http2Session: submitting push promise for stream %d: " 773 "end-stream: %d, headers: %d\n",
id, endStream,
776 if (!(parent = session->FindStream(
id))) {
777 return args.GetReturnValue().Set(NGHTTP2_ERR_INVALID_STREAM_ID);
780 Headers list(isolate, context, headers);
782 int32_t ret = parent->SubmitPushPromise(*list, list.length(),
784 DEBUG_HTTP2(
"Http2Session: push promise submitted, ret: %d\n", ret);
785 args.GetReturnValue().Set(ret);
788 int Http2Session::DoWrite(WriteWrap* req_wrap,
791 uv_stream_t* send_handle) {
792 Environment* env = req_wrap->env();
793 Local<Object> req_wrap_obj = req_wrap->object();
794 Local<Context> context = env->context();
796 Nghttp2Stream* stream;
799 req_wrap_obj->Get(context, env->stream_string()).ToLocalChecked();
800 int32_t
id = val->Int32Value(context).ToChecked();
801 if (!val->IsNumber() || !(stream = FindStream(
id))) {
803 req_wrap->Dispatched();
805 return NGHTTP2_ERR_INVALID_STREAM_ID;
809 nghttp2_stream_write_t*
req =
new nghttp2_stream_write_t;
810 req->data = req_wrap;
812 auto AfterWrite = [](nghttp2_stream_write_t*
req,
int status) {
813 WriteWrap*
wrap =
static_cast<WriteWrap*
>(req->data);
817 req_wrap->Dispatched();
818 stream->Write(req, bufs, count, AfterWrite);
822 void Http2Session::AllocateSend(
size_t recommended, uv_buf_t*
buf) {
823 buf->base = stream_alloc();
824 buf->len = kAllocBufferSize;
827 void Http2Session::Send(uv_buf_t* buf,
size_t length) {
828 DEBUG_HTTP2(
"Http2Session: Attempting to send data\n");
829 if (stream_ ==
nullptr || !stream_->IsAlive() || stream_->IsClosing()) {
832 HandleScope scope(env()->isolate());
833 auto AfterWrite = [](WriteWrap* req_wrap,
int status) {
836 Local<Object> req_wrap_obj =
837 env()->write_wrap_constructor_function()
838 ->NewInstance(env()->context()).ToLocalChecked();
844 uv_buf_t actual = uv_buf_init(buf->base, length);
845 if (stream_->DoWrite(write_req, &actual, 1,
nullptr)) {
846 write_req->Dispose();
850 void Http2Session::OnTrailers(Nghttp2Stream* stream,
851 const SubmitTrailers& submit_trailers) {
852 DEBUG_HTTP2(
"Http2Session: prompting for trailers on stream %d\n",
854 Local<Context> context = env()->context();
855 Isolate* isolate = env()->isolate();
856 HandleScope scope(isolate);
857 Context::Scope context_scope(context);
859 if (
object()->Has(context, env()->ontrailers_string()).FromJust()) {
860 Local<Value> argv[1] = {
864 Local<Value> ret =
MakeCallback(env()->ontrailers_string(),
865 arraysize(argv), argv).ToLocalChecked();
866 if (!ret.IsEmpty()) {
867 if (ret->IsArray()) {
868 Local<Array> headers = ret.As<Array>();
869 if (headers->Length() > 0) {
870 Headers trailers(isolate, context, headers);
871 submit_trailers.Submit(*trailers, trailers.length());
878 void Http2Session::OnHeaders(Nghttp2Stream* stream,
879 nghttp2_header_list* headers,
880 nghttp2_headers_category cat,
882 Local<Context> context = env()->context();
883 Isolate* isolate = env()->isolate();
884 Context::Scope context_scope(context);
885 HandleScope scope(isolate);
886 Local<String> name_str;
887 Local<String> value_str;
890 Local<Function> fn = env()->push_values_to_array_function();
891 Local<Value> argv[NODE_PUSH_VAL_TO_ARRAY_MAX * 2];
902 while (headers !=
nullptr && j < arraysize(argv) / 2) {
903 nghttp2_header_list* item = headers;
906 ExternalHeader::New<true>(env(), item->name).ToLocalChecked();
908 ExternalHeader::New<false>(env(), item->value).ToLocalChecked();
909 argv[j * 2] = name_str;
910 argv[j * 2 + 1] = value_str;
911 headers = item->next;
918 fn->Call(env()->context(), holder, j * 2, argv).ToLocalChecked();
920 }
while (headers !=
nullptr);
922 if (
object()->Has(context, env()->onheaders_string()).FromJust()) {
923 Local<Value> argv[4] = {
929 MakeCallback(env()->onheaders_string(), arraysize(argv), argv);
934 void Http2Session::OnStreamClose(int32_t
id, uint32_t code) {
935 Isolate* isolate = env()->isolate();
936 Local<Context> context = env()->context();
937 HandleScope scope(isolate);
938 Context::Scope context_scope(context);
939 if (
object()->Has(context, env()->onstreamclose_string()).FromJust()) {
940 Local<Value> argv[2] = {
942 Integer::NewFromUnsigned(isolate, code)
944 MakeCallback(env()->onstreamclose_string(), arraysize(argv), argv);
949 nghttp2_data_chunk_t* item =
reinterpret_cast<nghttp2_data_chunk_t*
>(hint);
954 void Http2Session::OnDataChunk(
955 Nghttp2Stream* stream,
956 nghttp2_data_chunk_t* chunk) {
957 Isolate* isolate = env()->isolate();
958 Local<Context> context = env()->context();
959 HandleScope scope(isolate);
966 if (chunk !=
nullptr) {
967 len = chunk->buf.len;
969 chunk->buf.base, len,
971 chunk).ToLocalChecked();
973 EmitData(len, buf, obj);
976 void Http2Session::OnSettings(
bool ack) {
977 Local<Context> context = env()->context();
978 Isolate* isolate = env()->isolate();
979 HandleScope scope(isolate);
980 Context::Scope context_scope(context);
981 if (
object()->Has(context, env()->onsettings_string()).FromJust()) {
983 MakeCallback(env()->onsettings_string(), arraysize(argv), argv);
987 void Http2Session::OnFrameError(int32_t
id, uint8_t type,
int error_code) {
988 Local<Context> context = env()->context();
989 Isolate* isolate = env()->isolate();
990 HandleScope scope(isolate);
991 Context::Scope context_scope(context);
992 if (
object()->Has(context, env()->onframeerror_string()).FromJust()) {
993 Local<Value> argv[3] = {
998 MakeCallback(env()->onframeerror_string(), arraysize(argv), argv);
1002 void Http2Session::OnPriority(int32_t stream,
1006 Local<Context> context = env()->context();
1007 Isolate* isolate = env()->isolate();
1008 HandleScope scope(isolate);
1009 Context::Scope context_scope(context);
1010 if (
object()->Has(context, env()->onpriority_string()).FromJust()) {
1011 Local<Value> argv[4] = {
1017 MakeCallback(env()->onpriority_string(), arraysize(argv), argv);
1021 void Http2Session::OnGoAway(int32_t lastStreamID,
1025 Local<Context> context = env()->context();
1026 Isolate* isolate = env()->isolate();
1027 HandleScope scope(isolate);
1028 Context::Scope context_scope(context);
1029 if (
object()->Has(context, env()->ongoawaydata_string()).FromJust()) {
1030 Local<Value> argv[3] = {
1031 Integer::NewFromUnsigned(isolate, errorCode),
1038 reinterpret_cast<char*>(data),
1039 length).ToLocalChecked();
1042 MakeCallback(env()->ongoawaydata_string(), arraysize(argv), argv);
1046 void Http2Session::OnStreamAllocImpl(
size_t suggested_size,
1049 Http2Session* session =
static_cast<Http2Session*
>(
ctx);
1050 buf->base = session->stream_alloc();
1051 buf->len = kAllocBufferSize;
1055 void Http2Session::OnStreamReadImpl(ssize_t nread,
1056 const uv_buf_t* bufs,
1057 uv_handle_type pending,
1059 Http2Session* session =
static_cast<Http2Session*
>(
ctx);
1062 tmp_buf.base =
nullptr;
1064 session->prev_read_cb_.fn(nread,
1067 session->prev_read_cb_.ctx);
1072 uv_buf_t buf[] { uv_buf_init((*bufs).base, nread) };
1073 ssize_t ret = session->Write(buf, 1);
1075 DEBUG_HTTP2(
"Http2Session: fatal error receiving data: %d\n", ret);
1076 nghttp2_session_terminate_session(session->session(),
1077 NGHTTP2_PROTOCOL_ERROR);
1083 void Http2Session::Consume(Local<External> external) {
1084 DEBUG_HTTP2(
"Http2Session: consuming socket\n");
1086 StreamBase* stream =
static_cast<StreamBase*
>(external->Value());
1087 CHECK_NE(stream,
nullptr);
1092 stream->set_alloc_cb({ Http2Session::OnStreamAllocImpl,
this });
1093 stream->set_read_cb({ Http2Session::OnStreamReadImpl,
this });
1097 void Http2Session::Unconsume() {
1098 DEBUG_HTTP2(
"Http2Session: unconsuming socket\n");
1109 Headers::Headers(Isolate* isolate,
1110 Local<Context> context,
1111 Local<Array> headers) {
1112 CHECK_EQ(headers->Length(), 2);
1113 Local<Value> header_string = headers->Get(context, 0).ToLocalChecked();
1114 Local<Value> header_count = headers->Get(context, 1).ToLocalChecked();
1115 CHECK(header_string->IsString());
1116 CHECK(header_count->IsUint32());
1117 count_ = header_count.As<Uint32>()->Value();
1118 int header_string_len = header_string.As<String>()->
Length();
1121 CHECK_EQ(header_string_len, 0);
1128 buf_.AllocateSufficientStorage((
alignof(nghttp2_nv) - 1) +
1129 count_ *
sizeof(nghttp2_nv) +
1132 char* start =
reinterpret_cast<char*
>(
1133 ROUND_UP(reinterpret_cast<uintptr_t>(*buf_),
alignof(nghttp2_nv)));
1134 char* header_contents = start + (count_ *
sizeof(nghttp2_nv));
1135 nghttp2_nv*
const nva =
reinterpret_cast<nghttp2_nv*
>(start);
1137 CHECK_LE(header_contents + header_string_len, *buf_ + buf_.length());
1138 CHECK_EQ(header_string.As<String>()
1139 ->WriteOneByte(reinterpret_cast<uint8_t*>(header_contents),
1140 0, header_string_len,
1141 String::NO_NULL_TERMINATION),
1146 for (p = header_contents; p < header_contents + header_string_len; n++) {
1151 static uint8_t zero =
'\0';
1152 nva[0].name = nva[0].value = &zero;
1153 nva[0].namelen = nva[0].valuelen = 1;
1158 nva[
n].flags = NGHTTP2_NV_FLAG_NONE;
1159 nva[
n].name =
reinterpret_cast<uint8_t*
>(
p);
1160 nva[
n].namelen = strlen(p);
1161 p += nva[
n].namelen + 1;
1162 nva[
n].value =
reinterpret_cast<uint8_t*
>(
p);
1163 nva[
n].valuelen = strlen(p);
1164 p += nva[
n].valuelen + 1;
1167 CHECK_EQ(p, header_contents + header_string_len);
1168 CHECK_EQ(n, count_);
1173 Local<Value> unused,
1174 Local<Context> context,
1176 Environment* env = Environment::GetCurrent(context);
1177 Isolate* isolate = env->isolate();
1178 HandleScope scope(isolate);
1181 env->set_http2_state_buffer(state);
1184 #define SET_STATE_TYPEDARRAY(name, type, field) \ 1185 target->Set(context, \ 1186 FIXED_ONE_BYTE_STRING(isolate, (name)), \ 1187 type::New(state_ab, \ 1188 offsetof(http2_state, field), \ 1189 arraysize(state->field))) \ 1200 #undef SET_STATE_TYPEDARRAY 1209 Local<String> http2SessionClassName =
1210 FIXED_ONE_BYTE_STRING(isolate,
"Http2Session");
1212 Local<FunctionTemplate> session =
1214 session->SetClassName(http2SessionClassName);
1215 session->InstanceTemplate()->SetInternalFieldCount(1);
1216 AsyncWrap::AddWrapMethods(env, session);
1217 env->SetProtoMethod(session,
"consume",
1218 Http2Session::Consume);
1219 env->SetProtoMethod(session,
"destroy",
1220 Http2Session::Destroy);
1221 env->SetProtoMethod(session,
"destroying",
1222 Http2Session::Destroying);
1223 env->SetProtoMethod(session,
"sendHeaders",
1224 Http2Session::SendHeaders);
1225 env->SetProtoMethod(session,
"submitShutdownNotice",
1226 Http2Session::SendShutdownNotice);
1227 env->SetProtoMethod(session,
"submitGoaway",
1228 Http2Session::SubmitGoaway);
1229 env->SetProtoMethod(session,
"submitSettings",
1230 Http2Session::SubmitSettings);
1231 env->SetProtoMethod(session,
"submitPushPromise",
1232 Http2Session::SubmitPushPromise);
1233 env->SetProtoMethod(session,
"submitRstStream",
1234 Http2Session::SubmitRstStream);
1235 env->SetProtoMethod(session,
"submitResponse",
1236 Http2Session::SubmitResponse);
1237 env->SetProtoMethod(session,
"submitFile",
1238 Http2Session::SubmitFile);
1239 env->SetProtoMethod(session,
"submitRequest",
1240 Http2Session::SubmitRequest);
1241 env->SetProtoMethod(session,
"submitPriority",
1242 Http2Session::SubmitPriority);
1243 env->SetProtoMethod(session,
"shutdownStream",
1244 Http2Session::ShutdownStream);
1245 env->SetProtoMethod(session,
"streamReadStart",
1246 Http2Session::StreamReadStart);
1247 env->SetProtoMethod(session,
"streamReadStop",
1248 Http2Session::StreamReadStop);
1249 env->SetProtoMethod(session,
"setNextStreamID",
1250 Http2Session::SetNextStreamID);
1251 env->SetProtoMethod(session,
"destroyStream",
1252 Http2Session::DestroyStream);
1253 StreamBase::AddMethods<Http2Session>(env, session,
1254 StreamBase::kFlagHasWritev |
1255 StreamBase::kFlagNoShutdown);
1256 target->Set(context,
1257 http2SessionClassName,
1258 session->GetFunction()).FromJust();
1325 #define STRING_CONSTANT(NAME, VALUE) \ 1326 NODE_DEFINE_STRING_CONSTANT(constants, "HTTP2_HEADER_" # NAME, VALUE); 1328 #undef STRING_CONSTANT 1330 #define STRING_CONSTANT(NAME, VALUE) \ 1331 NODE_DEFINE_STRING_CONSTANT(constants, "HTTP2_METHOD_" # NAME, VALUE); 1333 #undef STRING_CONSTANT 1335 #define V(name, _) NODE_DEFINE_CONSTANT(constants, HTTP_STATUS_##name); 1336 HTTP_STATUS_CODES(
V)
1339 env->SetMethod(target,
"refreshLocalSettings",
1340 RefreshSettings<nghttp2_session_get_local_settings>);
1341 env->SetMethod(target,
"refreshRemoteSettings",
1342 RefreshSettings<nghttp2_session_get_remote_settings>);
1348 target->Set(context,
1349 FIXED_ONE_BYTE_STRING(isolate,
"constants"),
1350 constants).FromJust();
StreamResource::Callback< StreamResource::AllocCb > prev_alloc_cb_
Freelist< Nghttp2Stream, FREELIST_MAX > stream_free_list
void HttpErrorString(const FunctionCallbackInfo< Value > &args)
uint32_t options_buffer[IDX_OPTIONS_FLAGS+1]
NODE_MODULE_CONTEXT_AWARE_BUILTIN(inspector, node::inspector::Agent::InitInspector)
void RefreshSettings(const FunctionCallbackInfo< Value > &args)
uint32_t padding_buffer[PADDING_BUF_FIELD_COUNT]
union node::cares_wrap::@8::CaresAsyncData::@0 data
double stream_state_buffer[IDX_STREAM_STATE_COUNT]
void RefreshDefaultSettings(const FunctionCallbackInfo< Value > &args)
void FreeDataChunk(char *data, void *hint)
double session_state_buffer[IDX_SESSION_STATE_COUNT]
void RefreshStreamState(const FunctionCallbackInfo< Value > &args)
size_t Length(Local< Value > val)
#define STRING_CONSTANT(NAME, VALUE)
void PackSettings(const FunctionCallbackInfo< Value > &args)
void RefreshSessionState(const FunctionCallbackInfo< Value > &args)
void Initialize(Local< Object > target, Local< Value > unused, Local< Context > context, void *priv)
Freelist< nghttp2_data_chunks_t, FREELIST_MAX > data_chunks_free_list
#define SET_STATE_TYPEDARRAY(name, type, field)
#define NODE_DEFINE_HIDDEN_CONSTANT(target, constant)
MaybeLocal< Object > New(Isolate *isolate, Local< String > string, enum encoding enc)
MaybeLocal< Value > MakeCallback(Isolate *isolate, Local< Object > recv, Local< Function > callback, int argc, Local< Value > *argv, async_id asyncId, async_id triggerAsyncId)
uint32_t settings_buffer[IDX_SETTINGS_COUNT+1]
Freelist< nghttp2_header_list, FREELIST_MAX > header_free_list
#define NODE_DEFINE_CONSTANT(target, constant)
MaybeLocal< Object > Copy(Isolate *isolate, const char *data, size_t length)
StreamResource::Callback< StreamResource::ReadCb > prev_read_cb_
Freelist< nghttp2_data_chunk_t, FREELIST_MAX > data_chunk_free_list