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