// // Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BEAST_HTTP_FIELDS_HPP #define BEAST_HTTP_FIELDS_HPP #include #include #include #include #include #include #include #include #include #include #include namespace beast { namespace http { /** A container for storing HTTP header fields. This container is designed to store the field value pairs that make up the fields and trailers in an HTTP message. Objects of this type are iterable, with each element holding the field name and field value. Field names are stored as-is, but comparisons are case-insensitive. When the container is iterated, the fields are presented in the order of insertion. For fields with the same name, the container behaves as a `std::multiset`; there will be a separate value for each occurrence of the field name. @note Meets the requirements of @b FieldSequence. */ template class basic_fields : #if ! BEAST_DOXYGEN private beast::detail::empty_base_optimization< typename std::allocator_traits:: template rebind_alloc< detail::basic_fields_base::element>>, #endif public detail::basic_fields_base { using alloc_type = typename std::allocator_traits:: template rebind_alloc< detail::basic_fields_base::element>; using alloc_traits = std::allocator_traits; using size_type = typename std::allocator_traits::size_type; void delete_all(); void move_assign(basic_fields&, std::false_type); void move_assign(basic_fields&, std::true_type); void copy_assign(basic_fields const&, std::false_type); void copy_assign(basic_fields const&, std::true_type); template void copy_from(FieldSequence const& fs) { for(auto const& e : fs) insert(e.first, e.second); } public: /// The type of allocator used. using allocator_type = Allocator; /** The value type of the field sequence. Meets the requirements of @b Field. */ #if BEAST_DOXYGEN using value_type = implementation_defined; #endif /// A const iterator to the field sequence #if BEAST_DOXYGEN using iterator = implementation_defined; #endif /// A const iterator to the field sequence #if BEAST_DOXYGEN using const_iterator = implementation_defined; #endif /// Default constructor. basic_fields() = default; /// Destructor ~basic_fields(); /** Construct the fields. @param alloc The allocator to use. */ explicit basic_fields(Allocator const& alloc); /** Move constructor. The moved-from object becomes an empty field sequence. @param other The object to move from. */ basic_fields(basic_fields&& other); /** Move assignment. The moved-from object becomes an empty field sequence. @param other The object to move from. */ basic_fields& operator=(basic_fields&& other); /// Copy constructor. basic_fields(basic_fields const&); /// Copy assignment. basic_fields& operator=(basic_fields const&); /// Copy constructor. template basic_fields(basic_fields const&); /// Copy assignment. template basic_fields& operator=(basic_fields const&); /// Returns a const iterator to the beginning of the field sequence. const_iterator begin() const { return list_.cbegin(); } /// Returns a const iterator to the end of the field sequence. const_iterator end() const { return list_.cend(); } /// Returns a const iterator to the beginning of the field sequence. const_iterator cbegin() const { return list_.cbegin(); } /// Returns a const iterator to the end of the field sequence. const_iterator cend() const { return list_.cend(); } /// Returns `true` if the specified field exists. bool exists(string_view name) const { return set_.find(name, less{}) != set_.end(); } /// Returns the number of values for the specified field. std::size_t count(string_view name) const; /** Returns an iterator to the case-insensitive matching field name. If more than one field with the specified name exists, the first field defined by insertion order is returned. */ iterator find(string_view name) const; /** Returns the value for a case-insensitive matching header, or `""`. If more than one field with the specified name exists, the first field defined by insertion order is returned. */ string_view const operator[](string_view name) const; /// Clear the contents of the basic_fields. void clear() noexcept; /** Remove a field. If more than one field with the specified name exists, all matching fields will be removed. @param name The name of the field(s) to remove. @return The number of fields removed. */ std::size_t erase(string_view name); /** Insert a field value. If a field with the same name already exists, the existing field is untouched and a new field value pair is inserted into the container. @param name The name of the field. @param value A string holding the value of the field. */ void insert(string_view name, string_view value); /** Insert a field value. If a field with the same name already exists, the existing field is untouched and a new field value pair is inserted into the container. @param name The name of the field @param value The value of the field. The object will be converted to a string using `boost::lexical_cast`. */ template typename std::enable_if< ! std::is_constructible::value>::type insert(string_view name, T const& value) { insert(name, boost::lexical_cast(value)); } /** Replace a field value. First removes any values with matching field names, then inserts the new field value. @param name The name of the field. @param value A string holding the value of the field. */ void replace(string_view name, string_view value); /** Replace a field value. First removes any values with matching field names, then inserts the new field value. @param name The name of the field @param value The value of the field. The object will be converted to a string using `boost::lexical_cast`. */ template typename std::enable_if< ! std::is_constructible::value>::type replace(string_view name, T const& value) { replace(name, boost::lexical_cast(value)); } #if BEAST_DOXYGEN private: #endif string_view method_impl() const { return (*this)[":method"]; } void method_impl(string_view s) { if(s.empty()) this->erase(":method"); else this->replace(":method", s); } string_view target_impl() const { return (*this)[":target"]; } void target_impl(string_view s) { if(s.empty()) this->erase(":target"); else return this->replace(":target", s); } string_view reason_impl() const { return (*this)[":reason"]; } void reason_impl(string_view s) { if(s.empty()) this->erase(":reason"); else this->replace(":reason", s); } }; /// A typical HTTP header fields container using fields = basic_fields>; } // http } // beast #include #endif