Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2021 Vinnie Falco (vinnie dot falco at gmail dot com) | ||
3 | // | ||
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
6 | // | ||
7 | // Official repository: https://github.com/CPPAlliance/http_proto | ||
8 | // | ||
9 | |||
10 | #ifndef BOOST_HTTP_PROTO_FIELDS_BASE_HPP | ||
11 | #define BOOST_HTTP_PROTO_FIELDS_BASE_HPP | ||
12 | |||
13 | #include <boost/http_proto/detail/config.hpp> | ||
14 | #include <boost/http_proto/fields_view_base.hpp> | ||
15 | |||
16 | namespace boost { | ||
17 | namespace http_proto { | ||
18 | |||
19 | /** Mixin for modifiable HTTP fields | ||
20 | |||
21 | @par Iterators | ||
22 | |||
23 | Iterators obtained from @ref fields | ||
24 | containers are not invalidated when | ||
25 | the underlying container is modified. | ||
26 | |||
27 | @note HTTP field names are case-insensitive. | ||
28 | */ | ||
29 | class BOOST_SYMBOL_VISIBLE | ||
30 | fields_base | ||
31 | : public virtual fields_view_base | ||
32 | { | ||
33 | detail::header h_; | ||
34 | |||
35 | class op_t; | ||
36 | using entry = | ||
37 | detail::header::entry; | ||
38 | using table = | ||
39 | detail::header::table; | ||
40 | |||
41 | friend class fields; | ||
42 | friend class request; | ||
43 | friend class response; | ||
44 | friend class serializer; | ||
45 | friend class message_base; | ||
46 | friend struct detail::header; | ||
47 | |||
48 | BOOST_HTTP_PROTO_DECL | ||
49 | explicit | ||
50 | fields_base( | ||
51 | detail::kind) noexcept; | ||
52 | |||
53 | BOOST_HTTP_PROTO_DECL | ||
54 | fields_base( | ||
55 | detail::kind, | ||
56 | string_view); | ||
57 | |||
58 | fields_base(detail::header const&); | ||
59 | |||
60 | public: | ||
61 | /** Destructor | ||
62 | */ | ||
63 | BOOST_HTTP_PROTO_DECL | ||
64 | ~fields_base(); | ||
65 | |||
66 | //-------------------------------------------- | ||
67 | // | ||
68 | // Capacity | ||
69 | // | ||
70 | //-------------------------------------------- | ||
71 | |||
72 | /** Returns the largest permissible capacity in bytes | ||
73 | */ | ||
74 | static | ||
75 | constexpr | ||
76 | std::size_t | ||
77 | 587 | max_capacity_in_bytes() noexcept | |
78 | { | ||
79 | using T = detail::header::entry; | ||
80 | return alignof(T) * | ||
81 | (((max_off_t - 2 + sizeof(T) * ( | ||
82 | max_off_t / 4)) + | ||
83 | alignof(T) - 1) / | ||
84 | 587 | alignof(T)); | |
85 | } | ||
86 | |||
87 | /** Returns the total number of bytes allocated by the container | ||
88 | */ | ||
89 | std::size_t | ||
90 | 38 | capacity_in_bytes() const noexcept | |
91 | { | ||
92 | 38 | return h_.cap; | |
93 | } | ||
94 | |||
95 | /** Clear the contents, but not the capacity | ||
96 | */ | ||
97 | BOOST_HTTP_PROTO_DECL | ||
98 | void | ||
99 | clear() noexcept; | ||
100 | |||
101 | /** Reserve a minimum capacity | ||
102 | */ | ||
103 | BOOST_HTTP_PROTO_DECL | ||
104 | void | ||
105 | reserve_bytes(std::size_t n); | ||
106 | |||
107 | /** Remove excess capacity | ||
108 | */ | ||
109 | BOOST_HTTP_PROTO_DECL | ||
110 | void | ||
111 | shrink_to_fit() noexcept; | ||
112 | |||
113 | //-------------------------------------------- | ||
114 | // | ||
115 | // Modifiers | ||
116 | // | ||
117 | //-------------------------------------------- | ||
118 | |||
119 | /** Append a header | ||
120 | |||
121 | This function appends a new header. | ||
122 | Existing headers with the same name are | ||
123 | not changed. Names are not case-sensitive. | ||
124 | <br> | ||
125 | No iterators are invalidated. | ||
126 | |||
127 | @par Example | ||
128 | @code | ||
129 | request req; | ||
130 | |||
131 | req.append( field::user_agent, "Boost" ); | ||
132 | @endcode | ||
133 | |||
134 | @par Complexity | ||
135 | Linear in `to_string( id ).size() + value.size()`. | ||
136 | |||
137 | @par Exception Safety | ||
138 | Strong guarantee. | ||
139 | Calls to allocate may throw. | ||
140 | |||
141 | @param id The field name constant, | ||
142 | which may not be @ref field::unknown. | ||
143 | |||
144 | @param value A value, which | ||
145 | @li Must be syntactically valid for the header, | ||
146 | @li Must be semantically valid for the message, and | ||
147 | @li May not contain leading or trailing whitespace. | ||
148 | */ | ||
149 | void | ||
150 | 20 | append( | |
151 | field id, | ||
152 | string_view value) | ||
153 | { | ||
154 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | BOOST_ASSERT( |
155 | id != field::unknown); | ||
156 | 20 | insert_impl( | |
157 | id, | ||
158 | to_string(id), | ||
159 | value, | ||
160 | 20 | h_.count); | |
161 | 20 | } | |
162 | |||
163 | /** Append a header | ||
164 | |||
165 | This function appends a new header. | ||
166 | Existing headers with the same name are | ||
167 | not changed. Names are not case-sensitive. | ||
168 | <br> | ||
169 | No iterators are invalidated. | ||
170 | |||
171 | @par Example | ||
172 | @code | ||
173 | request req; | ||
174 | |||
175 | req.append( "User-Agent", "Boost" ); | ||
176 | @endcode | ||
177 | |||
178 | @par Complexity | ||
179 | Linear in `name.size() + value.size()`. | ||
180 | |||
181 | @par Exception Safety | ||
182 | Strong guarantee. | ||
183 | Calls to allocate may throw. | ||
184 | |||
185 | @param name The header name. | ||
186 | |||
187 | @param value A value, which | ||
188 | @li Must be syntactically valid for the header, | ||
189 | @li Must be semantically valid for the message, and | ||
190 | @li May not contain leading or trailing whitespace. | ||
191 | */ | ||
192 | void | ||
193 | 10 | append( | |
194 | string_view name, | ||
195 | string_view value) | ||
196 | { | ||
197 | 10 | insert_impl( | |
198 | string_to_field( | ||
199 | name), | ||
200 | name, | ||
201 | value, | ||
202 | 10 | h_.count); | |
203 | 9 | } | |
204 | |||
205 | /** Insert a header | ||
206 | |||
207 | If a matching header with the same name | ||
208 | exists, it is not replaced. Instead, an | ||
209 | additional header with the same name is | ||
210 | inserted. Names are not case-sensitive. | ||
211 | <br> | ||
212 | All iterators that are equal to `before` | ||
213 | or come after are invalidated. | ||
214 | |||
215 | @par Example | ||
216 | @code | ||
217 | request req; | ||
218 | |||
219 | req.insert( req.begin(), field::user_agent, "Boost" ); | ||
220 | @endcode | ||
221 | |||
222 | @par Complexity | ||
223 | Linear in `to_string( id ).size() + value.size()`. | ||
224 | |||
225 | @par Exception Safety | ||
226 | Strong guarantee. | ||
227 | Calls to allocate may throw. | ||
228 | |||
229 | @return An iterator to the inserted | ||
230 | element. | ||
231 | |||
232 | @param before Position to insert before. | ||
233 | |||
234 | @param id The field name constant, | ||
235 | which may not be @ref field::unknown. | ||
236 | |||
237 | @param value A value, which | ||
238 | @li Must be syntactically valid for the header, | ||
239 | @li Must be semantically valid for the message, and | ||
240 | @li May not contain leading or trailing whitespace. | ||
241 | */ | ||
242 | iterator | ||
243 | 6 | insert( | |
244 | iterator before, | ||
245 | field id, | ||
246 | string_view value) | ||
247 | { | ||
248 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | BOOST_ASSERT( |
249 | id != field::unknown); | ||
250 | 6 | insert_impl( | |
251 | id, | ||
252 | to_string(id), | ||
253 | value, | ||
254 | before.i_); | ||
255 | 6 | return before; | |
256 | } | ||
257 | |||
258 | /** Insert a header | ||
259 | |||
260 | If a matching header with the same name | ||
261 | exists, it is not replaced. Instead, an | ||
262 | additional header with the same name is | ||
263 | inserted. Names are not case-sensitive. | ||
264 | <br> | ||
265 | All iterators that are equal to `before` | ||
266 | or come after are invalidated. | ||
267 | |||
268 | @par Example | ||
269 | @code | ||
270 | request req; | ||
271 | |||
272 | req.insert( req.begin(), "User-Agent", "Boost" ); | ||
273 | @endcode | ||
274 | |||
275 | @par Complexity | ||
276 | Linear in `name.size() + value.size()`. | ||
277 | |||
278 | @par Exception Safety | ||
279 | Strong guarantee. | ||
280 | Calls to allocate may throw. | ||
281 | |||
282 | @return An iterator to the inserted | ||
283 | element. | ||
284 | |||
285 | @param before Position to insert before. | ||
286 | |||
287 | @param name The header name. | ||
288 | |||
289 | @param value A value, which | ||
290 | @li Must be syntactically valid for the header, | ||
291 | @li Must be semantically valid for the message, and | ||
292 | @li May not contain leading or trailing whitespace. | ||
293 | */ | ||
294 | iterator | ||
295 | 12 | insert( | |
296 | iterator before, | ||
297 | string_view name, | ||
298 | string_view value) | ||
299 | { | ||
300 | 12 | insert_impl( | |
301 | string_to_field( | ||
302 | name), | ||
303 | name, | ||
304 | value, | ||
305 | before.i_); | ||
306 | 12 | return before; | |
307 | } | ||
308 | |||
309 | //-------------------------------------------- | ||
310 | |||
311 | /** Erase headers | ||
312 | |||
313 | This function removes the header pointed | ||
314 | to by `it`. | ||
315 | <br> | ||
316 | All iterators that are equal to `it` | ||
317 | or come after are invalidated. | ||
318 | |||
319 | @par Complexity | ||
320 | Linear in `name.size() + value.size()`. | ||
321 | |||
322 | @par Exception Safety | ||
323 | Throws nothing. | ||
324 | |||
325 | @return An iterator to the inserted | ||
326 | element. | ||
327 | |||
328 | @param it An iterator to the element | ||
329 | to erase. | ||
330 | */ | ||
331 | iterator | ||
332 | 31 | erase(iterator it) noexcept | |
333 | { | ||
334 | 31 | erase_impl(it.i_, it->id); | |
335 | 31 | return it; | |
336 | } | ||
337 | |||
338 | /** Erase headers | ||
339 | |||
340 | This removes all headers whose name | ||
341 | constant is equal to `id`. | ||
342 | <br> | ||
343 | If any headers are erased, then all | ||
344 | iterators equal to or that come after | ||
345 | the first erased element are invalidated. | ||
346 | Otherwise, no iterators are invalidated. | ||
347 | |||
348 | @par Complexity | ||
349 | Linear in `this->string().size()`. | ||
350 | |||
351 | @par Exception Safety | ||
352 | Throws nothing. | ||
353 | |||
354 | @return The number of headers erased. | ||
355 | |||
356 | @param id The field name constant, | ||
357 | which may not be @ref field::unknown. | ||
358 | */ | ||
359 | BOOST_HTTP_PROTO_DECL | ||
360 | std::size_t | ||
361 | erase(field id) noexcept; | ||
362 | |||
363 | /** Erase all matching fields | ||
364 | |||
365 | This removes all headers with a matching | ||
366 | name, using a case-insensitive comparison. | ||
367 | <br> | ||
368 | If any headers are erased, then all | ||
369 | iterators equal to or that come after | ||
370 | the first erased element are invalidated. | ||
371 | Otherwise, no iterators are invalidated. | ||
372 | |||
373 | @par Complexity | ||
374 | Linear in `this->string().size()`. | ||
375 | |||
376 | @par Exception Safety | ||
377 | Throws nothing. | ||
378 | |||
379 | @return The number of fields erased | ||
380 | |||
381 | @param name The header name. | ||
382 | */ | ||
383 | BOOST_HTTP_PROTO_DECL | ||
384 | std::size_t | ||
385 | erase(string_view name) noexcept; | ||
386 | |||
387 | //-------------------------------------------- | ||
388 | |||
389 | /** Set a header value | ||
390 | |||
391 | This sets the value of the header | ||
392 | at `it`. The name is not changed. | ||
393 | <br> | ||
394 | No iterators are invalidated. | ||
395 | |||
396 | @par Complexity | ||
397 | |||
398 | @par Exception Safety | ||
399 | Strong guarantee. | ||
400 | Calls to allocate may throw. | ||
401 | |||
402 | @param it An iterator to the header. | ||
403 | |||
404 | @param value A value, which | ||
405 | @li Must be syntactically valid for the header, | ||
406 | @li Must be semantically valid for the message, and | ||
407 | @li May not contain leading or trailing whitespace. | ||
408 | */ | ||
409 | BOOST_HTTP_PROTO_DECL | ||
410 | void | ||
411 | set( | ||
412 | iterator it, | ||
413 | string_view value); | ||
414 | |||
415 | /** Set a header value | ||
416 | |||
417 | This function sets the value of the | ||
418 | header with the specified field id. | ||
419 | Other headers with the same name | ||
420 | are removed first. | ||
421 | |||
422 | @par Postconditions | ||
423 | @code | ||
424 | this->count( id ) == 1 && this->at( id ) == value | ||
425 | @endcode | ||
426 | |||
427 | @par Complexity | ||
428 | |||
429 | @param id The field constant of the | ||
430 | header to set. | ||
431 | |||
432 | @param value A value, which | ||
433 | @li Must be syntactically valid for the header, | ||
434 | @li Must be semantically valid for the message, and | ||
435 | @li May not contain leading or trailing whitespace. | ||
436 | */ | ||
437 | BOOST_HTTP_PROTO_DECL | ||
438 | void | ||
439 | set( | ||
440 | field id, | ||
441 | string_view value); | ||
442 | |||
443 | /** Set a header value | ||
444 | |||
445 | This function sets the value of the | ||
446 | header with the specified name. Other | ||
447 | headers with the same name are removed | ||
448 | first. | ||
449 | |||
450 | @par Postconditions | ||
451 | @code | ||
452 | this->count( name ) == 1 && this->at( name ) == value | ||
453 | @endcode | ||
454 | |||
455 | @param name The field name. | ||
456 | |||
457 | @param value The corresponding value, which | ||
458 | @li must be syntactically valid for the field, | ||
459 | @li must be semantically valid for the message, and | ||
460 | @li may not contain leading or trailing whitespace. | ||
461 | */ | ||
462 | BOOST_HTTP_PROTO_DECL | ||
463 | void | ||
464 | set( | ||
465 | string_view name, | ||
466 | string_view value); | ||
467 | |||
468 | //-------------------------------------------- | ||
469 | |||
470 | private: | ||
471 | BOOST_HTTP_PROTO_DECL | ||
472 | void | ||
473 | copy_impl( | ||
474 | detail::header const&); | ||
475 | |||
476 | BOOST_HTTP_PROTO_DECL | ||
477 | void | ||
478 | insert_impl( | ||
479 | field id, | ||
480 | string_view name, | ||
481 | string_view value, | ||
482 | std::size_t before); | ||
483 | |||
484 | BOOST_HTTP_PROTO_DECL | ||
485 | void | ||
486 | erase_impl( | ||
487 | std::size_t i, | ||
488 | field id) noexcept; | ||
489 | |||
490 | void raw_erase( | ||
491 | std::size_t) noexcept; | ||
492 | |||
493 | std::size_t | ||
494 | erase_all_impl( | ||
495 | std::size_t i0, | ||
496 | field id) noexcept; | ||
497 | |||
498 | std::size_t | ||
499 | offset( | ||
500 | std::size_t i) const noexcept; | ||
501 | |||
502 | std::size_t | ||
503 | length( | ||
504 | std::size_t i) const noexcept; | ||
505 | |||
506 | void raw_erase_n(field, std::size_t) noexcept; | ||
507 | }; | ||
508 | |||
509 | //------------------------------------------------ | ||
510 | |||
511 | #ifndef BOOST_HTTP_PROTO_DOCS | ||
512 | namespace detail { | ||
513 | inline | ||
514 | header& | ||
515 | header:: | ||
516 | get(fields_base& f) noexcept | ||
517 | { | ||
518 | return f.h_; | ||
519 | } | ||
520 | } // detail | ||
521 | #endif | ||
522 | |||
523 | } // http_proto | ||
524 | } // boost | ||
525 | |||
526 | #endif | ||
527 |