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 : /** 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 711 : 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 711 : alignof(T));
87 : }
88 :
89 : /** Returns the total number of bytes allocated by the container
90 : */
91 : std::size_t
92 61 : capacity_in_bytes() const noexcept
93 : {
94 61 : 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 21 : append(
155 : field id,
156 : core::string_view value)
157 : {
158 21 : BOOST_ASSERT(
159 : id != field::unknown);
160 : return insert_impl(
161 21 : 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 55 : 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 55 : 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 7 : BOOST_ASSERT(
253 : id != field::unknown);
254 :
255 : auto rv = insert_impl(
256 7 : id, to_string(id), value, before.i_);
257 :
258 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 15 : before.i_);
311 :
312 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
|