summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJames M Snell <jasnell@gmail.com>2017-12-29 09:44:08 -0800
committerJames M Snell <jasnell@gmail.com>2018-01-03 08:45:58 -0800
commitce22d6f9178507c7a41b04ac4097b9ea902049e3 (patch)
tree4b82a06cff1bb3fde32e4f101cd254111d8f9bf4 /src
parentf51067a85d64b77f2eae2e099092209156d6e602 (diff)
downloadandroid-node-v8-ce22d6f9178507c7a41b04ac4097b9ea902049e3.tar.gz
android-node-v8-ce22d6f9178507c7a41b04ac4097b9ea902049e3.tar.bz2
android-node-v8-ce22d6f9178507c7a41b04ac4097b9ea902049e3.zip
http2: add altsvc support
Add support for sending and receiving ALTSVC frames. PR-URL: https://github.com/nodejs/node/pull/17917 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/env.h1
-rw-r--r--src/node_http2.cc76
-rw-r--r--src/node_http2.h7
3 files changed, 84 insertions, 0 deletions
diff --git a/src/env.h b/src/env.h
index abd089dddd..88c0023707 100644
--- a/src/env.h
+++ b/src/env.h
@@ -179,6 +179,7 @@ class ModuleWrap;
V(netmask_string, "netmask") \
V(nsname_string, "nsname") \
V(ocsp_request_string, "OCSPRequest") \
+ V(onaltsvc_string, "onaltsvc") \
V(onchange_string, "onchange") \
V(onclienthello_string, "onclienthello") \
V(oncomplete_string, "oncomplete") \
diff --git a/src/node_http2.cc b/src/node_http2.cc
index e409cdb579..17265a28cd 100644
--- a/src/node_http2.cc
+++ b/src/node_http2.cc
@@ -103,6 +103,11 @@ Http2Options::Http2Options(Environment* env) {
// are required to buffer.
nghttp2_option_set_no_auto_window_update(options_, 1);
+ // Enable built in support for ALTSVC frames. Once we add support for
+ // other non-built in extension frames, this will need to be handled
+ // a bit differently. For now, let's let nghttp2 take care of it.
+ nghttp2_option_set_builtin_recv_extension_type(options_, NGHTTP2_ALTSVC);
+
AliasedBuffer<uint32_t, v8::Uint32Array>& buffer =
env->http2_state()->options_buffer;
uint32_t flags = buffer[IDX_OPTIONS_FLAGS];
@@ -847,6 +852,10 @@ inline int Http2Session::OnFrameReceive(nghttp2_session* handle,
break;
case NGHTTP2_PING:
session->HandlePingFrame(frame);
+ break;
+ case NGHTTP2_ALTSVC:
+ session->HandleAltSvcFrame(frame);
+ break;
default:
break;
}
@@ -1185,6 +1194,34 @@ inline void Http2Session::HandleGoawayFrame(const nghttp2_frame* frame) {
MakeCallback(env()->ongoawaydata_string(), arraysize(argv), argv);
}
+// Called by OnFrameReceived when a complete ALTSVC frame has been received.
+inline void Http2Session::HandleAltSvcFrame(const nghttp2_frame* frame) {
+ Isolate* isolate = env()->isolate();
+ HandleScope scope(isolate);
+ Local<Context> context = env()->context();
+ Context::Scope context_scope(context);
+
+ int32_t id = GetFrameID(frame);
+
+ nghttp2_extension ext = frame->ext;
+ nghttp2_ext_altsvc* altsvc = static_cast<nghttp2_ext_altsvc*>(ext.payload);
+ DEBUG_HTTP2SESSION(this, "handling altsvc frame");
+
+ Local<Value> argv[3] = {
+ Integer::New(isolate, id),
+ String::NewFromOneByte(isolate,
+ altsvc->origin,
+ v8::NewStringType::kNormal,
+ altsvc->origin_len).ToLocalChecked(),
+ String::NewFromOneByte(isolate,
+ altsvc->field_value,
+ v8::NewStringType::kNormal,
+ altsvc->field_value_len).ToLocalChecked(),
+ };
+
+ MakeCallback(env()->onaltsvc_string(), arraysize(argv), argv);
+}
+
// Called by OnFrameReceived when a complete PING frame has been received.
inline void Http2Session::HandlePingFrame(const nghttp2_frame* frame) {
bool ack = frame->hd.flags & NGHTTP2_FLAG_ACK;
@@ -2494,6 +2531,44 @@ void Http2Stream::RefreshState(const FunctionCallbackInfo<Value>& args) {
}
}
+void Http2Session::AltSvc(int32_t id,
+ uint8_t* origin,
+ size_t origin_len,
+ uint8_t* value,
+ size_t value_len) {
+ Http2Scope h2scope(this);
+ CHECK_EQ(nghttp2_submit_altsvc(session_, NGHTTP2_FLAG_NONE, id,
+ origin, origin_len, value, value_len), 0);
+}
+
+// Submits an AltSvc frame to the sent to the connected peer.
+void Http2Session::AltSvc(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+ Http2Session* session;
+ ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
+
+ int32_t id = args[0]->Int32Value(env->context()).ToChecked();
+
+ // origin and value are both required to be ASCII, handle them as such.
+ Local<String> origin_str = args[1]->ToString(env->context()).ToLocalChecked();
+ Local<String> value_str = args[2]->ToString(env->context()).ToLocalChecked();
+
+ size_t origin_len = origin_str->Length();
+ size_t value_len = value_str->Length();
+
+ CHECK_LE(origin_len + value_len, 16382); // Max permitted for ALTSVC
+ // Verify that origin len != 0 if stream id == 0, or
+ // that origin len == 0 if stream id != 0
+ CHECK((origin_len != 0 && id == 0) || (origin_len == 0 && id != 0));
+
+ MaybeStackBuffer<uint8_t> origin(origin_len);
+ MaybeStackBuffer<uint8_t> value(value_len);
+ origin_str->WriteOneByte(*origin);
+ value_str->WriteOneByte(*value);
+
+ session->AltSvc(id, *origin, origin_len, *value, value_len);
+}
+
// Submits a PING frame to be sent to the connected peer.
void Http2Session::Ping(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@@ -2711,6 +2786,7 @@ void Initialize(Local<Object> target,
session->SetClassName(http2SessionClassName);
session->InstanceTemplate()->SetInternalFieldCount(1);
AsyncWrap::AddWrapMethods(env, session);
+ env->SetProtoMethod(session, "altsvc", Http2Session::AltSvc);
env->SetProtoMethod(session, "ping", Http2Session::Ping);
env->SetProtoMethod(session, "consume", Http2Session::Consume);
env->SetProtoMethod(session, "destroy", Http2Session::Destroy);
diff --git a/src/node_http2.h b/src/node_http2.h
index 1065ee8055..2b8542d951 100644
--- a/src/node_http2.h
+++ b/src/node_http2.h
@@ -800,6 +800,11 @@ class Http2Session : public AsyncWrap {
void Consume(Local<External> external);
void Unconsume();
void Goaway(uint32_t code, int32_t lastStreamID, uint8_t* data, size_t len);
+ void AltSvc(int32_t id,
+ uint8_t* origin,
+ size_t origin_len,
+ uint8_t* value,
+ size_t value_len);
bool Ping(v8::Local<v8::Function> function);
@@ -879,6 +884,7 @@ class Http2Session : public AsyncWrap {
static void UpdateChunksSent(const FunctionCallbackInfo<Value>& args);
static void RefreshState(const FunctionCallbackInfo<Value>& args);
static void Ping(const FunctionCallbackInfo<Value>& args);
+ static void AltSvc(const FunctionCallbackInfo<Value>& args);
template <get_setting fn>
static void RefreshSettings(const FunctionCallbackInfo<Value>& args);
@@ -923,6 +929,7 @@ class Http2Session : public AsyncWrap {
inline void HandlePriorityFrame(const nghttp2_frame* frame);
inline void HandleSettingsFrame(const nghttp2_frame* frame);
inline void HandlePingFrame(const nghttp2_frame* frame);
+ inline void HandleAltSvcFrame(const nghttp2_frame* frame);
// nghttp2 callbacks
static inline int OnBeginHeadersCallback(