@@ -93,7 +93,7 @@ Http2Scope::~Http2Scope() {
93
93
// instances to configure an appropriate nghttp2_options struct. The class
94
94
// uses a single TypedArray instance that is shared with the JavaScript side
95
95
// to more efficiently pass values back and forth.
96
- Http2Options::Http2Options (Environment* env) {
96
+ Http2Options::Http2Options (Environment* env, nghttp2_session_type type ) {
97
97
nghttp2_option_new (&options_);
98
98
99
99
// We manually handle flow control within a session in order to
@@ -104,10 +104,12 @@ Http2Options::Http2Options(Environment* env) {
104
104
// are required to buffer.
105
105
nghttp2_option_set_no_auto_window_update (options_, 1 );
106
106
107
- // Enable built in support for ALTSVC frames. Once we add support for
108
- // other non-built in extension frames, this will need to be handled
109
- // a bit differently. For now, let's let nghttp2 take care of it.
110
- nghttp2_option_set_builtin_recv_extension_type (options_, NGHTTP2_ALTSVC);
107
+ // Enable built in support for receiving ALTSVC and ORIGIN frames (but
108
+ // only on client side sessions
109
+ if (type == NGHTTP2_SESSION_CLIENT) {
110
+ nghttp2_option_set_builtin_recv_extension_type (options_, NGHTTP2_ALTSVC);
111
+ nghttp2_option_set_builtin_recv_extension_type (options_, NGHTTP2_ORIGIN);
112
+ }
111
113
112
114
AliasedBuffer<uint32_t , v8::Uint32Array>& buffer =
113
115
env->http2_state ()->options_buffer ;
@@ -446,6 +448,54 @@ Headers::Headers(Isolate* isolate,
446
448
}
447
449
}
448
450
451
+ Origins::Origins (Local<Context> context,
452
+ Local<String> origin_string,
453
+ size_t origin_count) : count_(origin_count) {
454
+ int origin_string_len = origin_string->Length ();
455
+ if (count_ == 0 ) {
456
+ CHECK_EQ (origin_string_len, 0 );
457
+ return ;
458
+ }
459
+
460
+ // Allocate a single buffer with count_ nghttp2_nv structs, followed
461
+ // by the raw header data as passed from JS. This looks like:
462
+ // | possible padding | nghttp2_nv | nghttp2_nv | ... | header contents |
463
+ buf_.AllocateSufficientStorage ((alignof (nghttp2_origin_entry) - 1 ) +
464
+ count_ * sizeof (nghttp2_origin_entry) +
465
+ origin_string_len);
466
+
467
+ // Make sure the start address is aligned appropriately for an nghttp2_nv*.
468
+ char * start = reinterpret_cast <char *>(
469
+ ROUND_UP (reinterpret_cast <uintptr_t >(*buf_),
470
+ alignof (nghttp2_origin_entry)));
471
+ char * origin_contents = start + (count_ * sizeof (nghttp2_origin_entry));
472
+ nghttp2_origin_entry* const nva =
473
+ reinterpret_cast <nghttp2_origin_entry*>(start);
474
+
475
+ CHECK_LE (origin_contents + origin_string_len, *buf_ + buf_.length ());
476
+ CHECK_EQ (origin_string->WriteOneByte (
477
+ reinterpret_cast <uint8_t *>(origin_contents),
478
+ 0 ,
479
+ origin_string_len,
480
+ String::NO_NULL_TERMINATION),
481
+ origin_string_len);
482
+
483
+ size_t n = 0 ;
484
+ char * p;
485
+ for (p = origin_contents; p < origin_contents + origin_string_len; n++) {
486
+ if (n >= count_) {
487
+ static uint8_t zero = ' \0 ' ;
488
+ nva[0 ].origin = &zero;
489
+ nva[0 ].origin_len = 1 ;
490
+ count_ = 1 ;
491
+ return ;
492
+ }
493
+
494
+ nva[n].origin = reinterpret_cast <uint8_t *>(p);
495
+ nva[n].origin_len = strlen (p);
496
+ p += nva[n].origin_len + 1 ;
497
+ }
498
+ }
449
499
450
500
// Sets the various callback functions that nghttp2 will use to notify us
451
501
// about significant events while processing http2 stuff.
@@ -581,7 +631,7 @@ Http2Session::Http2Session(Environment* env,
581
631
statistics_.start_time = uv_hrtime ();
582
632
583
633
// Capture the configuration options for this session
584
- Http2Options opts (env);
634
+ Http2Options opts (env, type );
585
635
586
636
max_session_memory_ = opts.GetMaxSessionMemory ();
587
637
@@ -985,6 +1035,9 @@ inline int Http2Session::OnFrameReceive(nghttp2_session* handle,
985
1035
case NGHTTP2_ALTSVC:
986
1036
session->HandleAltSvcFrame (frame);
987
1037
break ;
1038
+ case NGHTTP2_ORIGIN:
1039
+ session->HandleOriginFrame (frame);
1040
+ break ;
988
1041
default :
989
1042
break ;
990
1043
}
@@ -1378,6 +1431,41 @@ inline void Http2Session::HandleAltSvcFrame(const nghttp2_frame* frame) {
1378
1431
MakeCallback (env ()->onaltsvc_string (), arraysize (argv), argv);
1379
1432
}
1380
1433
1434
+ void Http2Session::HandleOriginFrame (const nghttp2_frame* frame) {
1435
+ Isolate* isolate = env ()->isolate ();
1436
+ HandleScope scope (isolate);
1437
+ Local<Context> context = env ()->context ();
1438
+ Context::Scope context_scope (context);
1439
+
1440
+ DEBUG_HTTP2SESSION2 (this , " handling origin frame" );
1441
+
1442
+ nghttp2_extension ext = frame->ext ;
1443
+ nghttp2_ext_origin* origin = static_cast <nghttp2_ext_origin*>(ext.payload );
1444
+
1445
+ Local<Array> holder = Array::New (isolate);
1446
+ Local<Function> fn = env ()->push_values_to_array_function ();
1447
+ Local<Value> argv[NODE_PUSH_VAL_TO_ARRAY_MAX];
1448
+
1449
+ size_t n = 0 ;
1450
+ while (n < origin->nov ) {
1451
+ size_t j = 0 ;
1452
+ while (n < origin->nov && j < arraysize (argv)) {
1453
+ auto entry = origin->ov [n++];
1454
+ argv[j++] =
1455
+ String::NewFromOneByte (isolate,
1456
+ entry.origin ,
1457
+ v8::NewStringType::kNormal ,
1458
+ entry.origin_len ).ToLocalChecked ();
1459
+ }
1460
+ if (j > 0 )
1461
+ fn->Call (context, holder, j, argv).ToLocalChecked ();
1462
+ }
1463
+
1464
+ Local<Value> args[1 ] = { holder };
1465
+
1466
+ MakeCallback (env ()->onorigin_string (), arraysize (args), args);
1467
+ }
1468
+
1381
1469
// Called by OnFrameReceived when a complete PING frame has been received.
1382
1470
inline void Http2Session::HandlePingFrame (const nghttp2_frame* frame) {
1383
1471
bool ack = frame->hd .flags & NGHTTP2_FLAG_ACK;
@@ -2809,7 +2897,12 @@ void Http2Session::AltSvc(int32_t id,
2809
2897
origin, origin_len, value, value_len), 0 );
2810
2898
}
2811
2899
2812
- // Submits an AltSvc frame to the sent to the connected peer.
2900
+ void Http2Session::Origin (nghttp2_origin_entry* ov, size_t count) {
2901
+ Http2Scope h2scope (this );
2902
+ CHECK_EQ (nghttp2_submit_origin (session_, NGHTTP2_FLAG_NONE, ov, count), 0 );
2903
+ }
2904
+
2905
+ // Submits an AltSvc frame to be sent to the connected peer.
2813
2906
void Http2Session::AltSvc (const FunctionCallbackInfo<Value>& args) {
2814
2907
Environment* env = Environment::GetCurrent (args);
2815
2908
Http2Session* session;
@@ -2837,6 +2930,23 @@ void Http2Session::AltSvc(const FunctionCallbackInfo<Value>& args) {
2837
2930
session->AltSvc (id, *origin, origin_len, *value, value_len);
2838
2931
}
2839
2932
2933
+ void Http2Session::Origin (const FunctionCallbackInfo<Value>& args) {
2934
+ Environment* env = Environment::GetCurrent (args);
2935
+ Local<Context> context = env->context ();
2936
+ Http2Session* session;
2937
+ ASSIGN_OR_RETURN_UNWRAP (&session, args.Holder ());
2938
+
2939
+ Local<String> origin_string = args[0 ].As <String>();
2940
+ int count = args[1 ]->IntegerValue (context).ToChecked ();
2941
+
2942
+
2943
+ Origins origins (env->context (),
2944
+ origin_string,
2945
+ count);
2946
+
2947
+ session->Origin (*origins, origins.length ());
2948
+ }
2949
+
2840
2950
// Submits a PING frame to be sent to the connected peer.
2841
2951
void Http2Session::Ping (const FunctionCallbackInfo<Value>& args) {
2842
2952
Environment* env = Environment::GetCurrent (args);
@@ -3063,6 +3173,7 @@ void Initialize(Local<Object> target,
3063
3173
session->SetClassName (http2SessionClassName);
3064
3174
session->InstanceTemplate ()->SetInternalFieldCount (1 );
3065
3175
AsyncWrap::AddWrapMethods (env, session);
3176
+ env->SetProtoMethod (session, " origin" , Http2Session::Origin);
3066
3177
env->SetProtoMethod (session, " altsvc" , Http2Session::AltSvc);
3067
3178
env->SetProtoMethod (session, " ping" , Http2Session::Ping);
3068
3179
env->SetProtoMethod (session, " consume" , Http2Session::Consume);
0 commit comments