GCC Code Coverage Report


Directory: libs/http_proto/
File: boost/http_proto/fields_base.hpp
Date: 2024-03-19 15:22:01
Exec Total Coverage
Lines: 23 23 100.0%
Functions: 7 7 100.0%
Branches: 9 14 64.3%

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