GCC Code Coverage Report


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