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/singleton/const_singleton.h"
14

            
15
#include "absl/strings/match.h"
16

            
17
namespace Envoy {
18
namespace Http {
19

            
20
bool HeaderStringValidator::disable_validation_for_tests_ = false;
21

            
22
namespace {
23

            
24
constexpr absl::string_view DelimiterForInlineHeaders{","};
25
constexpr absl::string_view DelimiterForInlineCookies{"; "};
26
const static int kMinHeadersForLazyMap = 3; // Optimal hard-coded value based on benchmarks.
27

            
28
36187
absl::string_view delimiterByHeader(const LowerCaseString& key) {
29
36187
  if (key == Http::Headers::get().Cookie) {
30
36001
    return DelimiterForInlineCookies;
31
36001
  }
32
186
  return DelimiterForInlineHeaders;
33
36187
}
34

            
35
} // namespace
36

            
37
// Initialize as a Type::Reference
38
HeaderString::HeaderString(const LowerCaseString& ref_value) noexcept
39
2910631
    : UnionStringBase(absl::string_view(ref_value.get().c_str(), ref_value.get().size())) {
40
2910631
  ASSERT(valid());
41
2910631
}
42

            
43
1
HeaderString::HeaderString(UnionString&& move_value) noexcept {
44
1
  buffer_ = std::move(move_value.storage());
45
1
  move_value.clear();
46
1
  ASSERT(valid());
47
1
}
48

            
49
// Specialization needed for HeaderMapImpl::HeaderList::insert() when key is LowerCaseString.
50
// A fully specialized template must be defined once in the program, hence this may not be in
51
// a header file.
52
2859600
template <> bool HeaderMapImpl::HeaderList::isPseudoHeader(const LowerCaseString& key) {
53
2859600
  return key.get().c_str()[0] == ':';
54
2859600
}
55

            
56
327584
bool HeaderMapImpl::HeaderList::maybeMakeMap() {
57
327584
  if (lazy_map_.empty()) {
58
141264
    if (headers_.size() < kMinHeadersForLazyMap) {
59
10132
      return false;
60
10132
    }
61
    // Add all entries from the list into the map.
62
913236
    for (auto node = headers_.begin(); node != headers_.end(); ++node) {
63
782104
      HeaderNodeVector& v = lazy_map_[node->key().getStringView()];
64
782104
      v.push_back(node);
65
782104
    }
66
131132
  }
67
317452
  return true;
68
327584
}
69

            
70
7436
size_t HeaderMapImpl::HeaderList::remove(absl::string_view key) {
71
7436
  size_t removed_bytes = 0;
72
7436
  if (maybeMakeMap()) {
73
5151
    auto iter = lazy_map_.find(key);
74
5151
    if (iter != lazy_map_.end()) {
75
      // Erase from the map, and all same key entries from the list.
76
1034
      HeaderNodeVector header_nodes = std::move(iter->second);
77
1034
      lazy_map_.erase(iter);
78
1191
      for (const HeaderNode& node : header_nodes) {
79
1191
        ASSERT(node->key() == key);
80
1191
        removed_bytes += node->key().size() + node->value().size();
81
1191
        erase(node, false /* remove_from_map */);
82
1191
      }
83
1034
    }
84
6902
  } else {
85
    // Erase all same key entries from the list.
86
4887
    for (auto i = headers_.begin(); i != headers_.end();) {
87
2602
      if (i->key() == key) {
88
137
        removed_bytes += i->key().size() + i->value().size();
89
137
        i = erase(i, false /* remove_from_map */);
90
2522
      } else {
91
2465
        ++i;
92
2465
      }
93
2602
    }
94
2285
  }
95
7436
  return removed_bytes;
96
7436
}
97

            
98
537041
HeaderMapImpl::HeaderEntryImpl::HeaderEntryImpl(const LowerCaseString& key) : key_(key) {}
99

            
100
HeaderMapImpl::HeaderEntryImpl::HeaderEntryImpl(const LowerCaseString& key, HeaderString&& value)
101
2322559
    : key_(key), value_(std::move(value)) {}
102

            
103
HeaderMapImpl::HeaderEntryImpl::HeaderEntryImpl(HeaderString&& key, HeaderString&& value)
104
973312
    : key_(std::move(key)), value_(std::move(value)) {}
105

            
106
void HeaderMapImpl::HeaderEntryImpl::value(absl::string_view value) { value_.setCopy(value); }
107

            
108
void HeaderMapImpl::HeaderEntryImpl::value(uint64_t value) { value_.setInteger(value); }
109

            
110
void HeaderMapImpl::HeaderEntryImpl::value(const HeaderEntry& header) {
111
  value(header.value().getStringView());
112
}
113

            
114
869
template <> HeaderMapImpl::StaticLookupTable<RequestHeaderMap>::StaticLookupTable() {
115
869
#define REGISTER_DEFAULT_REQUEST_HEADER(name)                                                      \
116
42581
  CustomInlineHeaderRegistry::registerInlineHeader<RequestHeaderMap::header_map_type>(             \
117
42581
      Headers::get().name);
118
32153
  INLINE_REQ_HEADERS(REGISTER_DEFAULT_REQUEST_HEADER)
119
10428
  INLINE_REQ_RESP_HEADERS(REGISTER_DEFAULT_REQUEST_HEADER)
120

            
121
869
  auto input = finalizedTable();
122

            
123
  // Special case where we map a legacy host header to :authority.
124
869
  const auto handle =
125
869
      CustomInlineHeaderRegistry::getInlineHeader<RequestHeaderMap::header_map_type>(
126
869
          Headers::get().Host);
127
869
  input.emplace_back(
128
41735
      Headers::get().HostLegacy.get(), [handle](HeaderMapImpl& h) -> StaticLookupResponse {
129
41238
        return {&h.inlineHeaders()[handle.value().it_->second], &handle.value().it_->first};
130
41238
      });
131
869
  compile(std::move(input));
132
869
}
133

            
134
581
template <> HeaderMapImpl::StaticLookupTable<RequestTrailerMap>::StaticLookupTable() {
135
581
  compile(finalizedTable());
136
581
}
137

            
138
772
template <> HeaderMapImpl::StaticLookupTable<ResponseHeaderMap>::StaticLookupTable() {
139
772
#define REGISTER_RESPONSE_HEADER(name)                                                             \
140
18528
  CustomInlineHeaderRegistry::registerInlineHeader<ResponseHeaderMap::header_map_type>(            \
141
18528
      Headers::get().name);
142
7720
  INLINE_RESP_HEADERS(REGISTER_RESPONSE_HEADER)
143
9264
  INLINE_REQ_RESP_HEADERS(REGISTER_RESPONSE_HEADER)
144
1544
  INLINE_RESP_HEADERS_TRAILERS(REGISTER_RESPONSE_HEADER)
145

            
146
772
  compile(finalizedTable());
147
772
}
148

            
149
608
template <> HeaderMapImpl::StaticLookupTable<ResponseTrailerMap>::StaticLookupTable() {
150
608
#define REGISTER_RESPONSE_TRAILER(name)                                                            \
151
1216
  CustomInlineHeaderRegistry::registerInlineHeader<ResponseTrailerMap::header_map_type>(           \
152
1216
      Headers::get().name);
153
1216
  INLINE_RESP_HEADERS_TRAILERS(REGISTER_RESPONSE_TRAILER)
154

            
155
608
  compile(finalizedTable());
156
608
}
157

            
158
uint64_t HeaderMapImpl::appendToHeader(HeaderString& header, absl::string_view data,
159
42323
                                       absl::string_view delimiter) {
160
42323
  if (data.empty()) {
161
2
    return 0;
162
2
  }
163
42321
  uint64_t byte_size = 0;
164
42321
  if (!header.empty()) {
165
36236
    header.append(delimiter.data(), delimiter.size());
166
36236
    byte_size += delimiter.size();
167
36236
  }
168
42321
  header.append(data.data(), data.size());
169
42321
  return data.size() + byte_size;
170
42323
}
171

            
172
3008596
void HeaderMapImpl::updateSize(uint64_t from_size, uint64_t to_size) {
173
3008596
  ASSERT(cached_byte_size_ >= from_size);
174
3008596
  cached_byte_size_ -= from_size;
175
3008596
  cached_byte_size_ += to_size;
176
3008596
}
177

            
178
4007577
void HeaderMapImpl::addSize(uint64_t size) { cached_byte_size_ += size; }
179

            
180
151042
void HeaderMapImpl::subtractSize(uint64_t size) {
181
151042
  ASSERT(cached_byte_size_ >= size);
182
151042
  cached_byte_size_ -= size;
183
151042
}
184

            
185
107741
void HeaderMapImpl::copyFrom(HeaderMap& lhs, const HeaderMap& header_map) {
186
351403
  header_map.iterate([&lhs](const HeaderEntry& header) -> HeaderMap::Iterate {
187
    // TODO(mattklein123) PERF: Avoid copying here if not necessary.
188
351373
    HeaderString key_string;
189
351373
    key_string.setCopy(header.key().getStringView());
190
351373
    HeaderString value_string;
191
351373
    value_string.setCopy(header.value().getStringView());
192

            
193
351373
    lhs.addViaMove(std::move(key_string), std::move(value_string));
194
351373
    return HeaderMap::Iterate::Continue;
195
351373
  });
196
107741
}
197

            
198
namespace {
199

            
200
// This is currently only used in tests and is not optimized for performance.
201
HeaderMap::ConstIterateCb
202
679
collectAllHeaders(std::vector<std::pair<absl::string_view, absl::string_view>>* dest) {
203
2382
  return [dest](const HeaderEntry& header) -> HeaderMap::Iterate {
204
2373
    dest->push_back(std::make_pair(header.key().getStringView(), header.value().getStringView()));
205
2373
    return HeaderMap::Iterate::Continue;
206
2373
  };
207
679
};
208

            
209
} // namespace
210

            
211
// This is currently only used in tests and is not optimized for performance.
212
680
bool HeaderMapImpl::operator==(const HeaderMap& rhs) const {
213
680
  if (size() != rhs.size()) {
214
1
    return false;
215
1
  }
216

            
217
679
  std::vector<std::pair<absl::string_view, absl::string_view>> rhs_headers;
218
679
  rhs_headers.reserve(rhs.size());
219
679
  rhs.iterate(collectAllHeaders(&rhs_headers));
220

            
221
679
  auto i = headers_.begin();
222
679
  auto j = rhs_headers.begin();
223
3049
  for (; i != headers_.end(); ++i, ++j) {
224
2372
    if (i->key() != j->first || i->value() != j->second) {
225
2
      return false;
226
2
    }
227
2372
  }
228

            
229
677
  return true;
230
679
}
231

            
232
8
bool HeaderMapImpl::operator!=(const HeaderMap& rhs) const { return !operator==(rhs); }
233

            
234
3295990
void HeaderMapImpl::insertByKey(HeaderString&& key, HeaderString&& value) {
235
3295990
  auto lookup = staticLookup(key.getStringView());
236
3295990
  if (lookup.has_value()) {
237
2322674
    key.clear();
238
2322681
    if (*lookup.value().entry_ == nullptr) {
239
2322567
      maybeCreateInline(lookup.value().entry_, *lookup.value().key_, std::move(value));
240
2234855
    } else {
241
114
      const auto delimiter = delimiterByHeader(*lookup.value().key_);
242
114
      const uint64_t added_size =
243
114
          appendToHeader((*lookup.value().entry_)->value(), value.getStringView(), delimiter);
244
114
      addSize(added_size);
245
114
      value.clear();
246
114
    }
247
3004950
  } else {
248
973316
    addSize(key.size() + value.size());
249
973316
    HeaderNode i = headers_.insert(std::move(key), std::move(value));
250
973316
    i->entry_ = i;
251
973316
  }
252
3295990
}
253

            
254
1576827
void HeaderMapImpl::addViaMove(HeaderString&& key, HeaderString&& value) {
255
1576827
  insertByKey(std::move(key), std::move(value));
256
1576827
}
257

            
258
1436
void HeaderMapImpl::addReference(const LowerCaseString& key, absl::string_view value) {
259
1436
  HeaderString ref_key(key);
260
1436
  HeaderString ref_value(value);
261
1436
  insertByKey(std::move(ref_key), std::move(ref_value));
262
1436
}
263

            
264
179
void HeaderMapImpl::addReferenceKey(const LowerCaseString& key, uint64_t value) {
265
179
  HeaderString ref_key(key);
266
179
  HeaderString new_value;
267
179
  new_value.setInteger(value);
268
179
  insertByKey(std::move(ref_key), std::move(new_value));
269
179
  ASSERT(new_value.empty()); // NOLINT(bugprone-use-after-move)
270
179
}
271

            
272
7638
void HeaderMapImpl::addReferenceKey(const LowerCaseString& key, absl::string_view value) {
273
7638
  HeaderString ref_key(key);
274
7638
  HeaderString new_value;
275
7638
  new_value.setCopy(value);
276
7638
  insertByKey(std::move(ref_key), std::move(new_value));
277
7638
  ASSERT(new_value.empty()); // NOLINT(bugprone-use-after-move)
278
7638
}
279

            
280
1470
void HeaderMapImpl::addCopy(const LowerCaseString& key, uint64_t value) {
281
  // In the case that the header is appended, we will perform a needless copy of the key and value.
282
  // This is done on purpose to keep the code simple and should be rare.
283
1470
  HeaderString new_key;
284
1470
  new_key.setCopy(key.get());
285
1470
  HeaderString new_value;
286
1470
  new_value.setInteger(value);
287
1470
  insertByKey(std::move(new_key), std::move(new_value));
288
1470
  ASSERT(new_key.empty());   // NOLINT(bugprone-use-after-move)
289
1470
  ASSERT(new_value.empty()); // NOLINT(bugprone-use-after-move)
290
1470
}
291

            
292
1708442
void HeaderMapImpl::addCopy(const LowerCaseString& key, absl::string_view value) {
293
  // In the case that the header is appended, we will perform a needless copy of the key and value.
294
  // This is done on purpose to keep the code simple and should be rare.
295
1708442
  HeaderString new_key;
296
1708442
  new_key.setCopy(key.get());
297
1708442
  HeaderString new_value;
298
1708442
  new_value.setCopy(value);
299
1708442
  insertByKey(std::move(new_key), std::move(new_value));
300
1708442
  ASSERT(new_key.empty());   // NOLINT(bugprone-use-after-move)
301
1708442
  ASSERT(new_value.empty()); // NOLINT(bugprone-use-after-move)
302
1708442
}
303

            
304
36304
void HeaderMapImpl::appendCopy(const LowerCaseString& key, absl::string_view value) {
305
  // TODO(#9221): converge on and document a policy for coalescing multiple headers.
306
36304
  auto entry = getExisting(key);
307
36304
  if (!entry.empty()) {
308
36074
    const auto delimiter = delimiterByHeader(key);
309
36074
    const uint64_t added_size = appendToHeader(entry[0]->value(), value, delimiter);
310
36074
    addSize(added_size);
311
36257
  } else {
312
230
    addCopy(key, value);
313
230
  }
314
36304
}
315

            
316
739
void HeaderMapImpl::setReference(const LowerCaseString& key, absl::string_view value) {
317
739
  remove(key);
318
739
  addReference(key, value);
319
739
}
320

            
321
1005
void HeaderMapImpl::setReferenceKey(const LowerCaseString& key, absl::string_view value) {
322
1005
  remove(key);
323
1005
  addReferenceKey(key, value);
324
1005
}
325

            
326
3486
void HeaderMapImpl::setCopy(const LowerCaseString& key, absl::string_view value) {
327
3486
  remove(key);
328
3486
  addCopy(key, value);
329
3486
}
330

            
331
1725469
uint64_t HeaderMapImpl::byteSize() const { return cached_byte_size_; }
332

            
333
3748066
void HeaderMapImpl::verifyByteSizeInternalForTest() const {
334
  // Computes the total byte size by summing the byte size of the keys and values.
335
3748066
  uint64_t byte_size = 0;
336
36844210
  for (const HeaderEntryImpl& header : headers_) {
337
36843809
    byte_size += header.key().size();
338
36843809
    byte_size += header.value().size();
339
36843809
  }
340
3748066
  ASSERT(cached_byte_size_ == byte_size);
341
3748066
}
342

            
343
810352
HeaderMap::GetResult HeaderMapImpl::get(const LowerCaseString& key) const {
344
810352
  return HeaderMap::GetResult(const_cast<HeaderMapImpl*>(this)->getExisting(key));
345
810352
}
346

            
347
846655
HeaderMap::NonConstGetResult HeaderMapImpl::getExisting(absl::string_view key) {
348
  // Attempt a trie lookup first to see if the user is requesting an O(1) header. This may be
349
  // relatively common in certain header matching / routing patterns.
350
  // TODO(mattklein123): Add inline handle support directly to the header matcher code to support
351
  // this use case more directly.
352
846655
  HeaderMap::NonConstGetResult ret;
353
846655
  auto lookup = staticLookup(key);
354
846655
  if (lookup.has_value()) {
355
526509
    if (*lookup.value().entry_ != nullptr) {
356
301182
      ret.push_back(*lookup.value().entry_);
357
301182
    }
358
526509
    return ret;
359
526509
  }
360

            
361
  // If the requested header is not an O(1) header try using the lazy map to
362
  // search for it instead of iterating the headers list.
363
320147
  if (headers_.maybeMakeMap()) {
364
312300
    HeaderList::HeaderLazyMap::iterator iter = headers_.mapFind(key);
365
312300
    if (iter != headers_.mapEnd()) {
366
65506
      const HeaderList::HeaderNodeVector& v = iter->second;
367
65506
      ASSERT(!v.empty()); // It's impossible to have a map entry with an empty vector as its value.
368
67844
      for (const auto& values_it : v) {
369
        // Convert the iterated value to a HeaderEntry*.
370
67844
        ret.push_back(&(*values_it));
371
67844
      }
372
65506
    }
373
312300
    return ret;
374
312300
  }
375

            
376
  // If the requested header is not an O(1) header and the lazy map is not in use, we do a full
377
  // scan. Doing the trie lookup is wasteful in the miss case, but is present for code consistency
378
  // with other functions that do similar things.
379
12220
  for (HeaderEntryImpl& header : headers_) {
380
10858
    if (header.key() == key) {
381
2075
      ret.push_back(&header);
382
2075
    }
383
10858
  }
384

            
385
7847
  return ret;
386
320146
}
387

            
388
436657
void HeaderMapImpl::iterate(HeaderMap::ConstIterateCb cb) const {
389
2501760
  for (const HeaderEntryImpl& header : headers_) {
390
2501671
    if (cb(header) == HeaderMap::Iterate::Break) {
391
3171
      break;
392
3171
    }
393
2501671
  }
394
436657
}
395

            
396
1
void HeaderMapImpl::iterateReverse(HeaderMap::ConstIterateCb cb) const {
397
2
  for (auto it = headers_.rbegin(); it != headers_.rend(); it++) {
398
2
    if (cb(*it) == HeaderMap::Iterate::Break) {
399
1
      break;
400
1
    }
401
2
  }
402
1
}
403

            
404
333
void HeaderMapImpl::clear() {
405
333
  clearInline();
406
333
  headers_.clear();
407
333
  cached_byte_size_ = 0;
408
333
}
409

            
410
11
size_t HeaderMapImpl::removeIf(const HeaderMap::HeaderMatchPredicate& predicate) {
411
11
  const size_t old_size = headers_.size();
412
44
  headers_.removeIf([&predicate, this](const HeaderEntryImpl& entry) {
413
44
    const bool to_remove = predicate(entry);
414
44
    if (to_remove) {
415
      // If this header should be removed, make sure any references in the
416
      // static lookup table are cleared as well.
417
15
      auto lookup = staticLookup(entry.key().getStringView());
418
15
      if (lookup.has_value()) {
419
3
        if (lookup.value().entry_) {
420
3
          const uint32_t key_value_size =
421
3
              (*lookup.value().entry_)->key().size() + (*lookup.value().entry_)->value().size();
422
3
          subtractSize(key_value_size);
423
3
          *lookup.value().entry_ = nullptr;
424
3
        }
425
14
      } else {
426
12
        subtractSize(entry.key().size() + entry.value().size());
427
12
      }
428
15
    }
429
44
    return to_remove;
430
44
  });
431
11
  return old_size - headers_.size();
432
11
}
433

            
434
10263
size_t HeaderMapImpl::remove(const LowerCaseString& key) { return removeExisting(key); }
435

            
436
6
size_t HeaderMapImpl::removePrefix(const LowerCaseString& prefix) {
437
16
  return HeaderMapImpl::removeIf([&prefix](const HeaderEntry& entry) -> bool {
438
16
    return absl::StartsWith(entry.key().getStringView(), prefix.get());
439
16
  });
440
6
}
441

            
442
559
void HeaderMapImpl::dumpState(std::ostream& os, int indent_level) const {
443
559
  iterate([&os,
444
3093
           spaces = spacesForLevel(indent_level)](const HeaderEntry& header) -> HeaderMap::Iterate {
445
3092
    os << spaces << "'" << header.key().getStringView() << "', '" << header.value().getStringView()
446
3092
       << "'\n";
447
3092
    return HeaderMap::Iterate::Continue;
448
3092
  });
449
559
}
450

            
451
HeaderMapImpl::HeaderEntryImpl& HeaderMapImpl::maybeCreateInline(HeaderEntryImpl** entry,
452
3147075
                                                                 const LowerCaseString& key) {
453
3147075
  if (*entry) {
454
2610034
    return **entry;
455
2610034
  }
456

            
457
537041
  addSize(key.get().size());
458
537041
  HeaderNode i = headers_.insert(key);
459
537041
  i->entry_ = i;
460
537041
  *entry = &(*i);
461
537041
  return **entry;
462
3147075
}
463

            
464
HeaderMapImpl::HeaderEntryImpl& HeaderMapImpl::maybeCreateInline(HeaderEntryImpl** entry,
465
                                                                 const LowerCaseString& key,
466
2322567
                                                                 HeaderString&& value) {
467
2322567
  if (*entry) {
468
    value.clear();
469
    return **entry;
470
  }
471

            
472
2322567
  addSize(key.get().size() + value.size());
473
2322567
  HeaderNode i = headers_.insert(key, std::move(value));
474
2322567
  i->entry_ = i;
475
2322567
  *entry = &(*i);
476
2322567
  return **entry;
477
2322567
}
478

            
479
10263
size_t HeaderMapImpl::removeExisting(absl::string_view key) {
480
10263
  const size_t old_size = headers_.size();
481
10263
  auto lookup = staticLookup(key);
482
10263
  if (lookup.has_value()) {
483
2827
    removeInline(lookup.value().entry_);
484
9430
  } else {
485
7436
    subtractSize(headers_.remove(key));
486
7436
  }
487
10263
  return old_size - headers_.size();
488
10263
}
489

            
490
2505707
size_t HeaderMapImpl::removeInline(HeaderEntryImpl** ptr_to_entry) {
491
2505707
  if (!*ptr_to_entry) {
492
2494459
    return 0;
493
2494459
  }
494

            
495
11248
  HeaderEntryImpl* entry = *ptr_to_entry;
496
11248
  const uint64_t size_to_subtract = entry->entry_->key().size() + entry->entry_->value().size();
497
11248
  subtractSize(size_to_subtract);
498
11248
  *ptr_to_entry = nullptr;
499
11248
  headers_.erase(entry->entry_, true);
500
11248
  return 1;
501
2505707
}
502

            
503
88
ProtobufTypes::MessagePtr TunnelResponseHeadersOrTrailersImpl::serializeAsProto() const {
504
88
  auto proto_out = std::make_unique<envoy::config::core::v3::HeaderMap>();
505
176
  value().iterate([&proto_out](const HeaderEntry& e) -> HeaderMap::Iterate {
506
176
    auto* new_header = proto_out->add_headers();
507
176
    new_header->set_key(std::string(e.key().getStringView()));
508
176
    new_header->set_value(std::string(e.value().getStringView()));
509
176
    return HeaderMap::Iterate::Continue;
510
176
  });
511
88
  return proto_out;
512
88
}
513

            
514
namespace {
515
template <class T>
516
42684
HeaderMapImplUtility::HeaderMapImplInfo makeHeaderMapImplInfo(absl::string_view name) {
517
  // Constructing a header map implementation will force the custom headers and sizing to be
518
  // finalized, so do that first.
519
42684
  auto header_map = T::create();
520

            
521
42684
  HeaderMapImplUtility::HeaderMapImplInfo info;
522
42684
  info.name_ = std::string(name);
523
42684
  info.size_ = T::inlineHeadersSize() + sizeof(T);
524
804487
  for (const auto& header : CustomInlineHeaderRegistry::headers<T::header_map_type>()) {
525
804487
    info.registered_headers_.push_back(header.first.get());
526
804487
  }
527
42684
  return info;
528
42684
}
529
} // namespace
530

            
531
std::vector<HeaderMapImplUtility::HeaderMapImplInfo>
532
10671
HeaderMapImplUtility::getAllHeaderMapImplInfo() {
533
10671
  std::vector<HeaderMapImplUtility::HeaderMapImplInfo> ret;
534
10671
  ret.push_back(makeHeaderMapImplInfo<RequestHeaderMapImpl>("request header map"));
535
10671
  ret.push_back(makeHeaderMapImplInfo<RequestTrailerMapImpl>("request trailer map"));
536
10671
  ret.push_back(makeHeaderMapImplInfo<ResponseHeaderMapImpl>("response header map"));
537
10671
  ret.push_back(makeHeaderMapImplInfo<ResponseTrailerMapImpl>("response trailer map"));
538
10671
  return ret;
539
10671
}
540

            
541
} // namespace Http
542
} // namespace Envoy