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