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