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