@@ -103,6 +103,11 @@ Http2Options::Http2Options(Environment* env) {
103
103
// are required to buffer.
104
104
nghttp2_option_set_no_auto_window_update (options_, 1 );
105
105
106
+ // Enable built in support for ALTSVC frames. Once we add support for
107
+ // other non-built in extension frames, this will need to be handled
108
+ // a bit differently. For now, let's let nghttp2 take care of it.
109
+ nghttp2_option_set_builtin_recv_extension_type (options_, NGHTTP2_ALTSVC);
110
+
106
111
AliasedBuffer<uint32_t , v8::Uint32Array>& buffer =
107
112
env->http2_state ()->options_buffer ;
108
113
uint32_t flags = buffer[IDX_OPTIONS_FLAGS];
@@ -847,6 +852,10 @@ inline int Http2Session::OnFrameReceive(nghttp2_session* handle,
847
852
break ;
848
853
case NGHTTP2_PING:
849
854
session->HandlePingFrame (frame);
855
+ break ;
856
+ case NGHTTP2_ALTSVC:
857
+ session->HandleAltSvcFrame (frame);
858
+ break ;
850
859
default :
851
860
break ;
852
861
}
@@ -1185,6 +1194,34 @@ inline void Http2Session::HandleGoawayFrame(const nghttp2_frame* frame) {
1185
1194
MakeCallback (env ()->ongoawaydata_string (), arraysize (argv), argv);
1186
1195
}
1187
1196
1197
+ // Called by OnFrameReceived when a complete ALTSVC frame has been received.
1198
+ inline void Http2Session::HandleAltSvcFrame (const nghttp2_frame* frame) {
1199
+ Isolate* isolate = env ()->isolate ();
1200
+ HandleScope scope (isolate);
1201
+ Local<Context> context = env ()->context ();
1202
+ Context::Scope context_scope (context);
1203
+
1204
+ int32_t id = GetFrameID (frame);
1205
+
1206
+ nghttp2_extension ext = frame->ext ;
1207
+ nghttp2_ext_altsvc* altsvc = static_cast <nghttp2_ext_altsvc*>(ext.payload );
1208
+ DEBUG_HTTP2SESSION (this , " handling altsvc frame" );
1209
+
1210
+ Local<Value> argv[3 ] = {
1211
+ Integer::New (isolate, id),
1212
+ String::NewFromOneByte (isolate,
1213
+ altsvc->origin ,
1214
+ v8::NewStringType::kNormal ,
1215
+ altsvc->origin_len ).ToLocalChecked (),
1216
+ String::NewFromOneByte (isolate,
1217
+ altsvc->field_value ,
1218
+ v8::NewStringType::kNormal ,
1219
+ altsvc->field_value_len ).ToLocalChecked (),
1220
+ };
1221
+
1222
+ MakeCallback (env ()->onaltsvc_string (), arraysize (argv), argv);
1223
+ }
1224
+
1188
1225
// Called by OnFrameReceived when a complete PING frame has been received.
1189
1226
inline void Http2Session::HandlePingFrame (const nghttp2_frame* frame) {
1190
1227
bool ack = frame->hd .flags & NGHTTP2_FLAG_ACK;
@@ -2494,6 +2531,44 @@ void Http2Stream::RefreshState(const FunctionCallbackInfo<Value>& args) {
2494
2531
}
2495
2532
}
2496
2533
2534
+ void Http2Session::AltSvc (int32_t id,
2535
+ uint8_t * origin,
2536
+ size_t origin_len,
2537
+ uint8_t * value,
2538
+ size_t value_len) {
2539
+ Http2Scope h2scope (this );
2540
+ CHECK_EQ (nghttp2_submit_altsvc (session_, NGHTTP2_FLAG_NONE, id,
2541
+ origin, origin_len, value, value_len), 0 );
2542
+ }
2543
+
2544
+ // Submits an AltSvc frame to the sent to the connected peer.
2545
+ void Http2Session::AltSvc (const FunctionCallbackInfo<Value>& args) {
2546
+ Environment* env = Environment::GetCurrent (args);
2547
+ Http2Session* session;
2548
+ ASSIGN_OR_RETURN_UNWRAP (&session, args.Holder ());
2549
+
2550
+ int32_t id = args[0 ]->Int32Value (env->context ()).ToChecked ();
2551
+
2552
+ // origin and value are both required to be ASCII, handle them as such.
2553
+ Local<String> origin_str = args[1 ]->ToString (env->context ()).ToLocalChecked ();
2554
+ Local<String> value_str = args[2 ]->ToString (env->context ()).ToLocalChecked ();
2555
+
2556
+ size_t origin_len = origin_str->Length ();
2557
+ size_t value_len = value_str->Length ();
2558
+
2559
+ CHECK_LE (origin_len + value_len, 16382 ); // Max permitted for ALTSVC
2560
+ // Verify that origin len != 0 if stream id == 0, or
2561
+ // that origin len == 0 if stream id != 0
2562
+ CHECK ((origin_len != 0 && id == 0 ) || (origin_len == 0 && id != 0 ));
2563
+
2564
+ MaybeStackBuffer<uint8_t > origin (origin_len);
2565
+ MaybeStackBuffer<uint8_t > value (value_len);
2566
+ origin_str->WriteOneByte (*origin);
2567
+ value_str->WriteOneByte (*value);
2568
+
2569
+ session->AltSvc (id, *origin, origin_len, *value, value_len);
2570
+ }
2571
+
2497
2572
// Submits a PING frame to be sent to the connected peer.
2498
2573
void Http2Session::Ping (const FunctionCallbackInfo<Value>& args) {
2499
2574
Environment* env = Environment::GetCurrent (args);
@@ -2711,6 +2786,7 @@ void Initialize(Local<Object> target,
2711
2786
session->SetClassName (http2SessionClassName);
2712
2787
session->InstanceTemplate ()->SetInternalFieldCount (1 );
2713
2788
AsyncWrap::AddWrapMethods (env, session);
2789
+ env->SetProtoMethod (session, " altsvc" , Http2Session::AltSvc);
2714
2790
env->SetProtoMethod (session, " ping" , Http2Session::Ping);
2715
2791
env->SetProtoMethod (session, " consume" , Http2Session::Consume);
2716
2792
env->SetProtoMethod (session, " destroy" , Http2Session::Destroy);
0 commit comments