GCC Code Coverage Report


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