@@ -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];
@@ -830,6 +835,10 @@ inline int Http2Session::OnFrameReceive(nghttp2_session* handle,
830
835
break ;
831
836
case NGHTTP2_PING:
832
837
session->HandlePingFrame (frame);
838
+ break ;
839
+ case NGHTTP2_ALTSVC:
840
+ session->HandleAltSvcFrame (frame);
841
+ break ;
833
842
default :
834
843
break ;
835
844
}
@@ -1168,6 +1177,34 @@ inline void Http2Session::HandleGoawayFrame(const nghttp2_frame* frame) {
1168
1177
MakeCallback (env ()->ongoawaydata_string (), arraysize (argv), argv);
1169
1178
}
1170
1179
1180
+ // Called by OnFrameReceived when a complete ALTSVC frame has been received.
1181
+ inline void Http2Session::HandleAltSvcFrame (const nghttp2_frame* frame) {
1182
+ Isolate* isolate = env ()->isolate ();
1183
+ HandleScope scope (isolate);
1184
+ Local<Context> context = env ()->context ();
1185
+ Context::Scope context_scope (context);
1186
+
1187
+ int32_t id = GetFrameID (frame);
1188
+
1189
+ nghttp2_extension ext = frame->ext ;
1190
+ nghttp2_ext_altsvc* altsvc = static_cast <nghttp2_ext_altsvc*>(ext.payload );
1191
+ DEBUG_HTTP2SESSION (this , " handling altsvc frame" );
1192
+
1193
+ Local<Value> argv[3 ] = {
1194
+ Integer::New (isolate, id),
1195
+ String::NewFromOneByte (isolate,
1196
+ altsvc->origin ,
1197
+ v8::NewStringType::kNormal ,
1198
+ altsvc->origin_len ).ToLocalChecked (),
1199
+ String::NewFromOneByte (isolate,
1200
+ altsvc->field_value ,
1201
+ v8::NewStringType::kNormal ,
1202
+ altsvc->field_value_len ).ToLocalChecked (),
1203
+ };
1204
+
1205
+ MakeCallback (env ()->onaltsvc_string (), arraysize (argv), argv);
1206
+ }
1207
+
1171
1208
// Called by OnFrameReceived when a complete PING frame has been received.
1172
1209
inline void Http2Session::HandlePingFrame (const nghttp2_frame* frame) {
1173
1210
bool ack = frame->hd .flags & NGHTTP2_FLAG_ACK;
@@ -2477,6 +2514,44 @@ void Http2Stream::RefreshState(const FunctionCallbackInfo<Value>& args) {
2477
2514
}
2478
2515
}
2479
2516
2517
+ void Http2Session::AltSvc (int32_t id,
2518
+ uint8_t * origin,
2519
+ size_t origin_len,
2520
+ uint8_t * value,
2521
+ size_t value_len) {
2522
+ Http2Scope h2scope (this );
2523
+ CHECK_EQ (nghttp2_submit_altsvc (session_, NGHTTP2_FLAG_NONE, id,
2524
+ origin, origin_len, value, value_len), 0 );
2525
+ }
2526
+
2527
+ // Submits an AltSvc frame to the sent to the connected peer.
2528
+ void Http2Session::AltSvc (const FunctionCallbackInfo<Value>& args) {
2529
+ Environment* env = Environment::GetCurrent (args);
2530
+ Http2Session* session;
2531
+ ASSIGN_OR_RETURN_UNWRAP (&session, args.Holder ());
2532
+
2533
+ int32_t id = args[0 ]->Int32Value (env->context ()).ToChecked ();
2534
+
2535
+ // origin and value are both required to be ASCII, handle them as such.
2536
+ Local<String> origin_str = args[1 ]->ToString (env->context ()).ToLocalChecked ();
2537
+ Local<String> value_str = args[2 ]->ToString (env->context ()).ToLocalChecked ();
2538
+
2539
+ size_t origin_len = origin_str->Length ();
2540
+ size_t value_len = value_str->Length ();
2541
+
2542
+ CHECK_LE (origin_len + value_len, 16382 ); // Max permitted for ALTSVC
2543
+ // Verify that origin len != 0 if stream id == 0, or
2544
+ // that origin len == 0 if stream id != 0
2545
+ CHECK ((origin_len != 0 && id == 0 ) || (origin_len == 0 && id != 0 ));
2546
+
2547
+ MaybeStackBuffer<uint8_t > origin (origin_len);
2548
+ MaybeStackBuffer<uint8_t > value (value_len);
2549
+ origin_str->WriteOneByte (*origin);
2550
+ value_str->WriteOneByte (*value);
2551
+
2552
+ session->AltSvc (id, *origin, origin_len, *value, value_len);
2553
+ }
2554
+
2480
2555
// Submits a PING frame to be sent to the connected peer.
2481
2556
void Http2Session::Ping (const FunctionCallbackInfo<Value>& args) {
2482
2557
Environment* env = Environment::GetCurrent (args);
@@ -2694,6 +2769,7 @@ void Initialize(Local<Object> target,
2694
2769
session->SetClassName (http2SessionClassName);
2695
2770
session->InstanceTemplate ()->SetInternalFieldCount (1 );
2696
2771
AsyncWrap::AddWrapMethods (env, session);
2772
+ env->SetProtoMethod (session, " altsvc" , Http2Session::AltSvc);
2697
2773
env->SetProtoMethod (session, " ping" , Http2Session::Ping);
2698
2774
env->SetProtoMethod (session, " consume" , Http2Session::Consume);
2699
2775
env->SetProtoMethod (session, " destroy" , Http2Session::Destroy);
0 commit comments