summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJames M Snell <jasnell@gmail.com>2018-09-16 19:13:11 -0700
committerJames M Snell <jasnell@gmail.com>2018-09-21 13:23:08 -0700
commitb92ce5165f91eec1f312bb9f762357e673f83501 (patch)
tree26b2416d55c157aba43e76953f3abebb8e65343f /src
parentc55ebd8502352c6405bfd8c3b356285ccdd242fd (diff)
downloadandroid-node-v8-b92ce5165f91eec1f312bb9f762357e673f83501.tar.gz
android-node-v8-b92ce5165f91eec1f312bb9f762357e673f83501.tar.bz2
android-node-v8-b92ce5165f91eec1f312bb9f762357e673f83501.zip
http2: add origin frame support
PR-URL: https://github.com/nodejs/node/pull/22956 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/env.h1
-rw-r--r--src/node_http2.cc126
-rw-r--r--src/node_http2.h27
3 files changed, 147 insertions, 7 deletions
diff --git a/src/env.h b/src/env.h
index df56194501..aafb3f6e0c 100644
--- a/src/env.h
+++ b/src/env.h
@@ -224,6 +224,7 @@ struct PackageConfig {
V(onnewsession_string, "onnewsession") \
V(onocspresponse_string, "onocspresponse") \
V(ongoawaydata_string, "ongoawaydata") \
+ V(onorigin_string, "onorigin") \
V(onpriority_string, "onpriority") \
V(onread_string, "onread") \
V(onreadstart_string, "onreadstart") \
diff --git a/src/node_http2.cc b/src/node_http2.cc
index 4d47291ace..837d58c81c 100644
--- a/src/node_http2.cc
+++ b/src/node_http2.cc
@@ -95,7 +95,7 @@ Http2Scope::~Http2Scope() {
// instances to configure an appropriate nghttp2_options struct. The class
// uses a single TypedArray instance that is shared with the JavaScript side
// to more efficiently pass values back and forth.
-Http2Options::Http2Options(Environment* env) {
+Http2Options::Http2Options(Environment* env, nghttp2_session_type type) {
nghttp2_option_new(&options_);
// We manually handle flow control within a session in order to
@@ -106,10 +106,12 @@ 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);
+ // Enable built in support for receiving ALTSVC and ORIGIN frames (but
+ // only on client side sessions
+ if (type == NGHTTP2_SESSION_CLIENT) {
+ nghttp2_option_set_builtin_recv_extension_type(options_, NGHTTP2_ALTSVC);
+ nghttp2_option_set_builtin_recv_extension_type(options_, NGHTTP2_ORIGIN);
+ }
AliasedBuffer<uint32_t, Uint32Array>& buffer =
env->http2_state()->options_buffer;
@@ -413,6 +415,56 @@ Headers::Headers(Isolate* isolate,
}
}
+Origins::Origins(Isolate* isolate,
+ Local<Context> context,
+ Local<String> origin_string,
+ size_t origin_count) : count_(origin_count) {
+ int origin_string_len = origin_string->Length();
+ if (count_ == 0) {
+ CHECK_EQ(origin_string_len, 0);
+ return;
+ }
+
+ // Allocate a single buffer with count_ nghttp2_nv structs, followed
+ // by the raw header data as passed from JS. This looks like:
+ // | possible padding | nghttp2_nv | nghttp2_nv | ... | header contents |
+ buf_.AllocateSufficientStorage((alignof(nghttp2_origin_entry) - 1) +
+ count_ * sizeof(nghttp2_origin_entry) +
+ origin_string_len);
+
+ // Make sure the start address is aligned appropriately for an nghttp2_nv*.
+ char* start = reinterpret_cast<char*>(
+ ROUND_UP(reinterpret_cast<uintptr_t>(*buf_),
+ alignof(nghttp2_origin_entry)));
+ char* origin_contents = start + (count_ * sizeof(nghttp2_origin_entry));
+ nghttp2_origin_entry* const nva =
+ reinterpret_cast<nghttp2_origin_entry*>(start);
+
+ CHECK_LE(origin_contents + origin_string_len, *buf_ + buf_.length());
+ CHECK_EQ(origin_string->WriteOneByte(
+ isolate,
+ reinterpret_cast<uint8_t*>(origin_contents),
+ 0,
+ origin_string_len,
+ String::NO_NULL_TERMINATION),
+ origin_string_len);
+
+ size_t n = 0;
+ char* p;
+ for (p = origin_contents; p < origin_contents + origin_string_len; n++) {
+ if (n >= count_) {
+ static uint8_t zero = '\0';
+ nva[0].origin = &zero;
+ nva[0].origin_len = 1;
+ count_ = 1;
+ return;
+ }
+
+ nva[n].origin = reinterpret_cast<uint8_t*>(p);
+ nva[n].origin_len = strlen(p);
+ p += nva[n].origin_len + 1;
+ }
+}
// Sets the various callback functions that nghttp2 will use to notify us
// about significant events while processing http2 stuff.
@@ -548,7 +600,7 @@ Http2Session::Http2Session(Environment* env,
statistics_.start_time = uv_hrtime();
// Capture the configuration options for this session
- Http2Options opts(env);
+ Http2Options opts(env, type);
max_session_memory_ = opts.GetMaxSessionMemory();
@@ -933,6 +985,9 @@ int Http2Session::OnFrameReceive(nghttp2_session* handle,
case NGHTTP2_ALTSVC:
session->HandleAltSvcFrame(frame);
break;
+ case NGHTTP2_ORIGIN:
+ session->HandleOriginFrame(frame);
+ break;
default:
break;
}
@@ -1365,6 +1420,41 @@ void Http2Session::HandleAltSvcFrame(const nghttp2_frame* frame) {
MakeCallback(env()->onaltsvc_string(), arraysize(argv), argv);
}
+void Http2Session::HandleOriginFrame(const nghttp2_frame* frame) {
+ Isolate* isolate = env()->isolate();
+ HandleScope scope(isolate);
+ Local<Context> context = env()->context();
+ Context::Scope context_scope(context);
+
+ Debug(this, "handling origin frame");
+
+ nghttp2_extension ext = frame->ext;
+ nghttp2_ext_origin* origin = static_cast<nghttp2_ext_origin*>(ext.payload);
+
+ Local<Array> holder = Array::New(isolate);
+ Local<Function> fn = env()->push_values_to_array_function();
+ Local<Value> argv[NODE_PUSH_VAL_TO_ARRAY_MAX];
+
+ size_t n = 0;
+ while (n < origin->nov) {
+ size_t j = 0;
+ while (n < origin->nov && j < arraysize(argv)) {
+ auto entry = origin->ov[n++];
+ argv[j++] =
+ String::NewFromOneByte(isolate,
+ entry.origin,
+ v8::NewStringType::kNormal,
+ entry.origin_len).ToLocalChecked();
+ }
+ if (j > 0)
+ fn->Call(context, holder, j, argv).ToLocalChecked();
+ }
+
+ Local<Value> args[1] = { holder };
+
+ MakeCallback(env()->onorigin_string(), arraysize(args), args);
+}
+
// Called by OnFrameReceived when a complete PING frame has been received.
void Http2Session::HandlePingFrame(const nghttp2_frame* frame) {
bool ack = frame->hd.flags & NGHTTP2_FLAG_ACK;
@@ -2613,6 +2703,11 @@ void Http2Session::AltSvc(int32_t id,
origin, origin_len, value, value_len), 0);
}
+void Http2Session::Origin(nghttp2_origin_entry* ov, size_t count) {
+ Http2Scope h2scope(this);
+ CHECK_EQ(nghttp2_submit_origin(session_, NGHTTP2_FLAG_NONE, ov, count), 0);
+}
+
// Submits an AltSvc frame to be sent to the connected peer.
void Http2Session::AltSvc(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@@ -2641,6 +2736,24 @@ void Http2Session::AltSvc(const FunctionCallbackInfo<Value>& args) {
session->AltSvc(id, *origin, origin_len, *value, value_len);
}
+void Http2Session::Origin(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+ Local<Context> context = env->context();
+ Http2Session* session;
+ ASSIGN_OR_RETURN_UNWRAP(&session, args.Holder());
+
+ Local<String> origin_string = args[0].As<String>();
+ int count = args[1]->IntegerValue(context).ToChecked();
+
+
+ Origins origins(env->isolate(),
+ env->context(),
+ origin_string,
+ count);
+
+ session->Origin(*origins, origins.length());
+}
+
// Submits a PING frame to be sent to the connected peer.
void Http2Session::Ping(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@@ -2874,6 +2987,7 @@ void Initialize(Local<Object> target,
session->SetClassName(http2SessionClassName);
session->InstanceTemplate()->SetInternalFieldCount(1);
AsyncWrap::AddWrapMethods(env, session);
+ env->SetProtoMethod(session, "origin", Http2Session::Origin);
env->SetProtoMethod(session, "altsvc", Http2Session::AltSvc);
env->SetProtoMethod(session, "ping", Http2Session::Ping);
env->SetProtoMethod(session, "consume", Http2Session::Consume);
diff --git a/src/node_http2.h b/src/node_http2.h
index d7f8d9acae..7fa230979a 100644
--- a/src/node_http2.h
+++ b/src/node_http2.h
@@ -364,7 +364,7 @@ class Http2Scope {
// configured.
class Http2Options {
public:
- explicit Http2Options(Environment* env);
+ Http2Options(Environment* env, nghttp2_session_type type);
~Http2Options() {
nghttp2_option_del(options_);
@@ -700,6 +700,8 @@ class Http2Session : public AsyncWrap, public StreamListener {
size_t origin_len,
uint8_t* value,
size_t value_len);
+ void Origin(nghttp2_origin_entry* ov, size_t count);
+
bool Ping(v8::Local<v8::Function> function);
@@ -796,6 +798,7 @@ class Http2Session : public AsyncWrap, public StreamListener {
static void RefreshState(const FunctionCallbackInfo<Value>& args);
static void Ping(const FunctionCallbackInfo<Value>& args);
static void AltSvc(const FunctionCallbackInfo<Value>& args);
+ static void Origin(const FunctionCallbackInfo<Value>& args);
template <get_setting fn>
static void RefreshSettings(const FunctionCallbackInfo<Value>& args);
@@ -871,6 +874,7 @@ class Http2Session : public AsyncWrap, public StreamListener {
void HandleSettingsFrame(const nghttp2_frame* frame);
void HandlePingFrame(const nghttp2_frame* frame);
void HandleAltSvcFrame(const nghttp2_frame* frame);
+ void HandleOriginFrame(const nghttp2_frame* frame);
// nghttp2 callbacks
static int OnBeginHeadersCallback(
@@ -1224,6 +1228,27 @@ class Headers {
MaybeStackBuffer<char, 3000> buf_;
};
+class Origins {
+ public:
+ Origins(Isolate* isolate,
+ Local<Context> context,
+ Local<v8::String> origin_string,
+ size_t origin_count);
+ ~Origins() {}
+
+ nghttp2_origin_entry* operator*() {
+ return reinterpret_cast<nghttp2_origin_entry*>(*buf_);
+ }
+
+ size_t length() const {
+ return count_;
+ }
+
+ private:
+ size_t count_;
+ MaybeStackBuffer<char, 512> buf_;
+};
+
} // namespace http2
} // namespace node