/proc/self/cwd/source/common/http/header_map_impl.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include "source/common/http/header_map_impl.h" |
2 | | |
3 | | #include <cstdint> |
4 | | #include <list> |
5 | | #include <memory> |
6 | | #include <string> |
7 | | |
8 | | #include "envoy/http/header_map.h" |
9 | | |
10 | | #include "source/common/common/assert.h" |
11 | | #include "source/common/common/dump_state_utils.h" |
12 | | #include "source/common/common/empty_string.h" |
13 | | #include "source/common/runtime/runtime_features.h" |
14 | | #include "source/common/singleton/const_singleton.h" |
15 | | |
16 | | #include "absl/strings/match.h" |
17 | | |
18 | | namespace Envoy { |
19 | | namespace Http { |
20 | | |
21 | | bool HeaderStringValidator::disable_validation_for_tests_ = false; |
22 | | |
23 | | namespace { |
24 | | |
25 | | constexpr absl::string_view DelimiterForInlineHeaders{","}; |
26 | | constexpr absl::string_view DelimiterForInlineCookies{"; "}; |
27 | | const static int kMinHeadersForLazyMap = 3; // Optimal hard-coded value based on benchmarks. |
28 | | |
29 | 0 | bool validatedLowerCaseString(absl::string_view str) { |
30 | 0 | auto lower_case_str = LowerCaseString(str); |
31 | 0 | return lower_case_str == str; |
32 | 0 | } |
33 | | |
34 | 295k | absl::string_view delimiterByHeader(const LowerCaseString& key) { |
35 | 295k | if (key == Http::Headers::get().Cookie) { |
36 | 7.94k | return DelimiterForInlineCookies; |
37 | 7.94k | } |
38 | 287k | return DelimiterForInlineHeaders; |
39 | 295k | } |
40 | | |
41 | | } // namespace |
42 | | |
43 | | // Initialize as a Type::Reference |
44 | | HeaderString::HeaderString(const LowerCaseString& ref_value) noexcept |
45 | 3.56M | : UnionStringBase(absl::string_view(ref_value.get().c_str(), ref_value.get().size())) { |
46 | 3.56M | ASSERT(valid()); |
47 | 3.56M | } |
48 | | |
49 | 0 | HeaderString::HeaderString(UnionString&& move_value) noexcept { |
50 | 0 | buffer_ = std::move(move_value.storage()); |
51 | 0 | move_value.clear(); |
52 | 0 | ASSERT(valid()); |
53 | 0 | } |
54 | | |
55 | | // Specialization needed for HeaderMapImpl::HeaderList::insert() when key is LowerCaseString. |
56 | | // A fully specialized template must be defined once in the program, hence this may not be in |
57 | | // a header file. |
58 | 3.09M | template <> bool HeaderMapImpl::HeaderList::isPseudoHeader(const LowerCaseString& key) { |
59 | 3.09M | return key.get().c_str()[0] == ':'; |
60 | 3.09M | } |
61 | | |
62 | 546k | bool HeaderMapImpl::HeaderList::maybeMakeMap() { |
63 | 546k | if (lazy_map_.empty()) { |
64 | 182k | if (headers_.size() < kMinHeadersForLazyMap) { |
65 | 85.7k | return false; |
66 | 85.7k | } |
67 | | // Add all entries from the list into the map. |
68 | 658k | for (auto node = headers_.begin(); node != headers_.end(); ++node) { |
69 | 561k | HeaderNodeVector& v = lazy_map_[node->key().getStringView()]; |
70 | 561k | v.push_back(node); |
71 | 561k | } |
72 | 96.7k | } |
73 | 460k | return true; |
74 | 546k | } |
75 | | |
76 | 161k | size_t HeaderMapImpl::HeaderList::remove(absl::string_view key) { |
77 | 161k | size_t removed_bytes = 0; |
78 | 161k | if (maybeMakeMap()) { |
79 | 135k | auto iter = lazy_map_.find(key); |
80 | 135k | if (iter != lazy_map_.end()) { |
81 | | // Erase from the map, and all same key entries from the list. |
82 | 78.7k | HeaderNodeVector header_nodes = std::move(iter->second); |
83 | 78.7k | lazy_map_.erase(iter); |
84 | 98.4k | for (const HeaderNode& node : header_nodes) { |
85 | 98.4k | ASSERT(node->key() == key); |
86 | 98.4k | removed_bytes += node->key().size() + node->value().size(); |
87 | 98.4k | erase(node, false /* remove_from_map */); |
88 | 98.4k | } |
89 | 78.7k | } |
90 | 135k | } else { |
91 | | // Erase all same key entries from the list. |
92 | 50.4k | for (auto i = headers_.begin(); i != headers_.end();) { |
93 | 23.9k | if (i->key() == key) { |
94 | 3.47k | removed_bytes += i->key().size() + i->value().size(); |
95 | 3.47k | i = erase(i, false /* remove_from_map */); |
96 | 20.4k | } else { |
97 | 20.4k | ++i; |
98 | 20.4k | } |
99 | 23.9k | } |
100 | 26.4k | } |
101 | 161k | return removed_bytes; |
102 | 161k | } |
103 | | |
104 | 1.09M | HeaderMapImpl::HeaderEntryImpl::HeaderEntryImpl(const LowerCaseString& key) : key_(key) {} |
105 | | |
106 | | HeaderMapImpl::HeaderEntryImpl::HeaderEntryImpl(const LowerCaseString& key, HeaderString&& value) |
107 | 1.99M | : key_(key), value_(std::move(value)) {} |
108 | | |
109 | | HeaderMapImpl::HeaderEntryImpl::HeaderEntryImpl(HeaderString&& key, HeaderString&& value) |
110 | 1.57M | : key_(std::move(key)), value_(std::move(value)) {} |
111 | | |
112 | 0 | void HeaderMapImpl::HeaderEntryImpl::value(absl::string_view value) { value_.setCopy(value); } |
113 | | |
114 | 0 | void HeaderMapImpl::HeaderEntryImpl::value(uint64_t value) { value_.setInteger(value); } |
115 | | |
116 | 0 | void HeaderMapImpl::HeaderEntryImpl::value(const HeaderEntry& header) { |
117 | 0 | value(header.value().getStringView()); |
118 | 0 | } |
119 | | |
120 | 32 | template <> HeaderMapImpl::StaticLookupTable<RequestHeaderMap>::StaticLookupTable() { |
121 | 32 | #define REGISTER_DEFAULT_REQUEST_HEADER(name) \ |
122 | 1.53k | CustomInlineHeaderRegistry::registerInlineHeader<RequestHeaderMap::header_map_type>( \ |
123 | 1.53k | Headers::get().name); |
124 | 1.15k | INLINE_REQ_HEADERS(REGISTER_DEFAULT_REQUEST_HEADER) |
125 | 384 | INLINE_REQ_RESP_HEADERS(REGISTER_DEFAULT_REQUEST_HEADER) |
126 | | |
127 | 32 | finalizeTable(); |
128 | | |
129 | | // Special case where we map a legacy host header to :authority. |
130 | 32 | const auto handle = |
131 | 32 | CustomInlineHeaderRegistry::getInlineHeader<RequestHeaderMap::header_map_type>( |
132 | 32 | Headers::get().Host); |
133 | 26.9k | add(Headers::get().HostLegacy.get().c_str(), [handle](HeaderMapImpl& h) -> StaticLookupResponse { |
134 | 26.9k | return {&h.inlineHeaders()[handle.value().it_->second], &handle.value().it_->first}; |
135 | 26.9k | }); |
136 | 32 | } |
137 | | |
138 | 22 | template <> HeaderMapImpl::StaticLookupTable<RequestTrailerMap>::StaticLookupTable() { |
139 | 22 | finalizeTable(); |
140 | 22 | } |
141 | | |
142 | 26 | template <> HeaderMapImpl::StaticLookupTable<ResponseHeaderMap>::StaticLookupTable() { |
143 | 26 | #define REGISTER_RESPONSE_HEADER(name) \ |
144 | 624 | CustomInlineHeaderRegistry::registerInlineHeader<ResponseHeaderMap::header_map_type>( \ |
145 | 624 | Headers::get().name); |
146 | 260 | INLINE_RESP_HEADERS(REGISTER_RESPONSE_HEADER) |
147 | 312 | INLINE_REQ_RESP_HEADERS(REGISTER_RESPONSE_HEADER) |
148 | 52 | INLINE_RESP_HEADERS_TRAILERS(REGISTER_RESPONSE_HEADER) |
149 | | |
150 | 26 | finalizeTable(); |
151 | 26 | } |
152 | | |
153 | 25 | template <> HeaderMapImpl::StaticLookupTable<ResponseTrailerMap>::StaticLookupTable() { |
154 | 25 | #define REGISTER_RESPONSE_TRAILER(name) \ |
155 | 50 | CustomInlineHeaderRegistry::registerInlineHeader<ResponseTrailerMap::header_map_type>( \ |
156 | 50 | Headers::get().name); |
157 | 50 | INLINE_RESP_HEADERS_TRAILERS(REGISTER_RESPONSE_TRAILER) |
158 | | |
159 | 25 | finalizeTable(); |
160 | 25 | } |
161 | | |
162 | | uint64_t HeaderMapImpl::appendToHeader(HeaderString& header, absl::string_view data, |
163 | 360k | absl::string_view delimiter) { |
164 | 360k | if (data.empty()) { |
165 | 90.3k | return 0; |
166 | 90.3k | } |
167 | 269k | uint64_t byte_size = 0; |
168 | 269k | if (!header.empty()) { |
169 | 201k | header.append(delimiter.data(), delimiter.size()); |
170 | 201k | byte_size += delimiter.size(); |
171 | 201k | } |
172 | 269k | header.append(data.data(), data.size()); |
173 | 269k | return data.size() + byte_size; |
174 | 360k | } |
175 | | |
176 | 1.19M | void HeaderMapImpl::updateSize(uint64_t from_size, uint64_t to_size) { |
177 | 1.19M | ASSERT(cached_byte_size_ >= from_size); |
178 | 1.19M | cached_byte_size_ -= from_size; |
179 | 1.19M | cached_byte_size_ += to_size; |
180 | 1.19M | } |
181 | | |
182 | 5.05M | void HeaderMapImpl::addSize(uint64_t size) { cached_byte_size_ += size; } |
183 | | |
184 | 249k | void HeaderMapImpl::subtractSize(uint64_t size) { |
185 | 249k | ASSERT(cached_byte_size_ >= size); |
186 | 249k | cached_byte_size_ -= size; |
187 | 249k | } |
188 | | |
189 | 346k | void HeaderMapImpl::copyFrom(HeaderMap& lhs, const HeaderMap& header_map) { |
190 | 1.08M | header_map.iterate([&lhs](const HeaderEntry& header) -> HeaderMap::Iterate { |
191 | | // TODO(mattklein123) PERF: Avoid copying here if not necessary. |
192 | 1.08M | HeaderString key_string; |
193 | 1.08M | key_string.setCopy(header.key().getStringView()); |
194 | 1.08M | HeaderString value_string; |
195 | 1.08M | value_string.setCopy(header.value().getStringView()); |
196 | | |
197 | 1.08M | lhs.addViaMove(std::move(key_string), std::move(value_string)); |
198 | 1.08M | return HeaderMap::Iterate::Continue; |
199 | 1.08M | }); |
200 | 346k | } |
201 | | |
202 | | namespace { |
203 | | |
204 | | // This is currently only used in tests and is not optimized for performance. |
205 | | HeaderMap::ConstIterateCb |
206 | 0 | collectAllHeaders(std::vector<std::pair<absl::string_view, absl::string_view>>* dest) { |
207 | 0 | return [dest](const HeaderEntry& header) -> HeaderMap::Iterate { |
208 | 0 | dest->push_back(std::make_pair(header.key().getStringView(), header.value().getStringView())); |
209 | 0 | return HeaderMap::Iterate::Continue; |
210 | 0 | }; |
211 | 0 | }; |
212 | | |
213 | | } // namespace |
214 | | |
215 | | // This is currently only used in tests and is not optimized for performance. |
216 | 0 | bool HeaderMapImpl::operator==(const HeaderMap& rhs) const { |
217 | 0 | if (size() != rhs.size()) { |
218 | 0 | return false; |
219 | 0 | } |
220 | | |
221 | 0 | std::vector<std::pair<absl::string_view, absl::string_view>> rhs_headers; |
222 | 0 | rhs_headers.reserve(rhs.size()); |
223 | 0 | rhs.iterate(collectAllHeaders(&rhs_headers)); |
224 | |
|
225 | 0 | auto i = headers_.begin(); |
226 | 0 | auto j = rhs_headers.begin(); |
227 | 0 | for (; i != headers_.end(); ++i, ++j) { |
228 | 0 | if (i->key() != j->first || i->value() != j->second) { |
229 | 0 | return false; |
230 | 0 | } |
231 | 0 | } |
232 | | |
233 | 0 | return true; |
234 | 0 | } |
235 | | |
236 | 0 | bool HeaderMapImpl::operator!=(const HeaderMap& rhs) const { return !operator==(rhs); } |
237 | | |
238 | 3.85M | void HeaderMapImpl::insertByKey(HeaderString&& key, HeaderString&& value) { |
239 | 3.85M | auto lookup = staticLookup(key.getStringView()); |
240 | 3.85M | if (lookup.has_value()) { |
241 | 2.28M | key.clear(); |
242 | 2.28M | if (*lookup.value().entry_ == nullptr) { |
243 | 1.99M | maybeCreateInline(lookup.value().entry_, *lookup.value().key_, std::move(value)); |
244 | 1.99M | } else { |
245 | 286k | const auto delimiter = delimiterByHeader(*lookup.value().key_); |
246 | 286k | const uint64_t added_size = |
247 | 286k | appendToHeader((*lookup.value().entry_)->value(), value.getStringView(), delimiter); |
248 | 286k | addSize(added_size); |
249 | 286k | value.clear(); |
250 | 286k | } |
251 | 2.28M | } else { |
252 | 1.57M | addSize(key.size() + value.size()); |
253 | 1.57M | HeaderNode i = headers_.insert(std::move(key), std::move(value)); |
254 | 1.57M | i->entry_ = i; |
255 | 1.57M | } |
256 | 3.85M | } |
257 | | |
258 | 2.06M | void HeaderMapImpl::addViaMove(HeaderString&& key, HeaderString&& value) { |
259 | 2.06M | insertByKey(std::move(key), std::move(value)); |
260 | 2.06M | } |
261 | | |
262 | 10.9k | void HeaderMapImpl::addReference(const LowerCaseString& key, absl::string_view value) { |
263 | 10.9k | HeaderString ref_key(key); |
264 | 10.9k | HeaderString ref_value(value); |
265 | 10.9k | insertByKey(std::move(ref_key), std::move(ref_value)); |
266 | 10.9k | } |
267 | | |
268 | 72 | void HeaderMapImpl::addReferenceKey(const LowerCaseString& key, uint64_t value) { |
269 | 72 | HeaderString ref_key(key); |
270 | 72 | HeaderString new_value; |
271 | 72 | new_value.setInteger(value); |
272 | 72 | insertByKey(std::move(ref_key), std::move(new_value)); |
273 | 72 | ASSERT(new_value.empty()); // NOLINT(bugprone-use-after-move) |
274 | 72 | } |
275 | | |
276 | 441k | void HeaderMapImpl::addReferenceKey(const LowerCaseString& key, absl::string_view value) { |
277 | 441k | HeaderString ref_key(key); |
278 | 441k | HeaderString new_value; |
279 | 441k | new_value.setCopy(value); |
280 | 441k | insertByKey(std::move(ref_key), std::move(new_value)); |
281 | 441k | ASSERT(new_value.empty()); // NOLINT(bugprone-use-after-move) |
282 | 441k | } |
283 | | |
284 | 609 | void HeaderMapImpl::addCopy(const LowerCaseString& key, uint64_t value) { |
285 | | // In the case that the header is appended, we will perform a needless copy of the key and value. |
286 | | // This is done on purpose to keep the code simple and should be rare. |
287 | 609 | HeaderString new_key; |
288 | 609 | new_key.setCopy(key.get()); |
289 | 609 | HeaderString new_value; |
290 | 609 | new_value.setInteger(value); |
291 | 609 | insertByKey(std::move(new_key), std::move(new_value)); |
292 | 609 | ASSERT(new_key.empty()); // NOLINT(bugprone-use-after-move) |
293 | 609 | ASSERT(new_value.empty()); // NOLINT(bugprone-use-after-move) |
294 | 609 | } |
295 | | |
296 | 1.33M | void HeaderMapImpl::addCopy(const LowerCaseString& key, absl::string_view value) { |
297 | | // In the case that the header is appended, we will perform a needless copy of the key and value. |
298 | | // This is done on purpose to keep the code simple and should be rare. |
299 | 1.33M | HeaderString new_key; |
300 | 1.33M | new_key.setCopy(key.get()); |
301 | 1.33M | HeaderString new_value; |
302 | 1.33M | new_value.setCopy(value); |
303 | 1.33M | insertByKey(std::move(new_key), std::move(new_value)); |
304 | 1.33M | ASSERT(new_key.empty()); // NOLINT(bugprone-use-after-move) |
305 | 1.33M | ASSERT(new_value.empty()); // NOLINT(bugprone-use-after-move) |
306 | 1.33M | } |
307 | | |
308 | 17.8k | void HeaderMapImpl::appendCopy(const LowerCaseString& key, absl::string_view value) { |
309 | | // TODO(#9221): converge on and document a policy for coalescing multiple headers. |
310 | 17.8k | auto entry = getExisting(key); |
311 | 17.8k | if (!entry.empty()) { |
312 | 8.90k | const auto delimiter = delimiterByHeader(key); |
313 | 8.90k | const uint64_t added_size = appendToHeader(entry[0]->value(), value, delimiter); |
314 | 8.90k | addSize(added_size); |
315 | 8.96k | } else { |
316 | 8.96k | addCopy(key, value); |
317 | 8.96k | } |
318 | 17.8k | } |
319 | | |
320 | 4.20k | void HeaderMapImpl::setReference(const LowerCaseString& key, absl::string_view value) { |
321 | 4.20k | remove(key); |
322 | 4.20k | addReference(key, value); |
323 | 4.20k | } |
324 | | |
325 | 238k | void HeaderMapImpl::setReferenceKey(const LowerCaseString& key, absl::string_view value) { |
326 | 238k | remove(key); |
327 | 238k | addReferenceKey(key, value); |
328 | 238k | } |
329 | | |
330 | 32.0k | void HeaderMapImpl::setCopy(const LowerCaseString& key, absl::string_view value) { |
331 | 32.0k | remove(key); |
332 | 32.0k | addCopy(key, value); |
333 | 32.0k | } |
334 | | |
335 | 1.81M | uint64_t HeaderMapImpl::byteSize() const { return cached_byte_size_; } |
336 | | |
337 | 4.17M | void HeaderMapImpl::verifyByteSizeInternalForTest() const { |
338 | | // Computes the total byte size by summing the byte size of the keys and values. |
339 | 4.17M | uint64_t byte_size = 0; |
340 | 189M | for (const HeaderEntryImpl& header : headers_) { |
341 | 189M | byte_size += header.key().size(); |
342 | 189M | byte_size += header.value().size(); |
343 | 189M | } |
344 | 4.17M | ASSERT(cached_byte_size_ == byte_size); |
345 | 4.17M | } |
346 | | |
347 | 419k | HeaderMap::GetResult HeaderMapImpl::get(const LowerCaseString& key) const { |
348 | 419k | return HeaderMap::GetResult(const_cast<HeaderMapImpl*>(this)->getExisting(key)); |
349 | 419k | } |
350 | | |
351 | 437k | HeaderMap::NonConstGetResult HeaderMapImpl::getExisting(absl::string_view key) { |
352 | | // Attempt a trie lookup first to see if the user is requesting an O(1) header. This may be |
353 | | // relatively common in certain header matching / routing patterns. |
354 | | // TODO(mattklein123): Add inline handle support directly to the header matcher code to support |
355 | | // this use case more directly. |
356 | 437k | HeaderMap::NonConstGetResult ret; |
357 | 437k | auto lookup = staticLookup(key); |
358 | 437k | if (lookup.has_value()) { |
359 | 53.1k | if (*lookup.value().entry_ != nullptr) { |
360 | 30.1k | ret.push_back(*lookup.value().entry_); |
361 | 30.1k | } |
362 | 53.1k | return ret; |
363 | 53.1k | } |
364 | | |
365 | | // If the requested header is not an O(1) header try using the lazy map to |
366 | | // search for it instead of iterating the headers list. |
367 | 384k | if (headers_.maybeMakeMap()) { |
368 | 325k | HeaderList::HeaderLazyMap::iterator iter = headers_.mapFind(key); |
369 | 325k | if (iter != headers_.mapEnd()) { |
370 | 232k | const HeaderList::HeaderNodeVector& v = iter->second; |
371 | 232k | ASSERT(!v.empty()); // It's impossible to have a map entry with an empty vector as its value. |
372 | 441k | for (const auto& values_it : v) { |
373 | | // Convert the iterated value to a HeaderEntry*. |
374 | 441k | ret.push_back(&(*values_it)); |
375 | 441k | } |
376 | 232k | } |
377 | 325k | return ret; |
378 | 325k | } |
379 | | |
380 | | // If the requested header is not an O(1) header and the lazy map is not in use, we do a full |
381 | | // scan. Doing the trie lookup is wasteful in the miss case, but is present for code consistency |
382 | | // with other functions that do similar things. |
383 | 59.3k | for (HeaderEntryImpl& header : headers_) { |
384 | 43.5k | if (header.key() == key) { |
385 | 11.5k | ret.push_back(&header); |
386 | 11.5k | } |
387 | 43.5k | } |
388 | | |
389 | 59.3k | return ret; |
390 | 384k | } |
391 | | |
392 | 643k | void HeaderMapImpl::iterate(HeaderMap::ConstIterateCb cb) const { |
393 | 3.15M | for (const HeaderEntryImpl& header : headers_) { |
394 | 3.15M | if (cb(header) == HeaderMap::Iterate::Break) { |
395 | 13.9k | break; |
396 | 13.9k | } |
397 | 3.15M | } |
398 | 643k | } |
399 | | |
400 | 27.5k | void HeaderMapImpl::iterateReverse(HeaderMap::ConstIterateCb cb) const { |
401 | 392k | for (auto it = headers_.rbegin(); it != headers_.rend(); it++) { |
402 | 364k | if (cb(*it) == HeaderMap::Iterate::Break) { |
403 | 0 | break; |
404 | 0 | } |
405 | 364k | } |
406 | 27.5k | } |
407 | | |
408 | 290k | void HeaderMapImpl::clear() { |
409 | 290k | clearInline(); |
410 | 290k | headers_.clear(); |
411 | 290k | cached_byte_size_ = 0; |
412 | 290k | } |
413 | | |
414 | 1.61k | size_t HeaderMapImpl::removeIf(const HeaderMap::HeaderMatchPredicate& predicate) { |
415 | 1.61k | const size_t old_size = headers_.size(); |
416 | 10.1k | headers_.removeIf([&predicate, this](const HeaderEntryImpl& entry) { |
417 | 10.1k | const bool to_remove = predicate(entry); |
418 | 10.1k | if (to_remove) { |
419 | | // If this header should be removed, make sure any references in the |
420 | | // static lookup table are cleared as well. |
421 | 3.70k | auto lookup = staticLookup(entry.key().getStringView()); |
422 | 3.70k | if (lookup.has_value()) { |
423 | 75 | if (lookup.value().entry_) { |
424 | 75 | const uint32_t key_value_size = |
425 | 75 | (*lookup.value().entry_)->key().size() + (*lookup.value().entry_)->value().size(); |
426 | 75 | subtractSize(key_value_size); |
427 | 75 | *lookup.value().entry_ = nullptr; |
428 | 75 | } |
429 | 3.63k | } else { |
430 | 3.63k | subtractSize(entry.key().size() + entry.value().size()); |
431 | 3.63k | } |
432 | 3.70k | } |
433 | 10.1k | return to_remove; |
434 | 10.1k | }); |
435 | 1.61k | return old_size - headers_.size(); |
436 | 1.61k | } |
437 | | |
438 | 365k | size_t HeaderMapImpl::remove(const LowerCaseString& key) { return removeExisting(key); } |
439 | | |
440 | 1.61k | size_t HeaderMapImpl::removePrefix(const LowerCaseString& prefix) { |
441 | 10.1k | return HeaderMapImpl::removeIf([&prefix](const HeaderEntry& entry) -> bool { |
442 | 10.1k | return absl::StartsWith(entry.key().getStringView(), prefix.get()); |
443 | 10.1k | }); |
444 | 1.61k | } |
445 | | |
446 | 0 | void HeaderMapImpl::dumpState(std::ostream& os, int indent_level) const { |
447 | 0 | iterate([&os, |
448 | 0 | spaces = spacesForLevel(indent_level)](const HeaderEntry& header) -> HeaderMap::Iterate { |
449 | 0 | os << spaces << "'" << header.key().getStringView() << "', '" << header.value().getStringView() |
450 | 0 | << "'\n"; |
451 | 0 | return HeaderMap::Iterate::Continue; |
452 | 0 | }); |
453 | 0 | } |
454 | | |
455 | | HeaderMapImpl::HeaderEntryImpl& HeaderMapImpl::maybeCreateInline(HeaderEntryImpl** entry, |
456 | 1.29M | const LowerCaseString& key) { |
457 | 1.29M | if (*entry) { |
458 | 198k | return **entry; |
459 | 198k | } |
460 | | |
461 | 1.09M | addSize(key.get().size()); |
462 | 1.09M | HeaderNode i = headers_.insert(key); |
463 | 1.09M | i->entry_ = i; |
464 | 1.09M | *entry = &(*i); |
465 | 1.09M | return **entry; |
466 | 1.29M | } |
467 | | |
468 | | HeaderMapImpl::HeaderEntryImpl& HeaderMapImpl::maybeCreateInline(HeaderEntryImpl** entry, |
469 | | const LowerCaseString& key, |
470 | 1.99M | HeaderString&& value) { |
471 | 1.99M | if (*entry) { |
472 | 0 | value.clear(); |
473 | 0 | return **entry; |
474 | 0 | } |
475 | | |
476 | 1.99M | addSize(key.get().size() + value.size()); |
477 | 1.99M | HeaderNode i = headers_.insert(key, std::move(value)); |
478 | 1.99M | i->entry_ = i; |
479 | 1.99M | *entry = &(*i); |
480 | 1.99M | return **entry; |
481 | 1.99M | } |
482 | | |
483 | 365k | size_t HeaderMapImpl::removeExisting(absl::string_view key) { |
484 | 365k | const size_t old_size = headers_.size(); |
485 | 365k | auto lookup = staticLookup(key); |
486 | 365k | if (lookup.has_value()) { |
487 | 203k | removeInline(lookup.value().entry_); |
488 | 203k | } else { |
489 | 161k | subtractSize(headers_.remove(key)); |
490 | 161k | } |
491 | 365k | return old_size - headers_.size(); |
492 | 365k | } |
493 | | |
494 | 2.68M | size_t HeaderMapImpl::removeInline(HeaderEntryImpl** ptr_to_entry) { |
495 | 2.68M | if (!*ptr_to_entry) { |
496 | 2.63M | return 0; |
497 | 2.63M | } |
498 | | |
499 | 48.0k | HeaderEntryImpl* entry = *ptr_to_entry; |
500 | 48.0k | const uint64_t size_to_subtract = entry->entry_->key().size() + entry->entry_->value().size(); |
501 | 48.0k | subtractSize(size_to_subtract); |
502 | 48.0k | *ptr_to_entry = nullptr; |
503 | 48.0k | headers_.erase(entry->entry_, true); |
504 | 48.0k | return 1; |
505 | 2.68M | } |
506 | | |
507 | | namespace { |
508 | | template <class T> |
509 | 21.9k | HeaderMapImplUtility::HeaderMapImplInfo makeHeaderMapImplInfo(absl::string_view name) { |
510 | | // Constructing a header map implementation will force the custom headers and sizing to be |
511 | | // finalized, so do that first. |
512 | 21.9k | auto header_map = T::create(); |
513 | | |
514 | 21.9k | HeaderMapImplUtility::HeaderMapImplInfo info; |
515 | 21.9k | info.name_ = std::string(name); |
516 | 21.9k | info.size_ = T::inlineHeadersSize() + sizeof(T); |
517 | 502k | for (const auto& header : CustomInlineHeaderRegistry::headers<T::header_map_type>()) { |
518 | 502k | info.registered_headers_.push_back(header.first.get()); |
519 | 502k | } |
520 | 21.9k | return info; |
521 | 21.9k | } header_map_impl.cc:Envoy::Http::HeaderMapImplUtility::HeaderMapImplInfo Envoy::Http::(anonymous namespace)::makeHeaderMapImplInfo<Envoy::Http::RequestHeaderMapImpl>(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 509 | 5.48k | HeaderMapImplUtility::HeaderMapImplInfo makeHeaderMapImplInfo(absl::string_view name) { | 510 | | // Constructing a header map implementation will force the custom headers and sizing to be | 511 | | // finalized, so do that first. | 512 | 5.48k | auto header_map = T::create(); | 513 | | | 514 | 5.48k | HeaderMapImplUtility::HeaderMapImplInfo info; | 515 | 5.48k | info.name_ = std::string(name); | 516 | 5.48k | info.size_ = T::inlineHeadersSize() + sizeof(T); | 517 | 320k | for (const auto& header : CustomInlineHeaderRegistry::headers<T::header_map_type>()) { | 518 | 320k | info.registered_headers_.push_back(header.first.get()); | 519 | 320k | } | 520 | 5.48k | return info; | 521 | 5.48k | } |
header_map_impl.cc:Envoy::Http::HeaderMapImplUtility::HeaderMapImplInfo Envoy::Http::(anonymous namespace)::makeHeaderMapImplInfo<Envoy::Http::RequestTrailerMapImpl>(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 509 | 5.48k | HeaderMapImplUtility::HeaderMapImplInfo makeHeaderMapImplInfo(absl::string_view name) { | 510 | | // Constructing a header map implementation will force the custom headers and sizing to be | 511 | | // finalized, so do that first. | 512 | 5.48k | auto header_map = T::create(); | 513 | | | 514 | 5.48k | HeaderMapImplUtility::HeaderMapImplInfo info; | 515 | 5.48k | info.name_ = std::string(name); | 516 | 5.48k | info.size_ = T::inlineHeadersSize() + sizeof(T); | 517 | 5.48k | for (const auto& header : CustomInlineHeaderRegistry::headers<T::header_map_type>()) { | 518 | 0 | info.registered_headers_.push_back(header.first.get()); | 519 | 0 | } | 520 | 5.48k | return info; | 521 | 5.48k | } |
header_map_impl.cc:Envoy::Http::HeaderMapImplUtility::HeaderMapImplInfo Envoy::Http::(anonymous namespace)::makeHeaderMapImplInfo<Envoy::Http::ResponseHeaderMapImpl>(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 509 | 5.48k | HeaderMapImplUtility::HeaderMapImplInfo makeHeaderMapImplInfo(absl::string_view name) { | 510 | | // Constructing a header map implementation will force the custom headers and sizing to be | 511 | | // finalized, so do that first. | 512 | 5.48k | auto header_map = T::create(); | 513 | | | 514 | 5.48k | HeaderMapImplUtility::HeaderMapImplInfo info; | 515 | 5.48k | info.name_ = std::string(name); | 516 | 5.48k | info.size_ = T::inlineHeadersSize() + sizeof(T); | 517 | 171k | for (const auto& header : CustomInlineHeaderRegistry::headers<T::header_map_type>()) { | 518 | 171k | info.registered_headers_.push_back(header.first.get()); | 519 | 171k | } | 520 | 5.48k | return info; | 521 | 5.48k | } |
header_map_impl.cc:Envoy::Http::HeaderMapImplUtility::HeaderMapImplInfo Envoy::Http::(anonymous namespace)::makeHeaderMapImplInfo<Envoy::Http::ResponseTrailerMapImpl>(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 509 | 5.48k | HeaderMapImplUtility::HeaderMapImplInfo makeHeaderMapImplInfo(absl::string_view name) { | 510 | | // Constructing a header map implementation will force the custom headers and sizing to be | 511 | | // finalized, so do that first. | 512 | 5.48k | auto header_map = T::create(); | 513 | | | 514 | 5.48k | HeaderMapImplUtility::HeaderMapImplInfo info; | 515 | 5.48k | info.name_ = std::string(name); | 516 | 5.48k | info.size_ = T::inlineHeadersSize() + sizeof(T); | 517 | 10.9k | for (const auto& header : CustomInlineHeaderRegistry::headers<T::header_map_type>()) { | 518 | 10.9k | info.registered_headers_.push_back(header.first.get()); | 519 | 10.9k | } | 520 | 5.48k | return info; | 521 | 5.48k | } |
|
522 | | } // namespace |
523 | | |
524 | | std::vector<HeaderMapImplUtility::HeaderMapImplInfo> |
525 | 5.48k | HeaderMapImplUtility::getAllHeaderMapImplInfo() { |
526 | 5.48k | std::vector<HeaderMapImplUtility::HeaderMapImplInfo> ret; |
527 | 5.48k | ret.push_back(makeHeaderMapImplInfo<RequestHeaderMapImpl>("request header map")); |
528 | 5.48k | ret.push_back(makeHeaderMapImplInfo<RequestTrailerMapImpl>("request trailer map")); |
529 | 5.48k | ret.push_back(makeHeaderMapImplInfo<ResponseHeaderMapImpl>("response header map")); |
530 | 5.48k | ret.push_back(makeHeaderMapImplInfo<ResponseTrailerMapImpl>("response trailer map")); |
531 | 5.48k | return ret; |
532 | 5.48k | } |
533 | | |
534 | 0 | absl::string_view RequestHeaderMapImpl::protocol() const { return getProtocolValue(); } |
535 | | |
536 | 0 | absl::string_view RequestHeaderMapImpl::host() const { return getHostValue(); } |
537 | | |
538 | 2.97k | absl::string_view RequestHeaderMapImpl::path() const { return getPathValue(); } |
539 | | |
540 | 1.11k | absl::string_view RequestHeaderMapImpl::method() const { return getMethodValue(); } |
541 | | |
542 | 0 | void RequestHeaderMapImpl::forEach(Tracing::TraceContext::IterateCallback callback) const { |
543 | 0 | HeaderMapImpl::iterate([cb = std::move(callback)](const HeaderEntry& entry) { |
544 | 0 | if (cb(entry.key().getStringView(), entry.value().getStringView())) { |
545 | 0 | return HeaderMap::Iterate::Continue; |
546 | 0 | } |
547 | 0 | return HeaderMap::Iterate::Break; |
548 | 0 | }); |
549 | 0 | } |
550 | | |
551 | 0 | absl::optional<absl::string_view> RequestHeaderMapImpl::getByKey(absl::string_view key) const { |
552 | 0 | ASSERT(validatedLowerCaseString(key)); |
553 | 0 | auto result = const_cast<RequestHeaderMapImpl*>(this)->getExisting(key); |
554 | |
|
555 | 0 | if (result.empty()) { |
556 | 0 | return absl::nullopt; |
557 | 0 | } |
558 | 0 | return result[0]->value().getStringView(); |
559 | 0 | } |
560 | | |
561 | 0 | void RequestHeaderMapImpl::setByKey(absl::string_view key, absl::string_view val) { |
562 | 0 | ASSERT(validatedLowerCaseString(key)); |
563 | 0 | HeaderMapImpl::removeExisting(key); |
564 | |
|
565 | 0 | HeaderString new_key; |
566 | 0 | new_key.setCopy(key); |
567 | 0 | HeaderString new_val; |
568 | 0 | new_val.setCopy(val); |
569 | |
|
570 | 0 | HeaderMapImpl::insertByKey(std::move(new_key), std::move(new_val)); |
571 | 0 | } |
572 | | |
573 | 0 | void RequestHeaderMapImpl::setByReferenceKey(absl::string_view key, absl::string_view val) { |
574 | 0 | ASSERT(validatedLowerCaseString(key)); |
575 | 0 | HeaderMapImpl::removeExisting(key); |
576 | |
|
577 | 0 | HeaderString new_val; |
578 | 0 | new_val.setCopy(val); |
579 | |
|
580 | 0 | HeaderMapImpl::insertByKey(HeaderString(key), std::move(new_val)); |
581 | 0 | } |
582 | | |
583 | 0 | void RequestHeaderMapImpl::setByReference(absl::string_view key, absl::string_view val) { |
584 | 0 | ASSERT(validatedLowerCaseString(key)); |
585 | 0 | HeaderMapImpl::removeExisting(key); |
586 | |
|
587 | 0 | HeaderMapImpl::insertByKey(HeaderString(key), HeaderString(val)); |
588 | 0 | } |
589 | | |
590 | 0 | void RequestHeaderMapImpl::removeByKey(absl::string_view key) { |
591 | 0 | ASSERT(validatedLowerCaseString(key)); |
592 | 0 | HeaderMapImpl::removeExisting(key); |
593 | 0 | } |
594 | | |
595 | | } // namespace Http |
596 | | } // namespace Envoy |