GCC Code Coverage Report


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