userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
header_map.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/http/header_map.hpp
4
/// @brief @copybrief http::headers::HeaderMap
5
/// @ingroup userver_universal
6
7
#
include
<
initializer_list
>
8
#
include
<
iterator
>
9
#
include
<
string
>
10
#
include
<
vector
>
11
12
#
include
<
userver
/
formats
/
json_fwd
.
hpp
>
13
#
include
<
userver
/
formats
/
parse
/
to
.
hpp
>
14
#
include
<
userver
/
http
/
predefined_header
.
hpp
>
15
#
include
<
userver
/
utils
/
fast_pimpl
.
hpp
>
16
17
USERVER_NAMESPACE_BEGIN
18
19
namespace
http::
headers
{
20
21
class
TestsHelper;
22
23
/// @brief Internal helpers for `HeaderMap` storage and iteration.
24
namespace
header_map
{
25
class
Map;
26
}
27
28
/// @ingroup userver_universal userver_containers
29
///
30
/// @brief Container that maps case-insensitive header name into header value.
31
///
32
/// Allows storing up to 24576 name->value pairs, after that an attempt to
33
/// insert a new pair will throw.
34
///
35
/// Has an anti-hashdos collisions resolution built-in, and the capacity limit
36
/// might be lowered in case of an attack being detected.
37
///
38
/// Iterators/pointers invalidation loosely matches that of std::vector:
39
/// * if an insertion took place, iterators/pointers are invalidated;
40
/// * successful erase invalidates the iterator being erased and `begin` (it's
41
/// implemented via swap and pop_back idiom, and `begin` is actually an `rbegin`
42
/// of underlying vector).
43
class
HeaderMap
final
{
44
public
:
45
/// Iterator
46
class
Iterator;
47
/// Const iterator
48
class
ConstIterator;
49
50
using
iterator = Iterator;
51
using
const_iterator = ConstIterator;
52
53
using
key_type = std::string;
54
using
mapped_type = std::string;
55
56
/// The exception being thrown in case of capacity overflow
57
class
TooManyHeadersException
final
:
public
std::runtime_error {
58
public
:
59
using
std::runtime_error::runtime_error;
60
61
TooManyHeadersException(
const
TooManyHeadersException&) =
default
;
62
TooManyHeadersException(TooManyHeadersException&&) =
default
;
63
TooManyHeadersException& operator=(
const
TooManyHeadersException&) =
default
;
64
TooManyHeadersException& operator=(TooManyHeadersException&&) =
default
;
65
66
~TooManyHeadersException()
override
;
67
};
68
69
/// Default constructor.
70
HeaderMap
();
71
/// Constructor from initializer list: `HeaderMap({{"a", "b"}, {"c", "d"}})`.
72
/// Its unspecified which pair is inserted in case of names not being unique.
73
/*implicit*/
HeaderMap
(std::initializer_list<std::pair<std::string_view, std::string_view>> headers);
74
/// Constructor with capacity: preallocates `capacity` elements for internal
75
/// storage.
76
explicit
HeaderMap
(std::size_t capacity);
77
/// Constructor from iterator pair:
78
/// `HeaderMap{key_value_pairs.begin(), key_value_pairs.end()}`.
79
/// Its unspecified which pair is inserted in case of names not being unique.
80
template
<
typename
InputIt>
81
HeaderMap
(InputIt first, InputIt last);
82
83
/// Destructor
84
~
HeaderMap
();
85
86
/// Copy constructor
87
HeaderMap
(
const
HeaderMap& other);
88
/// Move constructor
89
HeaderMap
(HeaderMap&& other)
noexcept
;
90
/// Copy assignment operator
91
HeaderMap&
operator
=(
const
HeaderMap& other);
92
/// Move assignment operator
93
HeaderMap&
operator
=(HeaderMap&& other)
noexcept
;
94
95
/// Non-binding call to reserve `capacity` elements for internal storage.
96
void
reserve
(std::size_t capacity);
97
/// Returns the amount of name-value-pairs being stored.
98
std::size_t
size
()
const
noexcept
;
99
/// Return true if no name-value-pairs are being stored, false otherwise.
100
bool
empty
()
const
noexcept
;
101
/// Removes all the key-value-pairs being stored,
102
/// doesn't shrink underlying storage.
103
void
clear
();
104
105
/// Returns 1 if the key exists, 0 otherwise.
106
std::size_t
count
(std::string_view key)
const
noexcept
;
107
/// @overload
108
std::size_t
count
(
const
PredefinedHeader& key)
const
noexcept
;
109
110
template
<std::size_t Size>
111
[[noreturn]] std::size_t count(
const
char
(&)[Size])
const
noexcept
{
112
ReportMisuse<Size>();
113
}
114
115
/// Returns true if the key exists, false otherwise.
116
bool
contains
(std::string_view key)
const
noexcept
;
117
/// @overload
118
bool
contains
(
const
PredefinedHeader& key)
const
noexcept
;
119
120
template
<std::size_t Size>
121
[[noreturn]]
bool
contains(
const
char
(&)[Size])
const
noexcept
{
122
ReportMisuse<Size>();
123
}
124
125
/// If the key is present, returns reference to it's header value,
126
/// otherwise inserts a pair (key, "") and returns reference
127
/// to newly inserted empty string.
128
/// In an insertion took place, key is moved-out,
129
/// otherwise key is left unchanged.
130
std::string&
operator
[](std::string&& key);
131
/// If the key is present, returns reference to it's header value,
132
/// otherwise inserts a pair (key, "") and returns reference
133
/// to newly inserted empty string.
134
std::string&
operator
[](std::string_view key);
135
/// @overload
136
std::string&
operator
[](
const
PredefinedHeader& key);
137
138
template
<std::size_t Size>
139
[[noreturn]] std::string& operator[](
const
char
(&)[Size]) {
140
ReportMisuse<Size>();
141
}
142
143
/// If the key is present, returns iterator to its name-value pair,
144
/// otherwise return end().
145
Iterator
find
(std::string_view key)
noexcept
;
146
/// @overload
147
ConstIterator
find
(std::string_view key)
const
noexcept
;
148
149
/// If the key is present, returns iterator to its name-value pair,
150
/// otherwise return end().
151
Iterator
find
(
const
PredefinedHeader& key)
noexcept
;
152
/// @overload
153
ConstIterator
find
(
const
PredefinedHeader& key)
const
noexcept
;
154
155
template
<std::size_t Size>
156
[[noreturn]] Iterator find(
const
char
(&)[Size])
noexcept
;
157
158
template
<std::size_t Size>
159
[[noreturn]] ConstIterator find(
const
char
(&)[Size])
const
noexcept
;
160
161
/// If the key is already present in the map, does nothing.
162
/// Otherwise inserts a pair of key and in-place constructed value.
163
template
<
typename
... Args>
164
void
emplace
(std::string_view key, Args&&... args) {
165
Emplace(std::move(key), std::forward<Args>(args)...);
166
}
167
168
/// If the key is already present in the map, does nothing.
169
/// Otherwise inserts a pair of key and inplace constructed value.
170
template
<
typename
... Args>
171
void
emplace
(std::string key, Args&&... args) {
172
Emplace(std::move(key), std::forward<Args>(args)...);
173
}
174
175
/// If the key is already present in the map, does nothing.
176
/// Otherwise inserts a pair of key and inplace constructed value.
177
template
<
typename
... Args>
178
void
try_emplace
(std::string key, Args&&... args) {
179
Emplace(std::move(key), std::forward<Args>(args)...);
180
}
181
182
/// For every iterator it in [first, last) inserts *it.
183
/// Its unspecified which pair is inserted in case of names not being unique.
184
template
<
typename
InputIt>
185
void
insert
(InputIt first, InputIt last);
186
187
/// If kvp.first is already present in the map, does nothing,
188
/// otherwise inserts the pair into container.
189
void
insert
(
const
std::pair<std::string, std::string>& kvp);
190
/// If kvp.first is already present in the map, does nothing,
191
/// otherwise inserts the pair into container.
192
void
insert
(std::pair<std::string, std::string>&& kvp);
193
194
/// If key is already present in the map, changes corresponding header value
195
/// to provided value, otherwise inserts the pair into container.
196
void
insert_or_assign
(std::string key, std::string value);
197
/// @overload
198
void
insert_or_assign
(
const
PredefinedHeader& key, std::string value);
199
200
/// If key is already present in the map, appends ",{value}" to the
201
/// corresponding header value, otherwise inserts the pair into container.
202
void
InsertOrAppend
(std::string key, std::string value);
203
/// @overload
204
void
InsertOrAppend
(
const
PredefinedHeader& key, std::string value);
205
206
/// Erases the pair to which the iterator points, returns iterator following
207
/// the last removed element.
208
/// Iterators/pointers to erased value and `begin` are invalidated.
209
Iterator
erase
(Iterator it);
210
/// Erases the pair to which the iterator points, returns iterator following
211
/// the last removed element.
212
/// Iterators/pointers to erased value and `begin` are invalidated.
213
Iterator
erase
(ConstIterator it);
214
215
/// If the key is present in container, behaves exactly like erase(Iterator).
216
/// Otherwise does nothing and returns `end()`.
217
Iterator
erase
(std::string_view key);
218
/// @overload
219
Iterator
erase
(
const
PredefinedHeader& key);
220
221
template
<std::size_t Size>
222
[[noreturn]] Iterator erase(
const
char
(&)[Size]);
223
224
/// If the key is present in container, returns reference to its header value,
225
/// otherwise throws std::out_of_range.
226
std::string&
at
(std::string_view key);
227
/// @overload
228
std::string&
at
(
const
PredefinedHeader& key);
229
/// If the key is present in container, returns reference to its header value,
230
/// otherwise throws std::out_of_range.
231
const
std::string&
at
(std::string_view key)
const
;
232
/// @overload
233
const
std::string&
at
(
const
PredefinedHeader& key)
const
;
234
235
template
<std::size_t Size>
236
[[noreturn]] std::string& at(
const
char
(&)[Size]) {
237
ReportMisuse<Size>();
238
}
239
template
<std::size_t Size>
240
[[noreturn]]
const
std::string& at(
const
char
(&)[Size])
const
{
241
ReportMisuse<Size>();
242
}
243
244
/// Returns an iterator to the first name-value-pair being stored.
245
Iterator
begin
()
noexcept
;
246
/// Returns an iterator to the first name-value-pair being stored.
247
ConstIterator
begin
()
const
noexcept
;
248
/// Returns an iterator to the first name-value-pair being stored.
249
ConstIterator
cbegin
()
const
noexcept
;
250
251
/// Returns an iterator to the end (valid but not dereferenceable).
252
Iterator
end
()
noexcept
;
253
/// Returns an iterator to the end (valid but not dereferenceable).
254
ConstIterator
end
()
const
noexcept
;
255
/// Returns an iterator to the end (valid but not dereferenceable).
256
ConstIterator
cend
()
const
noexcept
;
257
258
/// Returns true if `other` contains exactly the same set of name-value-pairs,
259
/// false otherwise.
260
bool
operator
==(
const
HeaderMap& other)
const
noexcept
;
261
262
/// Appends container content in http headers format to provided buffer,
263
/// that is appends
264
/// @code
265
/// header1: value1\r\n
266
/// header2: value2\r\n
267
/// ...
268
/// @endcode
269
/// resizing buffer as needed.
270
void
OutputInHttpFormat
(HeadersString& buffer)
const
;
271
272
private
:
273
friend
class
TestsHelper;
274
275
template
<
typename
KeyType,
typename
... Args>
276
void
Emplace(KeyType&& key, Args&&... args);
277
278
template
<std::size_t Size>
279
[[noreturn]]
static
void
ReportMisuse();
280
281
utils
::FastPimpl<
header_map
::Map, 272, 8> impl_;
282
};
283
284
template
<
typename
InputIt>
285
HeaderMap::
HeaderMap
(InputIt first, InputIt last)
286
: HeaderMap{}
287
{
288
insert(first, last);
289
}
290
291
template
<
typename
InputIt>
292
void
HeaderMap::
insert
(InputIt first, InputIt last) {
293
for
(; first != last; ++first) {
294
insert(*first);
295
}
296
}
297
298
template
<
typename
KeyType,
typename
... Args>
299
void
HeaderMap::Emplace(KeyType&& key, Args&&... args) {
300
static_assert
(std::is_rvalue_reference_v<
decltype
(key)>);
301
// This is a private function, and we know what we are doing here.
302
// NOLINTNEXTLINE(bugprone-move-forwarding-reference)
303
auto
& value = operator[](std::move(key));
304
if
(value.empty()) {
305
value = std::string{std::forward<Args>(args)...};
306
}
307
}
308
309
template
<std::size_t Size>
310
void
HeaderMap::ReportMisuse() {
311
static_assert
(
312
!Size,
313
"Please create a 'constexpr PredefinedHeader' and use that "
314
"instead of passing header name as a string literal."
315
);
316
}
317
318
namespace
header_map
{
319
320
class
MapEntry
final
{
321
public
:
322
MapEntry();
323
~MapEntry();
324
325
MapEntry(std::string&& key, std::string&& value);
326
327
MapEntry(
const
MapEntry& other);
328
MapEntry& operator=(
const
MapEntry& other);
329
MapEntry(MapEntry&& other)
noexcept
;
330
MapEntry& operator=(MapEntry&& other)
noexcept
;
331
332
std::pair<
const
std::string, std::string>& Get();
333
const
std::pair<
const
std::string, std::string>& Get()
const
;
334
335
std::pair<std::string, std::string>& GetMutable();
336
337
bool
operator==(
const
MapEntry& other)
const
;
338
339
private
:
340
// The interface requires std::pair<CONST std::string, std::string>, but we
341
// don't want to copy where move would do, so this.
342
// Only 'mutable_value' is ever the active member of 'Slot', but we still
343
// can access it through `value` due to
344
// https://eel.is/c++draft/class.union.general#note-1
345
// The idea was taken from abseil:
346
// https://github.com/abseil/abseil-cpp/blob/1ae9b71c474628d60eb251a3f62967fe64151bb2/absl/container/internal/container_memory.h#L302
347
union
Slot {
348
Slot();
349
~Slot();
350
351
std::pair<std::string, std::string> mutable_value;
352
std::pair<
const
std::string, std::string> value;
353
};
354
355
Slot slot_{};
356
};
357
358
}
// namespace header_map
359
360
class
HeaderMap::Iterator
final
{
361
public
:
362
using
iterator_category = std::forward_iterator_tag;
363
using
difference_type = std::ptrdiff_t;
364
using
value_type = std::pair<
const
std::string, std::string>;
365
using
reference = value_type&;
366
using
const_reference =
const
value_type&;
367
using
pointer = value_type*;
368
using
const_pointer =
const
value_type*;
369
370
// The underlying iterator is a reversed one to do not invalidate
371
// end() on erase - end() is actually an rbegin() of underlying storage and is
372
// only invalidated on reallocation.
373
using
UnderlyingIterator = std::vector<
header_map
::MapEntry>::reverse_iterator;
374
375
Iterator();
376
explicit
Iterator(UnderlyingIterator it);
377
~Iterator();
378
379
Iterator(
const
Iterator& other);
380
Iterator(Iterator&& other)
noexcept
;
381
Iterator& operator=(
const
Iterator& other);
382
Iterator& operator=(Iterator&& other)
noexcept
;
383
384
Iterator operator++(
int
);
385
Iterator& operator++();
386
387
reference operator*()
const
;
388
pointer operator->()
const
;
389
390
bool
operator==(
const
Iterator& other)
const
;
391
bool
operator!=(
const
Iterator& other)
const
;
392
393
bool
operator==(
const
ConstIterator& other)
const
;
394
395
private
:
396
friend
class
HeaderMap::ConstIterator;
397
398
UnderlyingIterator it_{};
399
};
400
401
class
HeaderMap::ConstIterator
final
{
402
public
:
403
using
iterator_category = std::forward_iterator_tag;
404
using
difference_type = std::ptrdiff_t;
405
using
value_type = std::pair<
const
std::string, std::string>;
406
using
reference =
const
value_type&;
407
using
const_reference =
const
value_type&;
408
using
pointer =
const
value_type*;
409
using
const_pointer =
const
value_type*;
410
411
// The underlying iterator is a reversed one to do not invalidate
412
// end() on erase - end() is actually an rbegin() of underlying storage and is
413
// only invalidated on reallocation.
414
using
UnderlyingIterator = std::vector<
header_map
::MapEntry>::const_reverse_iterator;
415
416
ConstIterator();
417
explicit
ConstIterator(UnderlyingIterator it);
418
~ConstIterator();
419
420
ConstIterator(
const
ConstIterator& other);
421
ConstIterator(ConstIterator&& other)
noexcept
;
422
ConstIterator& operator=(
const
ConstIterator& other);
423
ConstIterator& operator=(ConstIterator&& other)
noexcept
;
424
425
ConstIterator operator++(
int
);
426
ConstIterator& operator++();
427
428
const_reference operator*()
const
;
429
const_pointer operator->()
const
;
430
431
bool
operator==(
const
ConstIterator& other)
const
;
432
bool
operator!=(
const
ConstIterator& other)
const
;
433
434
bool
operator==(
const
Iterator& other)
const
;
435
436
private
:
437
friend
class
HeaderMap::Iterator;
438
439
UnderlyingIterator it_{};
440
};
441
442
template
<std::size_t Size>
443
HeaderMap::Iterator HeaderMap::find(
const
char
(&)[Size])
noexcept
{
444
ReportMisuse<Size>();
445
}
446
447
template
<std::size_t Size>
448
HeaderMap::ConstIterator HeaderMap::find(
const
char
(&)[Size])
const
noexcept
{
449
ReportMisuse<Size>();
450
}
451
452
template
<std::size_t Size>
453
HeaderMap::Iterator HeaderMap::erase(
const
char
(&)[Size]) {
454
ReportMisuse<Size>();
455
}
456
457
}
// namespace http::headers
458
459
USERVER_NAMESPACE_END
userver
http
header_map.hpp
Generated on
for userver by
Doxygen
1.17.0