2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_HTTP_FIELDS_HPP
11 #define BOOST_BEAST_HTTP_FIELDS_HPP
13 #include <boost/beast/core/detail/config.hpp>
14 #include <boost/beast/core/string_param.hpp>
15 #include <boost/beast/core/string.hpp>
16 #include <boost/beast/core/detail/allocator.hpp>
17 #include <boost/beast/http/field.hpp>
18 #include <boost/asio/buffer.hpp>
19 #include <boost/intrusive/list.hpp>
20 #include <boost/intrusive/set.hpp>
21 #include <boost/optional.hpp>
27 #include <type_traits>
34 /** A container for storing HTTP header fields.
36 This container is designed to store the field value pairs that make
37 up the fields and trailers in an HTTP message. Objects of this type
38 are iterable, with each element holding the field name and field
41 Field names are stored as-is, but comparisons are case-insensitive.
42 The container behaves as a `std::multiset`; there will be a separate
43 value for each occurrence of the same field name. When the container
44 is iterated the fields are presented in the order of insertion, with
45 fields having the same name following each other consecutively.
47 Meets the requirements of @b Fields
49 @tparam Allocator The allocator to use. This must meet the
50 requirements of @b Allocator.
52 template<class Allocator>
55 friend class fields_test; // for `header`
57 static std::size_t constexpr max_static_buffer = 4096;
59 using off_t = std::uint16_t;
62 /// The type of allocator used.
63 using allocator_type = Allocator;
65 /// The type of element used to represent a field
68 friend class basic_fields;
70 boost::asio::const_buffer
73 value_type(field name,
74 string_view sname, string_view value);
76 boost::intrusive::list_member_hook<
77 boost::intrusive::link_mode<
78 boost::intrusive::normal_link>>
80 boost::intrusive::set_member_hook<
81 boost::intrusive::link_mode<
82 boost::intrusive::normal_link>>
89 /// Constructor (deleted)
90 value_type(value_type const&) = delete;
92 /// Assignment (deleted)
93 value_type& operator=(value_type const&) = delete;
95 /// Returns the field enum, which can be @ref field::unknown
99 /// Returns the field name as a string
103 /// Returns the value of the field
108 /** A strictly less predicate for comparing keys, using a case-insensitive comparison.
110 The case-comparison operation is defined only for low-ASCII characters.
112 struct key_compare : beast::iless
114 /// Returns `true` if lhs is less than rhs using a strict ordering
115 template<class String>
119 value_type const& rhs) const noexcept
121 if(lhs.size() < rhs.name_string().size())
123 if(lhs.size() > rhs.name_string().size())
125 return iless::operator()(lhs, rhs.name_string());
128 /// Returns `true` if lhs is less than rhs using a strict ordering
129 template<class String>
132 value_type const& lhs,
133 String const& rhs) const noexcept
135 if(lhs.name_string().size() < rhs.size())
137 if(lhs.name_string().size() > rhs.size())
139 return iless::operator()(lhs.name_string(), rhs);
142 /// Returns `true` if lhs is less than rhs using a strict ordering
145 value_type const& lhs,
146 value_type const& rhs) const noexcept
148 if(lhs.name_string().size() < rhs.name_string().size())
150 if(lhs.name_string().size() > rhs.name_string().size())
152 return iless::operator()(lhs.name_string(), rhs.name_string());
156 /// The algorithm used to serialize the header
157 #if BOOST_BEAST_DOXYGEN
158 using writer = implementation_defined;
164 using list_t = typename boost::intrusive::make_list<
165 value_type, boost::intrusive::member_hook<
166 value_type, boost::intrusive::list_member_hook<
167 boost::intrusive::link_mode<
168 boost::intrusive::normal_link>>,
169 &value_type::list_hook_>,
170 boost::intrusive::constant_time_size<
173 using set_t = typename boost::intrusive::make_multiset<
174 value_type, boost::intrusive::member_hook<value_type,
175 boost::intrusive::set_member_hook<
176 boost::intrusive::link_mode<
177 boost::intrusive::normal_link>>,
178 &value_type::set_hook_>,
179 boost::intrusive::constant_time_size<true>,
180 boost::intrusive::compare<key_compare>>::type;
188 basic_fields() = default;
192 @param alloc The allocator to use.
195 basic_fields(Allocator const& alloc);
197 /** Move constructor.
199 The state of the moved-from object is
200 as if constructed using the same allocator.
202 basic_fields(basic_fields&&);
204 /** Move constructor.
206 The state of the moved-from object is
207 as if constructed using the same allocator.
209 @param alloc The allocator to use.
211 basic_fields(basic_fields&&, Allocator const& alloc);
213 /// Copy constructor.
214 basic_fields(basic_fields const&);
216 /** Copy constructor.
218 @param alloc The allocator to use.
220 basic_fields(basic_fields const&, Allocator const& alloc);
222 /// Copy constructor.
223 template<class OtherAlloc>
224 basic_fields(basic_fields<OtherAlloc> const&);
226 /** Copy constructor.
228 @param alloc The allocator to use.
230 template<class OtherAlloc>
231 basic_fields(basic_fields<OtherAlloc> const&,
232 Allocator const& alloc);
236 The state of the moved-from object is
237 as if constructed using the same allocator.
239 basic_fields& operator=(basic_fields&&);
242 basic_fields& operator=(basic_fields const&);
245 template<class OtherAlloc>
246 basic_fields& operator=(basic_fields<OtherAlloc> const&);
249 /// A constant iterator to the field sequence.
250 #if BOOST_BEAST_DOXYGEN
251 using const_iterator = implementation_defined;
253 using const_iterator = typename list_t::const_iterator;
256 /// A constant iterator to the field sequence.
257 using iterator = const_iterator;
259 /// Return a copy of the allocator associated with the container.
261 get_allocator() const
266 //--------------------------------------------------------------------------
270 //--------------------------------------------------------------------------
272 /** Returns the value for a field, or throws an exception.
274 If more than one field with the specified name exists, the
275 first field defined by insertion order is returned.
277 @param name The name of the field.
279 @return The field value.
281 @throws std::out_of_range if the field is not found.
284 at(field name) const;
286 /** Returns the value for a field, or throws an exception.
288 If more than one field with the specified name exists, the
289 first field defined by insertion order is returned.
291 @param name The name of the field.
293 @return The field value.
295 @throws std::out_of_range if the field is not found.
298 at(string_view name) const;
300 /** Returns the value for a field, or `""` if it does not exist.
302 If more than one field with the specified name exists, the
303 first field defined by insertion order is returned.
305 @param name The name of the field.
308 operator[](field name) const;
310 /** Returns the value for a case-insensitive matching header, or `""` if it does not exist.
312 If more than one field with the specified name exists, the
313 first field defined by insertion order is returned.
315 @param name The name of the field.
318 operator[](string_view name) const;
320 //--------------------------------------------------------------------------
324 //--------------------------------------------------------------------------
326 /// Return a const iterator to the beginning of the field sequence.
330 return list_.cbegin();
333 /// Return a const iterator to the end of the field sequence.
340 /// Return a const iterator to the beginning of the field sequence.
344 return list_.cbegin();
347 /// Return a const iterator to the end of the field sequence.
354 //--------------------------------------------------------------------------
358 //--------------------------------------------------------------------------
361 // VFALCO Since the header and message derive from Fields,
362 // what does the expression m.empty() mean? Its confusing.
366 return list_.empty();
370 //--------------------------------------------------------------------------
374 //--------------------------------------------------------------------------
376 /** Remove all fields from the container
378 All references, pointers, or iterators referring to contained
379 elements are invalidated. All past-the-end iterators are also
384 std::distance(this->begin(), this->end()) == 0
392 If one or more fields with the same name already exist,
393 the new field will be inserted after the last field with
394 the matching name, in serialization order.
396 @param name The field name.
398 @param value The value of the field, as a @ref string_param
401 insert(field name, string_param const& value);
405 If one or more fields with the same name already exist,
406 the new field will be inserted after the last field with
407 the matching name, in serialization order.
409 @param name The field name.
411 @param value The value of the field, as a @ref string_param
414 insert(string_view name, string_param const& value);
418 If one or more fields with the same name already exist,
419 the new field will be inserted after the last field with
420 the matching name, in serialization order.
422 @param name The field name.
424 @param name_string The literal text corresponding to the
425 field name. If `name != field::unknown`, then this value
426 must be equal to `to_string(name)` using a case-insensitive
427 comparison, otherwise the behavior is undefined.
429 @param value The value of the field, as a @ref string_param
432 insert(field name, string_view name_string,
433 string_param const& value);
435 /** Set a field value, removing any other instances of that field.
437 First removes any values with matching field names, then
438 inserts the new field value.
440 @param name The field name.
442 @param value The value of the field, as a @ref string_param
444 @return The field value.
447 set(field name, string_param const& value);
449 /** Set a field value, removing any other instances of that field.
451 First removes any values with matching field names, then
452 inserts the new field value.
454 @param name The field name.
456 @param value The value of the field, as a @ref string_param
459 set(string_view name, string_param const& value);
463 References and iterators to the erased elements are
464 invalidated. Other references and iterators are not
467 @param pos An iterator to the element to remove.
469 @return An iterator following the last removed element.
470 If the iterator refers to the last element, the end()
471 iterator is returned.
474 erase(const_iterator pos);
476 /** Remove all fields with the specified name.
478 All fields with the same field name are erased from the
480 References and iterators to the erased elements are
481 invalidated. Other references and iterators are not
484 @param name The field name.
486 @return The number of fields removed.
491 /** Remove all fields with the specified name.
493 All fields with the same field name are erased from the
495 References and iterators to the erased elements are
496 invalidated. Other references and iterators are not
499 @param name The field name.
501 @return The number of fields removed.
504 erase(string_view name);
506 /** Return a buffer sequence representing the trailers.
508 This function returns a buffer sequence holding the
509 serialized representation of the trailer fields promised
510 in the Accept field. Before calling this function the
511 Accept field must contain the exact trailer fields
512 desired. Each field must also exist.
516 /// Swap this container with another
518 swap(basic_fields& other);
520 /// Swap two field containers
521 template<class Alloc>
524 swap(basic_fields<Alloc>& lhs, basic_fields<Alloc>& rhs);
526 //--------------------------------------------------------------------------
530 //--------------------------------------------------------------------------
532 /** Return the number of fields with the specified name.
534 @param name The field name.
537 count(field name) const;
539 /** Return the number of fields with the specified name.
541 @param name The field name.
544 count(string_view name) const;
546 /** Returns an iterator to the case-insensitive matching field.
548 If more than one field with the specified name exists, the
549 first field defined by insertion order is returned.
551 @param name The field name.
553 @return An iterator to the matching field, or `end()` if
557 find(field name) const;
559 /** Returns an iterator to the case-insensitive matching field name.
561 If more than one field with the specified name exists, the
562 first field defined by insertion order is returned.
564 @param name The field name.
566 @return An iterator to the matching field, or `end()` if
570 find(string_view name) const;
572 /** Returns a range of iterators to the fields with the specified name.
574 @param name The field name.
576 @return A range of iterators to fields with the same name,
577 otherwise an empty range.
579 std::pair<const_iterator, const_iterator>
580 equal_range(field name) const;
582 /** Returns a range of iterators to the fields with the specified name.
584 @param name The field name.
586 @return A range of iterators to fields with the same name,
587 otherwise an empty range.
589 std::pair<const_iterator, const_iterator>
590 equal_range(string_view name) const;
592 //--------------------------------------------------------------------------
596 //--------------------------------------------------------------------------
598 /// Returns a copy of the key comparison function
602 return key_compare{};
606 /** Returns the request-method string.
608 @note Only called for requests.
611 get_method_impl() const;
613 /** Returns the request-target string.
615 @note Only called for requests.
618 get_target_impl() const;
620 /** Returns the response reason-phrase string.
622 @note Only called for responses.
625 get_reason_impl() const;
627 /** Returns the chunked Transfer-Encoding setting
630 get_chunked_impl() const;
632 /** Returns the keep-alive setting
635 get_keep_alive_impl(unsigned version) const;
637 /** Returns `true` if the Content-Length field is present.
640 has_content_length_impl() const;
642 /** Set or clear the method string.
644 @note Only called for requests.
647 set_method_impl(string_view s);
649 /** Set or clear the target string.
651 @note Only called for requests.
654 set_target_impl(string_view s);
656 /** Set or clear the reason string.
658 @note Only called for responses.
661 set_reason_impl(string_view s);
663 /** Adjusts the chunked Transfer-Encoding value
666 set_chunked_impl(bool value);
668 /** Sets or clears the Content-Length field
671 set_content_length_impl(
672 boost::optional<std::uint64_t> const& value);
674 /** Adjusts the Connection field
678 unsigned version, bool keep_alive);
681 template<class OtherAlloc>
682 friend class basic_fields;
684 using base_alloc_type = typename
685 beast::detail::allocator_traits<Allocator>::
686 template rebind_alloc<value_type>;
689 beast::detail::allocator_traits<base_alloc_type>;
691 using size_type = typename
692 beast::detail::allocator_traits<Allocator>::size_type;
695 new_element(field name,
696 string_view sname, string_view value);
699 delete_element(value_type& e);
702 set_element(value_type& e);
705 realloc_string(string_view& dest, string_view s);
709 string_view& dest, string_view s);
711 template<class OtherAlloc>
713 copy_all(basic_fields<OtherAlloc> const&);
722 move_assign(basic_fields&, std::true_type);
725 move_assign(basic_fields&, std::false_type);
728 copy_assign(basic_fields const&, std::true_type);
731 copy_assign(basic_fields const&, std::false_type);
734 swap(basic_fields& other, std::true_type);
737 swap(basic_fields& other, std::false_type);
739 base_alloc_type alloc_;
743 string_view target_or_reason_;
746 /// A typical HTTP header fields container
747 using fields = basic_fields<std::allocator<char>>;
753 #include <boost/beast/http/impl/fields.ipp>