#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 namespace node { template NgHeaders::NgHeaders(Environment* env, v8::Local headers) { v8::Local header_string = headers->Get(env->context(), 0).ToLocalChecked(); v8::Local header_count = headers->Get(env->context(), 1).ToLocalChecked(); CHECK(header_count->IsUint32()); CHECK(header_string->IsString()); count_ = header_count.As()->Value(); int header_string_len = header_string.As()->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 = AlignUp(buf_.out(), alignof(nv_t)); char* header_contents = start + (count_ * sizeof(nv_t)); nv_t* const nva = reinterpret_cast(start); CHECK_LE(header_contents + header_string_len, *buf_ + buf_.length()); CHECK_EQ(header_string.As()->WriteOneByte( env->isolate(), reinterpret_cast(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].name = reinterpret_cast(p); nva[n].namelen = strlen(p); p += nva[n].namelen + 1; nva[n].value = reinterpret_cast(p); nva[n].valuelen = strlen(p); p += nva[n].valuelen + 1; nva[n].flags = *p; p++; } } 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 std::string NgHeaderBase::ToString() const { std::string ret = name(); ret += " = "; ret += value(); return ret; } template bool NgHeader::IsZeroLength( NgHeader::rcbuf_t* name, NgHeader::rcbuf_t* value) { return IsZeroLength(-1, name, value); } template bool NgHeader::IsZeroLength( int32_t token, NgHeader::rcbuf_t* name, NgHeader::rcbuf_t* value) { if (NgHeader::rcbufferpointer_t::IsZeroLength(value)) return true; const char* header_name = T::ToHttpHeaderName(token); return header_name != nullptr || NgHeader::rcbufferpointer_t::IsZeroLength(name); } template NgHeader::NgHeader( Environment* env, NgHeader::rcbuf_t* name, NgHeader::rcbuf_t* value, uint8_t flags) : NgHeader(env, -1, name, value, flags) {} template NgHeader::NgHeader( Environment* env, int32_t token, NgHeader::rcbuf_t* name, NgHeader::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 NgHeader::NgHeader(NgHeader&& other) noexcept : name_(std::move(other.name_)), value_(std::move(other.value_)), token_(other.token_), flags_(other.flags_) { other.token_ = -1; other.flags_ = 0; other.env_ = nullptr; } template void NgHeader::MemoryInfo(MemoryTracker* tracker) const { tracker->TrackField("name", name_); tracker->TrackField("value", value_); } template v8::MaybeLocal NgHeader::GetName( NgHeader::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()->static_str_map; v8::Eternal eternal = static_str_map[header_name]; if (eternal.IsEmpty()) { v8::Local 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 v8::MaybeLocal NgHeader::GetValue( NgHeader::allocator_t* allocator) const { return rcbufferpointer_t::External::New(allocator, value_); } template std::string NgHeader::name() const { return name_.str(); } template std::string NgHeader::value() const { return value_.str(); } template size_t NgHeader::length() const { return name_.len() + value_.len(); } template uint8_t NgHeader::flags() const { return flags_; } } // namespace node #endif // SRC_NODE_HTTP_COMMON_INL_H_