Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames M Snell <jasnell@gmail.com>2020-03-03 04:27:06 +0300
committerMyles Borins <mylesborins@google.com>2020-03-10 01:59:17 +0300
commita03777096ea495821f1c234c947fd52b4cdba50c (patch)
treeb1f53a4c2bfd1dfc59b936f4832f85a05501c067 /src/node_http_common-inl.h
parent50094de274309b417cfdd4b1b3bdb550a6b60594 (diff)
src,http2: introduce node_http_common
The nghttp2 and nghttp3 (used in the QUIC implementation) share nearly identical structs for header handling. However, they differ enough that they need to be handled slightly different in each case. This PR includes some elements introduced in the QUIC PR separated out to make them independently reviewable, and updates the http2 implementation to use the shared utilities. Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/32069 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Diffstat (limited to 'src/node_http_common-inl.h')
-rw-r--r--src/node_http_common-inl.h181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/node_http_common-inl.h b/src/node_http_common-inl.h
new file mode 100644
index 00000000000..1bc7b46d63a
--- /dev/null
+++ b/src/node_http_common-inl.h
@@ -0,0 +1,181 @@
+#ifndef SRC_NODE_HTTP_COMMON_INL_H_
+#define SRC_NODE_HTTP_COMMON_INL_H_
+
+#include "node_http_common.h"
+#include "node.h"
+#include "node_mem-inl.h"
+#include "env-inl.h"
+#include "v8.h"
+
+#include <algorithm>
+
+namespace node {
+
+template <typename T>
+NgHeaders<T>::NgHeaders(Environment* env, v8::Local<v8::Array> headers) {
+ v8::Local<v8::Value> header_string =
+ headers->Get(env->context(), 0).ToLocalChecked();
+ v8::Local<v8::Value> header_count =
+ headers->Get(env->context(), 1).ToLocalChecked();
+ CHECK(header_count->IsUint32());
+ CHECK(header_string->IsString());
+ count_ = header_count.As<v8::Uint32>()->Value();
+ int header_string_len = header_string.As<v8::String>()->Length();
+
+ if (count_ == 0) {
+ CHECK_EQ(header_string_len, 0);
+ return;
+ }
+
+ buf_.AllocateSufficientStorage((alignof(nv_t) - 1) +
+ count_ * sizeof(nv_t) +
+ header_string_len);
+
+ char* start = reinterpret_cast<char*>(
+ RoundUp(reinterpret_cast<uintptr_t>(*buf_), alignof(nv_t)));
+ char* header_contents = start + (count_ * sizeof(nv_t));
+ nv_t* const nva = reinterpret_cast<nv_t*>(start);
+
+ CHECK_LE(header_contents + header_string_len, *buf_ + buf_.length());
+ CHECK_EQ(header_string.As<v8::String>()->WriteOneByte(
+ env->isolate(),
+ reinterpret_cast<uint8_t*>(header_contents),
+ 0,
+ header_string_len,
+ v8::String::NO_NULL_TERMINATION),
+ header_string_len);
+
+ size_t n = 0;
+ char* p;
+ for (p = header_contents; p < header_contents + header_string_len; n++) {
+ if (n >= count_) {
+ static uint8_t zero = '\0';
+ nva[0].name = nva[0].value = &zero;
+ nva[0].namelen = nva[0].valuelen = 1;
+ count_ = 1;
+ return;
+ }
+
+ nva[n].flags = T::kNoneFlag;
+ nva[n].name = reinterpret_cast<uint8_t*>(p);
+ nva[n].namelen = strlen(p);
+ p += nva[n].namelen + 1;
+ nva[n].value = reinterpret_cast<uint8_t*>(p);
+ nva[n].valuelen = strlen(p);
+ p += nva[n].valuelen + 1;
+ }
+}
+
+size_t GetClientMaxHeaderPairs(size_t max_header_pairs) {
+ static constexpr size_t min_header_pairs = 1;
+ return std::max(max_header_pairs, min_header_pairs);
+}
+
+size_t GetServerMaxHeaderPairs(size_t max_header_pairs) {
+ static constexpr size_t min_header_pairs = 4;
+ return std::max(max_header_pairs, min_header_pairs);
+}
+
+template <typename T>
+bool NgHeader<T>::IsZeroLength(
+ NgHeader<T>::rcbuf_t* name,
+ NgHeader<T>::rcbuf_t* value) {
+ return IsZeroLength(-1, name, value);
+}
+
+template <typename T>
+bool NgHeader<T>::IsZeroLength(
+ int32_t token,
+ NgHeader<T>::rcbuf_t* name,
+ NgHeader<T>::rcbuf_t* value) {
+
+ if (NgHeader<T>::rcbufferpointer_t::IsZeroLength(value))
+ return true;
+
+ const char* header_name = T::ToHttpHeaderName(token);
+ return header_name != nullptr ||
+ NgHeader<T>::rcbufferpointer_t::IsZeroLength(name);
+}
+
+template <typename T>
+NgHeader<T>::NgHeader(
+ Environment* env,
+ NgHeader<T>::rcbuf_t* name,
+ NgHeader<T>::rcbuf_t* value,
+ uint8_t flags)
+ : NgHeader<T>(env, -1, name, value, flags) {}
+
+template <typename T>
+NgHeader<T>::NgHeader(
+ Environment* env,
+ int32_t token,
+ NgHeader<T>::rcbuf_t* name,
+ NgHeader<T>::rcbuf_t* value,
+ uint8_t flags) : env_(env), token_(token), flags_(flags) {
+ if (token == -1) {
+ CHECK_NOT_NULL(name);
+ name_.reset(name, true); // Internalizable
+ }
+ CHECK_NOT_NULL(value);
+ name_.reset(name, true); // Internalizable
+ value_.reset(value);
+}
+
+template <typename T>
+NgHeader<T>::NgHeader(NgHeader<T>&& other) noexcept
+ : token_(other.token_),
+ name_(std::move(other.name_)),
+ value_(std::move(other.value_)),
+ flags_(other.flags_) {
+ other.token_ = -1;
+ other.flags_ = 0;
+ other.env_ = nullptr;
+}
+
+template <typename T>
+v8::MaybeLocal<v8::String> NgHeader<T>::GetName(
+ NgHeader<T>::allocator_t* allocator) const {
+
+ // Not all instances will support using token id's for header names.
+ // HTTP/2 specifically does not support it.
+ const char* header_name = T::ToHttpHeaderName(token_);
+
+ // If header_name is not nullptr, then it is a known header with
+ // a statically defined name. We can safely internalize it here.
+ if (header_name != nullptr) {
+ auto& static_str_map = env_->isolate_data()->http_static_strs;
+ v8::Eternal<v8::String> eternal = static_str_map[header_name];
+ if (eternal.IsEmpty()) {
+ v8::Local<v8::String> str = OneByteString(env_->isolate(), header_name);
+ eternal.Set(env_->isolate(), str);
+ return str;
+ }
+ return eternal.Get(env_->isolate());
+ }
+ return rcbufferpointer_t::External::New(allocator, name_);
+}
+
+template <typename T>
+v8::MaybeLocal<v8::String> NgHeader<T>::GetValue(
+ NgHeader<T>::allocator_t* allocator) const {
+ return rcbufferpointer_t::External::New(allocator, value_);
+}
+
+template <typename T>
+std::string NgHeader<T>::name() const {
+ return name_.str();
+}
+
+template <typename T>
+std::string NgHeader<T>::value() const {
+ return value_.str();
+}
+
+template <typename T>
+size_t NgHeader<T>::length() const {
+ return name_.len() + value_.len();
+}
+
+} // namespace node
+
+#endif // SRC_NODE_HTTP_COMMON_INL_H_