Line data Source code
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 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 7 : BOOST_ASSERT(
258 : id != field::unknown);
259 :
260 : auto rv = insert_impl(
261 7 : id, to_string(id), value, before.i_);
262 :
263 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 15 : before.i_);
316 :
317 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
|