• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot 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/boostorg/beast
8 //
9 
10 #ifndef BOOST_BEAST_HTTP_FIELDS_HPP
11 #define BOOST_BEAST_HTTP_FIELDS_HPP
12 
13 #include <boost/beast/core/detail/config.hpp>
14 #include <boost/beast/core/string.hpp>
15 #include <boost/beast/core/detail/allocator.hpp>
16 #include <boost/beast/http/field.hpp>
17 #include <boost/asio/buffer.hpp>
18 #include <boost/core/empty_value.hpp>
19 #include <boost/intrusive/list.hpp>
20 #include <boost/intrusive/set.hpp>
21 #include <boost/optional.hpp>
22 #include <algorithm>
23 #include <cctype>
24 #include <cstring>
25 #include <memory>
26 #include <string>
27 #include <type_traits>
28 #include <utility>
29 
30 namespace boost {
31 namespace beast {
32 namespace http {
33 
34 /** A container for storing HTTP header fields.
35 
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
39     value.
40 
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.
46 
47     Meets the requirements of <em>Fields</em>
48 
49     @tparam Allocator The allocator to use.
50 */
51 template<class Allocator>
52 class basic_fields
53 #if ! BOOST_BEAST_DOXYGEN
54     : private boost::empty_value<Allocator>
55 #endif
56 {
57     // Fancy pointers are not supported
58     static_assert(std::is_pointer<typename
59         std::allocator_traits<Allocator>::pointer>::value,
60         "Allocator must use regular pointers");
61 
62     friend class fields_test; // for `header`
63 
64     struct element;
65 
66     using off_t = std::uint16_t;
67 
68 public:
69     /// The type of allocator used.
70     using allocator_type = Allocator;
71 
72     /// The type of element used to represent a field
73     class value_type
74     {
75         friend class basic_fields;
76 
77         off_t off_;
78         off_t len_;
79         field f_;
80 
81         char*
82         data() const;
83 
84         net::const_buffer
85         buffer() const;
86 
87     protected:
88         value_type(field name,
89             string_view sname, string_view value);
90 
91     public:
92         /// Constructor (deleted)
93         value_type(value_type const&) = delete;
94 
95         /// Assignment (deleted)
96         value_type& operator=(value_type const&) = delete;
97 
98         /// Returns the field enum, which can be @ref field::unknown
99         field
100         name() const;
101 
102         /// Returns the field name as a string
103         string_view const
104         name_string() const;
105 
106         /// Returns the value of the field
107         string_view const
108         value() const;
109     };
110 
111     /** A strictly less predicate for comparing keys, using a case-insensitive comparison.
112 
113         The case-comparison operation is defined only for low-ASCII characters.
114     */
115 #if BOOST_BEAST_DOXYGEN
116     using key_compare = __implementation_defined__;
117 #else
118     struct key_compare : beast::iless
119 #endif
120     {
121         /// Returns `true` if lhs is less than rhs using a strict ordering
122         bool
operator ()boost::beast::http::basic_fields::key_compare123         operator()(
124             string_view lhs,
125             value_type const& rhs) const noexcept
126         {
127             if(lhs.size() < rhs.name_string().size())
128                 return true;
129             if(lhs.size() > rhs.name_string().size())
130                 return false;
131             return iless::operator()(lhs, rhs.name_string());
132         }
133 
134         /// Returns `true` if lhs is less than rhs using a strict ordering
135         bool
operator ()boost::beast::http::basic_fields::key_compare136         operator()(
137             value_type const& lhs,
138             string_view rhs) const noexcept
139         {
140             if(lhs.name_string().size() < rhs.size())
141                 return true;
142             if(lhs.name_string().size() > rhs.size())
143                 return false;
144             return iless::operator()(lhs.name_string(), rhs);
145         }
146 
147         /// Returns `true` if lhs is less than rhs using a strict ordering
148         bool
operator ()boost::beast::http::basic_fields::key_compare149         operator()(
150             value_type const& lhs,
151             value_type const& rhs) const noexcept
152         {
153             if(lhs.name_string().size() < rhs.name_string().size())
154                 return true;
155             if(lhs.name_string().size() > rhs.name_string().size())
156                 return false;
157             return iless::operator()(lhs.name_string(), rhs.name_string());
158         }
159     };
160 
161     /// The algorithm used to serialize the header
162 #if BOOST_BEAST_DOXYGEN
163     using writer = __implementation_defined__;
164 #else
165     class writer;
166 #endif
167 
168 private:
169     struct element
170         : public boost::intrusive::list_base_hook<
171             boost::intrusive::link_mode<
172                 boost::intrusive::normal_link>>
173         , public boost::intrusive::set_base_hook<
174             boost::intrusive::link_mode<
175                 boost::intrusive::normal_link>>
176         , public value_type
177     {
178         element(field name,
179             string_view sname, string_view value);
180     };
181 
182     using list_t = typename boost::intrusive::make_list<
183         element,
184         boost::intrusive::constant_time_size<false>
185             >::type;
186 
187     using set_t = typename boost::intrusive::make_multiset<
188         element,
189         boost::intrusive::constant_time_size<true>,
190         boost::intrusive::compare<key_compare>
191             >::type;
192 
193     using align_type = typename
194         boost::type_with_alignment<alignof(element)>::type;
195 
196     using rebind_type = typename
197         beast::detail::allocator_traits<Allocator>::
198             template rebind_alloc<align_type>;
199 
200     using alloc_traits =
201         beast::detail::allocator_traits<rebind_type>;
202 
203     using size_type = typename
204         beast::detail::allocator_traits<Allocator>::size_type;
205 
206 
207 public:
208     /// Destructor
209     ~basic_fields();
210 
211     /// Constructor.
212     basic_fields() = default;
213 
214     /** Constructor.
215 
216         @param alloc The allocator to use.
217     */
218     explicit
219     basic_fields(Allocator const& alloc) noexcept;
220 
221     /** Move constructor.
222 
223         The state of the moved-from object is
224         as if constructed using the same allocator.
225     */
226     basic_fields(basic_fields&&) noexcept;
227 
228     /** Move constructor.
229 
230         The state of the moved-from object is
231         as if constructed using the same allocator.
232 
233         @param alloc The allocator to use.
234     */
235     basic_fields(basic_fields&&, Allocator const& alloc);
236 
237     /// Copy constructor.
238     basic_fields(basic_fields const&);
239 
240     /** Copy constructor.
241 
242         @param alloc The allocator to use.
243     */
244     basic_fields(basic_fields const&, Allocator const& alloc);
245 
246     /// Copy constructor.
247     template<class OtherAlloc>
248     basic_fields(basic_fields<OtherAlloc> const&);
249 
250     /** Copy constructor.
251 
252         @param alloc The allocator to use.
253     */
254     template<class OtherAlloc>
255     basic_fields(basic_fields<OtherAlloc> const&,
256         Allocator const& alloc);
257 
258     /** Move assignment.
259 
260         The state of the moved-from object is
261         as if constructed using the same allocator.
262     */
263     basic_fields& operator=(basic_fields&&) noexcept(
264         alloc_traits::propagate_on_container_move_assignment::value);
265 
266     /// Copy assignment.
267     basic_fields& operator=(basic_fields const&);
268 
269     /// Copy assignment.
270     template<class OtherAlloc>
271     basic_fields& operator=(basic_fields<OtherAlloc> const&);
272 
273 public:
274     /// A constant iterator to the field sequence.
275 #if BOOST_BEAST_DOXYGEN
276     using const_iterator = __implementation_defined__;
277 #else
278     using const_iterator = typename list_t::const_iterator;
279 #endif
280 
281     /// A constant iterator to the field sequence.
282     using iterator = const_iterator;
283 
284     /// Return a copy of the allocator associated with the container.
285     allocator_type
get_allocator() const286     get_allocator() const
287     {
288         return this->get();
289     }
290 
291     //--------------------------------------------------------------------------
292     //
293     // Element access
294     //
295     //--------------------------------------------------------------------------
296 
297     /** Returns the value for a field, or throws an exception.
298 
299         If more than one field with the specified name exists, the
300         first field defined by insertion order is returned.
301 
302         @param name The name of the field.
303 
304         @return The field value.
305 
306         @throws std::out_of_range if the field is not found.
307     */
308     string_view const
309     at(field name) const;
310 
311     /** Returns the value for a field, or throws an exception.
312 
313         If more than one field with the specified name exists, the
314         first field defined by insertion order is returned.
315 
316         @param name The name of the field.
317 
318         @return The field value.
319 
320         @throws std::out_of_range if the field is not found.
321     */
322     string_view const
323     at(string_view name) const;
324 
325     /** Returns the value for a field, or `""` if it does not exist.
326 
327         If more than one field with the specified name exists, the
328         first field defined by insertion order is returned.
329 
330         @param name The name of the field.
331     */
332     string_view const
333     operator[](field name) const;
334 
335     /** Returns the value for a case-insensitive matching header, or `""` if it does not exist.
336 
337         If more than one field with the specified name exists, the
338         first field defined by insertion order is returned.
339 
340         @param name The name of the field.
341     */
342     string_view const
343     operator[](string_view name) const;
344 
345     //--------------------------------------------------------------------------
346     //
347     // Iterators
348     //
349     //--------------------------------------------------------------------------
350 
351     /// Return a const iterator to the beginning of the field sequence.
352     const_iterator
begin() const353     begin() const
354     {
355         return list_.cbegin();
356     }
357 
358     /// Return a const iterator to the end of the field sequence.
359     const_iterator
end() const360     end() const
361     {
362         return list_.cend();
363     }
364 
365     /// Return a const iterator to the beginning of the field sequence.
366     const_iterator
cbegin() const367     cbegin() const
368     {
369         return list_.cbegin();
370     }
371 
372     /// Return a const iterator to the end of the field sequence.
373     const_iterator
cend() const374     cend() const
375     {
376         return list_.cend();
377     }
378 
379     //--------------------------------------------------------------------------
380     //
381     // Capacity
382     //
383     //--------------------------------------------------------------------------
384 
385 private:
386     // VFALCO Since the header and message derive from Fields,
387     //        what does the expression m.empty() mean? Its confusing.
388     bool
empty() const389     empty() const
390     {
391         return list_.empty();
392     }
393 public:
394 
395     //--------------------------------------------------------------------------
396     //
397     // Modifiers
398     //
399     //--------------------------------------------------------------------------
400 
401     /** Remove all fields from the container
402 
403         All references, pointers, or iterators referring to contained
404         elements are invalidated. All past-the-end iterators are also
405         invalidated.
406 
407         @par Postconditions:
408         @code
409             std::distance(this->begin(), this->end()) == 0
410         @endcode
411     */
412     void
413     clear();
414 
415     /** Insert a field.
416 
417         If one or more fields with the same name already exist,
418         the new field will be inserted after the last field with
419         the matching name, in serialization order.
420 
421         @param name The field name.
422 
423         @param value The value of the field, as a @ref string_view
424     */
425     void
426     insert(field name, string_view const& value);
427 
428     /* Set a field from a null pointer (deleted).
429     */
430     void
431     insert(field, std::nullptr_t) = delete;
432 
433     /** Insert a field.
434 
435         If one or more fields with the same name already exist,
436         the new field will be inserted after the last field with
437         the matching name, in serialization order.
438 
439         @param name The field name.
440 
441         @param value The value of the field, as a @ref string_view
442     */
443     void
444     insert(string_view name, string_view const& value);
445 
446     /* Insert a field from a null pointer (deleted).
447     */
448     void
449     insert(string_view, std::nullptr_t) = delete;
450 
451     /** Insert a field.
452 
453         If one or more fields with the same name already exist,
454         the new field will be inserted after the last field with
455         the matching name, in serialization order.
456 
457         @param name The field name.
458 
459         @param name_string The literal text corresponding to the
460         field name. If `name != field::unknown`, then this value
461         must be equal to `to_string(name)` using a case-insensitive
462         comparison, otherwise the behavior is undefined.
463 
464         @param value The value of the field, as a @ref string_view
465     */
466     void
467     insert(field name, string_view name_string,
468            string_view const& value);
469 
470     void
471     insert(field, string_view, std::nullptr_t) = delete;
472 
473     /** Set a field value, removing any other instances of that field.
474 
475         First removes any values with matching field names, then
476         inserts the new field value.
477 
478         @param name The field name.
479 
480         @param value The value of the field, as a @ref string_view
481 
482         @return The field value.
483     */
484     void
485     set(field name, string_view const& value);
486 
487     void
488     set(field, std::nullptr_t) = delete;
489 
490     /** Set a field value, removing any other instances of that field.
491 
492         First removes any values with matching field names, then
493         inserts the new field value.
494 
495         @param name The field name.
496 
497         @param value The value of the field, as a @ref string_view
498     */
499     void
500     set(string_view name, string_view const& value);
501 
502     void
503     set(string_view, std::nullptr_t) = delete;
504 
505         /** Remove a field.
506 
507         References and iterators to the erased elements are
508         invalidated. Other references and iterators are not
509         affected.
510 
511         @param pos An iterator to the element to remove.
512 
513         @return An iterator following the last removed element.
514         If the iterator refers to the last element, the end()
515         iterator is returned.
516     */
517     const_iterator
518     erase(const_iterator pos);
519 
520     /** Remove all fields with the specified name.
521 
522         All fields with the same field name are erased from the
523         container.
524         References and iterators to the erased elements are
525         invalidated. Other references and iterators are not
526         affected.
527 
528         @param name The field name.
529 
530         @return The number of fields removed.
531     */
532     std::size_t
533     erase(field name);
534 
535     /** Remove all fields with the specified name.
536 
537         All fields with the same field name are erased from the
538         container.
539         References and iterators to the erased elements are
540         invalidated. Other references and iterators are not
541         affected.
542 
543         @param name The field name.
544 
545         @return The number of fields removed.
546     */
547     std::size_t
548     erase(string_view name);
549 
550     /** Return a buffer sequence representing the trailers.
551 
552         This function returns a buffer sequence holding the
553         serialized representation of the trailer fields promised
554         in the Accept field. Before calling this function the
555         Accept field must contain the exact trailer fields
556         desired. Each field must also exist.
557     */
558 
559 
560     /// Swap this container with another
561     void
562     swap(basic_fields& other);
563 
564     /// Swap two field containers
565     template<class Alloc>
566     friend
567     void
568     swap(basic_fields<Alloc>& lhs, basic_fields<Alloc>& rhs);
569 
570     //--------------------------------------------------------------------------
571     //
572     // Lookup
573     //
574     //--------------------------------------------------------------------------
575 
576     /** Return the number of fields with the specified name.
577 
578         @param name The field name.
579     */
580     std::size_t
581     count(field name) const;
582 
583     /** Return the number of fields with the specified name.
584 
585         @param name The field name.
586     */
587     std::size_t
588     count(string_view name) const;
589 
590     /** Returns an iterator to the case-insensitive matching field.
591 
592         If more than one field with the specified name exists, the
593         first field defined by insertion order is returned.
594 
595         @param name The field name.
596 
597         @return An iterator to the matching field, or `end()` if
598         no match was found.
599     */
600     const_iterator
601     find(field name) const;
602 
603     /** Returns an iterator to the case-insensitive matching field name.
604 
605         If more than one field with the specified name exists, the
606         first field defined by insertion order is returned.
607 
608         @param name The field name.
609 
610         @return An iterator to the matching field, or `end()` if
611         no match was found.
612     */
613     const_iterator
614     find(string_view name) const;
615 
616     /** Returns a range of iterators to the fields with the specified name.
617 
618         @param name The field name.
619 
620         @return A range of iterators to fields with the same name,
621         otherwise an empty range.
622     */
623     std::pair<const_iterator, const_iterator>
624     equal_range(field name) const;
625 
626     /** Returns a range of iterators to the fields with the specified name.
627 
628         @param name The field name.
629 
630         @return A range of iterators to fields with the same name,
631         otherwise an empty range.
632     */
633     std::pair<const_iterator, const_iterator>
634     equal_range(string_view name) const;
635 
636     //--------------------------------------------------------------------------
637     //
638     // Observers
639     //
640     //--------------------------------------------------------------------------
641 
642     /// Returns a copy of the key comparison function
643     key_compare
key_comp() const644     key_comp() const
645     {
646         return key_compare{};
647     }
648 
649 protected:
650     /** Returns the request-method string.
651 
652         @note Only called for requests.
653     */
654     string_view
655     get_method_impl() const;
656 
657     /** Returns the request-target string.
658 
659         @note Only called for requests.
660     */
661     string_view
662     get_target_impl() const;
663 
664     /** Returns the response reason-phrase string.
665 
666         @note Only called for responses.
667     */
668     string_view
669     get_reason_impl() const;
670 
671     /** Returns the chunked Transfer-Encoding setting
672     */
673     bool
674     get_chunked_impl() const;
675 
676     /** Returns the keep-alive setting
677     */
678     bool
679     get_keep_alive_impl(unsigned version) const;
680 
681     /** Returns `true` if the Content-Length field is present.
682     */
683     bool
684     has_content_length_impl() const;
685 
686     /** Set or clear the method string.
687 
688         @note Only called for requests.
689     */
690     void
691     set_method_impl(string_view s);
692 
693     /** Set or clear the target string.
694 
695         @note Only called for requests.
696     */
697     void
698     set_target_impl(string_view s);
699 
700     /** Set or clear the reason string.
701 
702         @note Only called for responses.
703     */
704     void
705     set_reason_impl(string_view s);
706 
707     /** Adjusts the chunked Transfer-Encoding value
708     */
709     void
710     set_chunked_impl(bool value);
711 
712     /** Sets or clears the Content-Length field
713     */
714     void
715     set_content_length_impl(
716         boost::optional<std::uint64_t> const& value);
717 
718     /** Adjusts the Connection field
719     */
720     void
721     set_keep_alive_impl(
722         unsigned version, bool keep_alive);
723 
724 private:
725     template<class OtherAlloc>
726     friend class basic_fields;
727 
728     element&
729     new_element(field name,
730         string_view sname, string_view value);
731 
732     void
733     delete_element(element& e);
734 
735     void
736     set_element(element& e);
737 
738     void
739     realloc_string(string_view& dest, string_view s);
740 
741     void
742     realloc_target(
743         string_view& dest, string_view s);
744 
745     template<class OtherAlloc>
746     void
747     copy_all(basic_fields<OtherAlloc> const&);
748 
749     void
750     clear_all();
751 
752     void
753     delete_list();
754 
755     void
756     move_assign(basic_fields&, std::true_type);
757 
758     void
759     move_assign(basic_fields&, std::false_type);
760 
761     void
762     copy_assign(basic_fields const&, std::true_type);
763 
764     void
765     copy_assign(basic_fields const&, std::false_type);
766 
767     void
768     swap(basic_fields& other, std::true_type);
769 
770     void
771     swap(basic_fields& other, std::false_type);
772 
773     set_t set_;
774     list_t list_;
775     string_view method_;
776     string_view target_or_reason_;
777 };
778 
779 /// A typical HTTP header fields container
780 using fields = basic_fields<std::allocator<char>>;
781 
782 } // http
783 } // beast
784 } // boost
785 
786 #include <boost/beast/http/impl/fields.hpp>
787 
788 #endif
789