1 #ifndef SRC_NODE_HTTP_COMMON_INL_H_
2 #define SRC_NODE_HTTP_COMMON_INL_H_
3
4 #include "node_http_common.h"
5 #include "node.h"
6 #include "node_mem-inl.h"
7 #include "env-inl.h"
8 #include "v8.h"
9
10 #include <algorithm>
11
12 namespace node {
13
14 template <typename T>
NgHeaders(Environment * env,v8::Local<v8::Array> headers)15 NgHeaders<T>::NgHeaders(Environment* env, v8::Local<v8::Array> headers) {
16 v8::Local<v8::Value> header_string =
17 headers->Get(env->context(), 0).ToLocalChecked();
18 v8::Local<v8::Value> header_count =
19 headers->Get(env->context(), 1).ToLocalChecked();
20 CHECK(header_count->IsUint32());
21 CHECK(header_string->IsString());
22 count_ = header_count.As<v8::Uint32>()->Value();
23 int header_string_len = header_string.As<v8::String>()->Length();
24
25 if (count_ == 0) {
26 CHECK_EQ(header_string_len, 0);
27 return;
28 }
29
30 buf_.AllocateSufficientStorage((alignof(nv_t) - 1) +
31 count_ * sizeof(nv_t) +
32 header_string_len);
33
34 char* start = AlignUp(buf_.out(), alignof(nv_t));
35 char* header_contents = start + (count_ * sizeof(nv_t));
36 nv_t* const nva = reinterpret_cast<nv_t*>(start);
37
38 CHECK_LE(header_contents + header_string_len, *buf_ + buf_.length());
39 CHECK_EQ(header_string.As<v8::String>()->WriteOneByte(
40 env->isolate(),
41 reinterpret_cast<uint8_t*>(header_contents),
42 0,
43 header_string_len,
44 v8::String::NO_NULL_TERMINATION),
45 header_string_len);
46
47 size_t n = 0;
48 char* p;
49 for (p = header_contents; p < header_contents + header_string_len; n++) {
50 if (n >= count_) {
51 static uint8_t zero = '\0';
52 nva[0].name = nva[0].value = &zero;
53 nva[0].namelen = nva[0].valuelen = 1;
54 count_ = 1;
55 return;
56 }
57
58 nva[n].name = reinterpret_cast<uint8_t*>(p);
59 nva[n].namelen = strlen(p);
60 p += nva[n].namelen + 1;
61 nva[n].value = reinterpret_cast<uint8_t*>(p);
62 nva[n].valuelen = strlen(p);
63 p += nva[n].valuelen + 1;
64 nva[n].flags = *p;
65 p++;
66 }
67 }
68
GetClientMaxHeaderPairs(size_t max_header_pairs)69 size_t GetClientMaxHeaderPairs(size_t max_header_pairs) {
70 static constexpr size_t min_header_pairs = 1;
71 return std::max(max_header_pairs, min_header_pairs);
72 }
73
GetServerMaxHeaderPairs(size_t max_header_pairs)74 size_t GetServerMaxHeaderPairs(size_t max_header_pairs) {
75 static constexpr size_t min_header_pairs = 4;
76 return std::max(max_header_pairs, min_header_pairs);
77 }
78
79 template <typename allocator_t>
ToString()80 std::string NgHeaderBase<allocator_t>::ToString() const {
81 std::string ret = name();
82 ret += " = ";
83 ret += value();
84 return ret;
85 }
86
87 template <typename T>
IsZeroLength(NgHeader<T>::rcbuf_t * name,NgHeader<T>::rcbuf_t * value)88 bool NgHeader<T>::IsZeroLength(
89 NgHeader<T>::rcbuf_t* name,
90 NgHeader<T>::rcbuf_t* value) {
91 return IsZeroLength(-1, name, value);
92 }
93
94 template <typename T>
IsZeroLength(int32_t token,NgHeader<T>::rcbuf_t * name,NgHeader<T>::rcbuf_t * value)95 bool NgHeader<T>::IsZeroLength(
96 int32_t token,
97 NgHeader<T>::rcbuf_t* name,
98 NgHeader<T>::rcbuf_t* value) {
99
100 if (NgHeader<T>::rcbufferpointer_t::IsZeroLength(value))
101 return true;
102
103 const char* header_name = T::ToHttpHeaderName(token);
104 return header_name != nullptr ||
105 NgHeader<T>::rcbufferpointer_t::IsZeroLength(name);
106 }
107
108 template <typename T>
NgHeader(Environment * env,NgHeader<T>::rcbuf_t * name,NgHeader<T>::rcbuf_t * value,uint8_t flags)109 NgHeader<T>::NgHeader(
110 Environment* env,
111 NgHeader<T>::rcbuf_t* name,
112 NgHeader<T>::rcbuf_t* value,
113 uint8_t flags)
114 : NgHeader<T>(env, -1, name, value, flags) {}
115
116 template <typename T>
NgHeader(Environment * env,int32_t token,NgHeader<T>::rcbuf_t * name,NgHeader<T>::rcbuf_t * value,uint8_t flags)117 NgHeader<T>::NgHeader(
118 Environment* env,
119 int32_t token,
120 NgHeader<T>::rcbuf_t* name,
121 NgHeader<T>::rcbuf_t* value,
122 uint8_t flags) : env_(env), token_(token), flags_(flags) {
123 if (token == -1) {
124 CHECK_NOT_NULL(name);
125 name_.reset(name, true); // Internalizable
126 }
127 CHECK_NOT_NULL(value);
128 name_.reset(name, true); // Internalizable
129 value_.reset(value);
130 }
131
132 template <typename T>
NgHeader(NgHeader<T> && other)133 NgHeader<T>::NgHeader(NgHeader<T>&& other) noexcept
134 : name_(std::move(other.name_)),
135 value_(std::move(other.value_)),
136 token_(other.token_),
137 flags_(other.flags_) {
138 other.token_ = -1;
139 other.flags_ = 0;
140 other.env_ = nullptr;
141 }
142
143 template <typename T>
MemoryInfo(MemoryTracker * tracker)144 void NgHeader<T>::MemoryInfo(MemoryTracker* tracker) const {
145 tracker->TrackField("name", name_);
146 tracker->TrackField("value", value_);
147 }
148
149 template <typename T>
GetName(NgHeader<T>::allocator_t * allocator)150 v8::MaybeLocal<v8::String> NgHeader<T>::GetName(
151 NgHeader<T>::allocator_t* allocator) const {
152
153 // Not all instances will support using token id's for header names.
154 // HTTP/2 specifically does not support it.
155 const char* header_name = T::ToHttpHeaderName(token_);
156
157 // If header_name is not nullptr, then it is a known header with
158 // a statically defined name. We can safely internalize it here.
159 if (header_name != nullptr) {
160 auto& static_str_map = env_->isolate_data()->static_str_map;
161 v8::Eternal<v8::String> eternal = static_str_map[header_name];
162 if (eternal.IsEmpty()) {
163 v8::Local<v8::String> str = OneByteString(env_->isolate(), header_name);
164 eternal.Set(env_->isolate(), str);
165 return str;
166 }
167 return eternal.Get(env_->isolate());
168 }
169 return rcbufferpointer_t::External::New(allocator, name_);
170 }
171
172 template <typename T>
GetValue(NgHeader<T>::allocator_t * allocator)173 v8::MaybeLocal<v8::String> NgHeader<T>::GetValue(
174 NgHeader<T>::allocator_t* allocator) const {
175 return rcbufferpointer_t::External::New(allocator, value_);
176 }
177
178 template <typename T>
name()179 std::string NgHeader<T>::name() const {
180 return name_.str();
181 }
182
183 template <typename T>
value()184 std::string NgHeader<T>::value() const {
185 return value_.str();
186 }
187
188 template <typename T>
length()189 size_t NgHeader<T>::length() const {
190 return name_.len() + value_.len();
191 }
192
193 template <typename T>
flags()194 uint8_t NgHeader<T>::flags() const {
195 return flags_;
196 }
197
198 } // namespace node
199
200 #endif // SRC_NODE_HTTP_COMMON_INL_H_
201