• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     : env_(other.env_),
135       name_(std::move(other.name_)),
136       value_(std::move(other.value_)),
137       token_(other.token_),
138       flags_(other.flags_) {
139   other.token_ = -1;
140   other.flags_ = 0;
141   other.env_ = nullptr;
142 }
143 
144 template <typename T>
MemoryInfo(MemoryTracker * tracker)145 void NgHeader<T>::MemoryInfo(MemoryTracker* tracker) const {
146   tracker->TrackField("name", name_);
147   tracker->TrackField("value", value_);
148 }
149 
150 template <typename T>
GetName(NgHeader<T>::allocator_t * allocator)151 v8::MaybeLocal<v8::String> NgHeader<T>::GetName(
152     NgHeader<T>::allocator_t* allocator) const {
153 
154   // Not all instances will support using token id's for header names.
155   // HTTP/2 specifically does not support it.
156   const char* header_name = T::ToHttpHeaderName(token_);
157 
158   // If header_name is not nullptr, then it is a known header with
159   // a statically defined name. We can safely internalize it here.
160   if (header_name != nullptr) {
161     auto& static_str_map = env_->isolate_data()->static_str_map;
162     v8::Eternal<v8::String> eternal = static_str_map[header_name];
163     if (eternal.IsEmpty()) {
164       v8::Local<v8::String> str = OneByteString(env_->isolate(), header_name);
165       eternal.Set(env_->isolate(), str);
166       return str;
167     }
168     return eternal.Get(env_->isolate());
169   }
170   return rcbufferpointer_t::External::New(allocator, name_);
171 }
172 
173 template <typename T>
GetValue(NgHeader<T>::allocator_t * allocator)174 v8::MaybeLocal<v8::String> NgHeader<T>::GetValue(
175     NgHeader<T>::allocator_t* allocator) const {
176   return rcbufferpointer_t::External::New(allocator, value_);
177 }
178 
179 template <typename T>
name()180 std::string NgHeader<T>::name() const {
181   return name_.str();
182 }
183 
184 template <typename T>
value()185 std::string NgHeader<T>::value() const {
186   return value_.str();
187 }
188 
189 template <typename T>
length()190 size_t NgHeader<T>::length() const {
191   return name_.len() + value_.len();
192 }
193 
194 template <typename T>
flags()195 uint8_t NgHeader<T>::flags() const {
196   return flags_;
197 }
198 
199 }  // namespace node
200 
201 #endif  // SRC_NODE_HTTP_COMMON_INL_H_
202