Line data Source code
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 930 : max_capacity_in_bytes() noexcept
94 : {
95 930 : 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 96 : append(
164 : field id,
165 : core::string_view value)
166 : {
167 96 : BOOST_ASSERT(
168 : id != field::unknown);
169 : return insert_impl(
170 96 : 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 : return insert_impl(
210 : string_to_field(
211 : name),
212 : name,
213 : value,
214 55 : 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 43 : BOOST_ASSERT(
262 : id != field::unknown);
263 :
264 : auto rv = insert_impl(
265 43 : id, to_string(id), value, before.i_);
266 :
267 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 : auto rv = insert_impl(
315 : string_to_field(
316 : name),
317 : name,
318 : value,
319 15 : before.i_);
320 :
321 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
|