fields.hpp 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210
  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. #ifndef BOOST_BEAST_HTTP_IMPL_FIELDS_HPP
  10. #define BOOST_BEAST_HTTP_IMPL_FIELDS_HPP
  11. #include <boost/beast/core/buffers_cat.hpp>
  12. #include <boost/beast/core/string.hpp>
  13. #include <boost/beast/core/detail/buffers_ref.hpp>
  14. #include <boost/beast/core/detail/clamp.hpp>
  15. #include <boost/beast/core/detail/temporary_buffer.hpp>
  16. #include <boost/beast/http/verb.hpp>
  17. #include <boost/beast/http/rfc7230.hpp>
  18. #include <boost/beast/http/status.hpp>
  19. #include <boost/beast/http/chunk_encode.hpp>
  20. #include <boost/core/exchange.hpp>
  21. #include <boost/throw_exception.hpp>
  22. #include <stdexcept>
  23. #include <string>
  24. namespace boost {
  25. namespace beast {
  26. namespace http {
  27. template<class Allocator>
  28. class basic_fields<Allocator>::writer
  29. {
  30. public:
  31. using iter_type = typename list_t::const_iterator;
  32. struct field_iterator
  33. {
  34. iter_type it_;
  35. using value_type = net::const_buffer;
  36. using pointer = value_type const*;
  37. using reference = value_type const;
  38. using difference_type = std::ptrdiff_t;
  39. using iterator_category =
  40. std::bidirectional_iterator_tag;
  41. field_iterator() = default;
  42. field_iterator(field_iterator&& other) = default;
  43. field_iterator(field_iterator const& other) = default;
  44. field_iterator& operator=(field_iterator&& other) = default;
  45. field_iterator& operator=(field_iterator const& other) = default;
  46. explicit
  47. field_iterator(iter_type it)
  48. : it_(it)
  49. {
  50. }
  51. bool
  52. operator==(field_iterator const& other) const
  53. {
  54. return it_ == other.it_;
  55. }
  56. bool
  57. operator!=(field_iterator const& other) const
  58. {
  59. return !(*this == other);
  60. }
  61. reference
  62. operator*() const
  63. {
  64. return it_->buffer();
  65. }
  66. field_iterator&
  67. operator++()
  68. {
  69. ++it_;
  70. return *this;
  71. }
  72. field_iterator
  73. operator++(int)
  74. {
  75. auto temp = *this;
  76. ++(*this);
  77. return temp;
  78. }
  79. field_iterator&
  80. operator--()
  81. {
  82. --it_;
  83. return *this;
  84. }
  85. field_iterator
  86. operator--(int)
  87. {
  88. auto temp = *this;
  89. --(*this);
  90. return temp;
  91. }
  92. };
  93. class field_range
  94. {
  95. field_iterator first_;
  96. field_iterator last_;
  97. public:
  98. using const_iterator =
  99. field_iterator;
  100. using value_type =
  101. typename const_iterator::value_type;
  102. field_range(iter_type first, iter_type last)
  103. : first_(first)
  104. , last_(last)
  105. {
  106. }
  107. const_iterator
  108. begin() const
  109. {
  110. return first_;
  111. }
  112. const_iterator
  113. end() const
  114. {
  115. return last_;
  116. }
  117. };
  118. using view_type = buffers_cat_view<
  119. net::const_buffer,
  120. net::const_buffer,
  121. net::const_buffer,
  122. field_range,
  123. chunk_crlf>;
  124. basic_fields const& f_;
  125. boost::optional<view_type> view_;
  126. char buf_[13];
  127. public:
  128. using const_buffers_type =
  129. beast::detail::buffers_ref<view_type>;
  130. writer(basic_fields const& f,
  131. unsigned version, verb v);
  132. writer(basic_fields const& f,
  133. unsigned version, unsigned code);
  134. writer(basic_fields const& f);
  135. const_buffers_type
  136. get() const
  137. {
  138. return const_buffers_type(*view_);
  139. }
  140. };
  141. template<class Allocator>
  142. basic_fields<Allocator>::writer::
  143. writer(basic_fields const& f)
  144. : f_(f)
  145. {
  146. view_.emplace(
  147. net::const_buffer{nullptr, 0},
  148. net::const_buffer{nullptr, 0},
  149. net::const_buffer{nullptr, 0},
  150. field_range(f_.list_.begin(), f_.list_.end()),
  151. chunk_crlf());
  152. }
  153. template<class Allocator>
  154. basic_fields<Allocator>::writer::
  155. writer(basic_fields const& f,
  156. unsigned version, verb v)
  157. : f_(f)
  158. {
  159. /*
  160. request
  161. "<method>"
  162. " <target>"
  163. " HTTP/X.Y\r\n" (11 chars)
  164. */
  165. string_view sv;
  166. if(v == verb::unknown)
  167. sv = f_.get_method_impl();
  168. else
  169. sv = to_string(v);
  170. // target_or_reason_ has a leading SP
  171. buf_[0] = ' ';
  172. buf_[1] = 'H';
  173. buf_[2] = 'T';
  174. buf_[3] = 'T';
  175. buf_[4] = 'P';
  176. buf_[5] = '/';
  177. buf_[6] = '0' + static_cast<char>(version / 10);
  178. buf_[7] = '.';
  179. buf_[8] = '0' + static_cast<char>(version % 10);
  180. buf_[9] = '\r';
  181. buf_[10]= '\n';
  182. view_.emplace(
  183. net::const_buffer{sv.data(), sv.size()},
  184. net::const_buffer{
  185. f_.target_or_reason_.data(),
  186. f_.target_or_reason_.size()},
  187. net::const_buffer{buf_, 11},
  188. field_range(f_.list_.begin(), f_.list_.end()),
  189. chunk_crlf());
  190. }
  191. template<class Allocator>
  192. basic_fields<Allocator>::writer::
  193. writer(basic_fields const& f,
  194. unsigned version, unsigned code)
  195. : f_(f)
  196. {
  197. /*
  198. response
  199. "HTTP/X.Y ### " (13 chars)
  200. "<reason>"
  201. "\r\n"
  202. */
  203. buf_[0] = 'H';
  204. buf_[1] = 'T';
  205. buf_[2] = 'T';
  206. buf_[3] = 'P';
  207. buf_[4] = '/';
  208. buf_[5] = '0' + static_cast<char>(version / 10);
  209. buf_[6] = '.';
  210. buf_[7] = '0' + static_cast<char>(version % 10);
  211. buf_[8] = ' ';
  212. buf_[9] = '0' + static_cast<char>(code / 100);
  213. buf_[10]= '0' + static_cast<char>((code / 10) % 10);
  214. buf_[11]= '0' + static_cast<char>(code % 10);
  215. buf_[12]= ' ';
  216. string_view sv;
  217. if(! f_.target_or_reason_.empty())
  218. sv = f_.target_or_reason_;
  219. else
  220. sv = obsolete_reason(static_cast<status>(code));
  221. view_.emplace(
  222. net::const_buffer{buf_, 13},
  223. net::const_buffer{sv.data(), sv.size()},
  224. net::const_buffer{"\r\n", 2},
  225. field_range(f_.list_.begin(), f_.list_.end()),
  226. chunk_crlf{});
  227. }
  228. //------------------------------------------------------------------------------
  229. template<class Allocator>
  230. char*
  231. basic_fields<Allocator>::
  232. value_type::
  233. data() const
  234. {
  235. return const_cast<char*>(
  236. reinterpret_cast<char const*>(
  237. static_cast<element const*>(this) + 1));
  238. }
  239. template<class Allocator>
  240. net::const_buffer
  241. basic_fields<Allocator>::
  242. value_type::
  243. buffer() const
  244. {
  245. return net::const_buffer{data(),
  246. static_cast<std::size_t>(off_) + len_ + 2};
  247. }
  248. template<class Allocator>
  249. basic_fields<Allocator>::
  250. value_type::
  251. value_type(field name,
  252. string_view sname, string_view value)
  253. : off_(static_cast<off_t>(sname.size() + 2))
  254. , len_(static_cast<off_t>(value.size()))
  255. , f_(name)
  256. {
  257. //BOOST_ASSERT(name == field::unknown ||
  258. // iequals(sname, to_string(name)));
  259. char* p = data();
  260. p[off_-2] = ':';
  261. p[off_-1] = ' ';
  262. p[off_ + len_] = '\r';
  263. p[off_ + len_ + 1] = '\n';
  264. sname.copy(p, sname.size());
  265. value.copy(p + off_, value.size());
  266. }
  267. template<class Allocator>
  268. field
  269. basic_fields<Allocator>::
  270. value_type::
  271. name() const
  272. {
  273. return f_;
  274. }
  275. template<class Allocator>
  276. string_view const
  277. basic_fields<Allocator>::
  278. value_type::
  279. name_string() const
  280. {
  281. return {data(),
  282. static_cast<std::size_t>(off_ - 2)};
  283. }
  284. template<class Allocator>
  285. string_view const
  286. basic_fields<Allocator>::
  287. value_type::
  288. value() const
  289. {
  290. return {data() + off_,
  291. static_cast<std::size_t>(len_)};
  292. }
  293. template<class Allocator>
  294. basic_fields<Allocator>::
  295. element::
  296. element(field name,
  297. string_view sname, string_view value)
  298. : value_type(name, sname, value)
  299. {
  300. }
  301. //------------------------------------------------------------------------------
  302. template<class Allocator>
  303. basic_fields<Allocator>::
  304. ~basic_fields()
  305. {
  306. delete_list();
  307. realloc_string(method_, {});
  308. realloc_string(
  309. target_or_reason_, {});
  310. }
  311. template<class Allocator>
  312. basic_fields<Allocator>::
  313. basic_fields(Allocator const& alloc) noexcept
  314. : boost::empty_value<Allocator>(boost::empty_init_t(), alloc)
  315. {
  316. }
  317. template<class Allocator>
  318. basic_fields<Allocator>::
  319. basic_fields(basic_fields&& other) noexcept
  320. : boost::empty_value<Allocator>(boost::empty_init_t(),
  321. std::move(other.get()))
  322. , set_(std::move(other.set_))
  323. , list_(std::move(other.list_))
  324. , method_(boost::exchange(other.method_, {}))
  325. , target_or_reason_(boost::exchange(other.target_or_reason_, {}))
  326. {
  327. }
  328. template<class Allocator>
  329. basic_fields<Allocator>::
  330. basic_fields(basic_fields&& other, Allocator const& alloc)
  331. : boost::empty_value<Allocator>(boost::empty_init_t(), alloc)
  332. {
  333. if(this->get() != other.get())
  334. {
  335. copy_all(other);
  336. }
  337. else
  338. {
  339. set_ = std::move(other.set_);
  340. list_ = std::move(other.list_);
  341. method_ = other.method_;
  342. target_or_reason_ = other.target_or_reason_;
  343. }
  344. }
  345. template<class Allocator>
  346. basic_fields<Allocator>::
  347. basic_fields(basic_fields const& other)
  348. : boost::empty_value<Allocator>(boost::empty_init_t(), alloc_traits::
  349. select_on_container_copy_construction(other.get()))
  350. {
  351. copy_all(other);
  352. }
  353. template<class Allocator>
  354. basic_fields<Allocator>::
  355. basic_fields(basic_fields const& other,
  356. Allocator const& alloc)
  357. : boost::empty_value<Allocator>(boost::empty_init_t(), alloc)
  358. {
  359. copy_all(other);
  360. }
  361. template<class Allocator>
  362. template<class OtherAlloc>
  363. basic_fields<Allocator>::
  364. basic_fields(basic_fields<OtherAlloc> const& other)
  365. {
  366. copy_all(other);
  367. }
  368. template<class Allocator>
  369. template<class OtherAlloc>
  370. basic_fields<Allocator>::
  371. basic_fields(basic_fields<OtherAlloc> const& other,
  372. Allocator const& alloc)
  373. : boost::empty_value<Allocator>(boost::empty_init_t(), alloc)
  374. {
  375. copy_all(other);
  376. }
  377. template<class Allocator>
  378. auto
  379. basic_fields<Allocator>::
  380. operator=(basic_fields&& other) noexcept(
  381. alloc_traits::propagate_on_container_move_assignment::value)
  382. -> basic_fields&
  383. {
  384. static_assert(is_nothrow_move_assignable<Allocator>::value,
  385. "Allocator must be noexcept assignable.");
  386. if(this == &other)
  387. return *this;
  388. move_assign(other, std::integral_constant<bool,
  389. alloc_traits:: propagate_on_container_move_assignment::value>{});
  390. return *this;
  391. }
  392. template<class Allocator>
  393. auto
  394. basic_fields<Allocator>::
  395. operator=(basic_fields const& other) ->
  396. basic_fields&
  397. {
  398. copy_assign(other, std::integral_constant<bool,
  399. alloc_traits::propagate_on_container_copy_assignment::value>{});
  400. return *this;
  401. }
  402. template<class Allocator>
  403. template<class OtherAlloc>
  404. auto
  405. basic_fields<Allocator>::
  406. operator=(basic_fields<OtherAlloc> const& other) ->
  407. basic_fields&
  408. {
  409. clear_all();
  410. copy_all(other);
  411. return *this;
  412. }
  413. //------------------------------------------------------------------------------
  414. //
  415. // Element access
  416. //
  417. //------------------------------------------------------------------------------
  418. template<class Allocator>
  419. string_view const
  420. basic_fields<Allocator>::
  421. at(field name) const
  422. {
  423. BOOST_ASSERT(name != field::unknown);
  424. auto const it = find(name);
  425. if(it == end())
  426. BOOST_THROW_EXCEPTION(std::out_of_range{
  427. "field not found"});
  428. return it->value();
  429. }
  430. template<class Allocator>
  431. string_view const
  432. basic_fields<Allocator>::
  433. at(string_view name) const
  434. {
  435. auto const it = find(name);
  436. if(it == end())
  437. BOOST_THROW_EXCEPTION(std::out_of_range{
  438. "field not found"});
  439. return it->value();
  440. }
  441. template<class Allocator>
  442. string_view const
  443. basic_fields<Allocator>::
  444. operator[](field name) const
  445. {
  446. BOOST_ASSERT(name != field::unknown);
  447. auto const it = find(name);
  448. if(it == end())
  449. return {};
  450. return it->value();
  451. }
  452. template<class Allocator>
  453. string_view const
  454. basic_fields<Allocator>::
  455. operator[](string_view name) const
  456. {
  457. auto const it = find(name);
  458. if(it == end())
  459. return {};
  460. return it->value();
  461. }
  462. //------------------------------------------------------------------------------
  463. //
  464. // Modifiers
  465. //
  466. //------------------------------------------------------------------------------
  467. template<class Allocator>
  468. void
  469. basic_fields<Allocator>::
  470. clear()
  471. {
  472. delete_list();
  473. set_.clear();
  474. list_.clear();
  475. }
  476. template<class Allocator>
  477. inline
  478. void
  479. basic_fields<Allocator>::
  480. insert(field name, string_param const& value)
  481. {
  482. BOOST_ASSERT(name != field::unknown);
  483. insert(name, to_string(name), value);
  484. }
  485. template<class Allocator>
  486. void
  487. basic_fields<Allocator>::
  488. insert(string_view sname, string_param const& value)
  489. {
  490. auto const name =
  491. string_to_field(sname);
  492. insert(name, sname, value);
  493. }
  494. template<class Allocator>
  495. void
  496. basic_fields<Allocator>::
  497. insert(field name,
  498. string_view sname, string_param const& value)
  499. {
  500. auto& e = new_element(name, sname,
  501. static_cast<string_view>(value));
  502. auto const before =
  503. set_.upper_bound(sname, key_compare{});
  504. if(before == set_.begin())
  505. {
  506. BOOST_ASSERT(count(sname) == 0);
  507. set_.insert_before(before, e);
  508. list_.push_back(e);
  509. return;
  510. }
  511. auto const last = std::prev(before);
  512. // VFALCO is it worth comparing `field name` first?
  513. if(! beast::iequals(sname, last->name_string()))
  514. {
  515. BOOST_ASSERT(count(sname) == 0);
  516. set_.insert_before(before, e);
  517. list_.push_back(e);
  518. return;
  519. }
  520. // keep duplicate fields together in the list
  521. set_.insert_before(before, e);
  522. list_.insert(++list_.iterator_to(*last), e);
  523. }
  524. template<class Allocator>
  525. void
  526. basic_fields<Allocator>::
  527. set(field name, string_param const& value)
  528. {
  529. BOOST_ASSERT(name != field::unknown);
  530. set_element(new_element(name, to_string(name),
  531. static_cast<string_view>(value)));
  532. }
  533. template<class Allocator>
  534. void
  535. basic_fields<Allocator>::
  536. set(string_view sname, string_param const& value)
  537. {
  538. set_element(new_element(
  539. string_to_field(sname), sname,
  540. static_cast<string_view>(value)));
  541. }
  542. template<class Allocator>
  543. auto
  544. basic_fields<Allocator>::
  545. erase(const_iterator pos) ->
  546. const_iterator
  547. {
  548. auto next = pos;
  549. auto& e = *next++;
  550. set_.erase(set_.iterator_to(e));
  551. list_.erase(pos);
  552. delete_element(const_cast<element&>(e));
  553. return next;
  554. }
  555. template<class Allocator>
  556. std::size_t
  557. basic_fields<Allocator>::
  558. erase(field name)
  559. {
  560. BOOST_ASSERT(name != field::unknown);
  561. return erase(to_string(name));
  562. }
  563. template<class Allocator>
  564. std::size_t
  565. basic_fields<Allocator>::
  566. erase(string_view name)
  567. {
  568. std::size_t n =0;
  569. set_.erase_and_dispose(name, key_compare{},
  570. [&](element* e)
  571. {
  572. ++n;
  573. list_.erase(list_.iterator_to(*e));
  574. delete_element(*e);
  575. });
  576. return n;
  577. }
  578. template<class Allocator>
  579. void
  580. basic_fields<Allocator>::
  581. swap(basic_fields<Allocator>& other)
  582. {
  583. swap(other, std::integral_constant<bool,
  584. alloc_traits::propagate_on_container_swap::value>{});
  585. }
  586. template<class Allocator>
  587. void
  588. swap(
  589. basic_fields<Allocator>& lhs,
  590. basic_fields<Allocator>& rhs)
  591. {
  592. lhs.swap(rhs);
  593. }
  594. //------------------------------------------------------------------------------
  595. //
  596. // Lookup
  597. //
  598. //------------------------------------------------------------------------------
  599. template<class Allocator>
  600. inline
  601. std::size_t
  602. basic_fields<Allocator>::
  603. count(field name) const
  604. {
  605. BOOST_ASSERT(name != field::unknown);
  606. return count(to_string(name));
  607. }
  608. template<class Allocator>
  609. std::size_t
  610. basic_fields<Allocator>::
  611. count(string_view name) const
  612. {
  613. return set_.count(name, key_compare{});
  614. }
  615. template<class Allocator>
  616. inline
  617. auto
  618. basic_fields<Allocator>::
  619. find(field name) const ->
  620. const_iterator
  621. {
  622. BOOST_ASSERT(name != field::unknown);
  623. return find(to_string(name));
  624. }
  625. template<class Allocator>
  626. auto
  627. basic_fields<Allocator>::
  628. find(string_view name) const ->
  629. const_iterator
  630. {
  631. auto const it = set_.find(
  632. name, key_compare{});
  633. if(it == set_.end())
  634. return list_.end();
  635. return list_.iterator_to(*it);
  636. }
  637. template<class Allocator>
  638. inline
  639. auto
  640. basic_fields<Allocator>::
  641. equal_range(field name) const ->
  642. std::pair<const_iterator, const_iterator>
  643. {
  644. BOOST_ASSERT(name != field::unknown);
  645. return equal_range(to_string(name));
  646. }
  647. template<class Allocator>
  648. auto
  649. basic_fields<Allocator>::
  650. equal_range(string_view name) const ->
  651. std::pair<const_iterator, const_iterator>
  652. {
  653. auto result =
  654. set_.equal_range(name, key_compare{});
  655. if(result.first == result.second)
  656. return {list_.end(), list_.end()};
  657. return {
  658. list_.iterator_to(*result.first),
  659. ++list_.iterator_to(*(--result.second))};
  660. }
  661. //------------------------------------------------------------------------------
  662. namespace detail {
  663. struct iequals_predicate
  664. {
  665. bool
  666. operator()(string_view s) const
  667. {
  668. return beast::iequals(s, sv1) || beast::iequals(s, sv2);
  669. }
  670. string_view sv1;
  671. string_view sv2;
  672. };
  673. // Filter the last item in a token list
  674. BOOST_BEAST_DECL
  675. void
  676. filter_token_list_last(
  677. beast::detail::temporary_buffer& s,
  678. string_view value,
  679. iequals_predicate const& pred);
  680. BOOST_BEAST_DECL
  681. void
  682. keep_alive_impl(
  683. beast::detail::temporary_buffer& s, string_view value,
  684. unsigned version, bool keep_alive);
  685. } // detail
  686. //------------------------------------------------------------------------------
  687. // Fields
  688. template<class Allocator>
  689. inline
  690. string_view
  691. basic_fields<Allocator>::
  692. get_method_impl() const
  693. {
  694. return method_;
  695. }
  696. template<class Allocator>
  697. inline
  698. string_view
  699. basic_fields<Allocator>::
  700. get_target_impl() const
  701. {
  702. if(target_or_reason_.empty())
  703. return target_or_reason_;
  704. return {
  705. target_or_reason_.data() + 1,
  706. target_or_reason_.size() - 1};
  707. }
  708. template<class Allocator>
  709. inline
  710. string_view
  711. basic_fields<Allocator>::
  712. get_reason_impl() const
  713. {
  714. return target_or_reason_;
  715. }
  716. template<class Allocator>
  717. bool
  718. basic_fields<Allocator>::
  719. get_chunked_impl() const
  720. {
  721. auto const te = token_list{
  722. (*this)[field::transfer_encoding]};
  723. for(auto it = te.begin(); it != te.end();)
  724. {
  725. auto const next = std::next(it);
  726. if(next == te.end())
  727. return beast::iequals(*it, "chunked");
  728. it = next;
  729. }
  730. return false;
  731. }
  732. template<class Allocator>
  733. bool
  734. basic_fields<Allocator>::
  735. get_keep_alive_impl(unsigned version) const
  736. {
  737. auto const it = find(field::connection);
  738. if(version < 11)
  739. {
  740. if(it == end())
  741. return false;
  742. return token_list{
  743. it->value()}.exists("keep-alive");
  744. }
  745. if(it == end())
  746. return true;
  747. return ! token_list{
  748. it->value()}.exists("close");
  749. }
  750. template<class Allocator>
  751. bool
  752. basic_fields<Allocator>::
  753. has_content_length_impl() const
  754. {
  755. return count(field::content_length) > 0;
  756. }
  757. template<class Allocator>
  758. inline
  759. void
  760. basic_fields<Allocator>::
  761. set_method_impl(string_view s)
  762. {
  763. realloc_string(method_, s);
  764. }
  765. template<class Allocator>
  766. inline
  767. void
  768. basic_fields<Allocator>::
  769. set_target_impl(string_view s)
  770. {
  771. realloc_target(
  772. target_or_reason_, s);
  773. }
  774. template<class Allocator>
  775. inline
  776. void
  777. basic_fields<Allocator>::
  778. set_reason_impl(string_view s)
  779. {
  780. realloc_string(
  781. target_or_reason_, s);
  782. }
  783. template<class Allocator>
  784. void
  785. basic_fields<Allocator>::
  786. set_chunked_impl(bool value)
  787. {
  788. beast::detail::temporary_buffer buf;
  789. auto it = find(field::transfer_encoding);
  790. if(value)
  791. {
  792. // append "chunked"
  793. if(it == end())
  794. {
  795. set(field::transfer_encoding, "chunked");
  796. return;
  797. }
  798. auto const te = token_list{it->value()};
  799. for(auto itt = te.begin();;)
  800. {
  801. auto const next = std::next(itt);
  802. if(next == te.end())
  803. {
  804. if(beast::iequals(*itt, "chunked"))
  805. return; // already set
  806. break;
  807. }
  808. itt = next;
  809. }
  810. buf.append(it->value(), ", chunked");
  811. set(field::transfer_encoding, buf.view());
  812. return;
  813. }
  814. // filter "chunked"
  815. if(it == end())
  816. return;
  817. detail::filter_token_list_last(buf, it->value(), {"chunked", {}});
  818. if(! buf.empty())
  819. set(field::transfer_encoding, buf.view());
  820. else
  821. erase(field::transfer_encoding);
  822. }
  823. template<class Allocator>
  824. void
  825. basic_fields<Allocator>::
  826. set_content_length_impl(
  827. boost::optional<std::uint64_t> const& value)
  828. {
  829. if(! value)
  830. erase(field::content_length);
  831. else
  832. set(field::content_length, *value);
  833. }
  834. template<class Allocator>
  835. void
  836. basic_fields<Allocator>::
  837. set_keep_alive_impl(
  838. unsigned version, bool keep_alive)
  839. {
  840. // VFALCO What about Proxy-Connection ?
  841. auto const value = (*this)[field::connection];
  842. beast::detail::temporary_buffer buf;
  843. detail::keep_alive_impl(buf, value, version, keep_alive);
  844. if(buf.empty())
  845. erase(field::connection);
  846. else
  847. set(field::connection, buf.view());
  848. }
  849. //------------------------------------------------------------------------------
  850. template<class Allocator>
  851. auto
  852. basic_fields<Allocator>::
  853. new_element(field name,
  854. string_view sname, string_view value) ->
  855. element&
  856. {
  857. if(sname.size() + 2 >
  858. (std::numeric_limits<off_t>::max)())
  859. BOOST_THROW_EXCEPTION(std::length_error{
  860. "field name too large"});
  861. if(value.size() + 2 >
  862. (std::numeric_limits<off_t>::max)())
  863. BOOST_THROW_EXCEPTION(std::length_error{
  864. "field value too large"});
  865. value = detail::trim(value);
  866. std::uint16_t const off =
  867. static_cast<off_t>(sname.size() + 2);
  868. std::uint16_t const len =
  869. static_cast<off_t>(value.size());
  870. auto a = rebind_type{this->get()};
  871. auto const p = alloc_traits::allocate(a,
  872. (sizeof(element) + off + len + 2 + sizeof(align_type) - 1) /
  873. sizeof(align_type));
  874. return *(::new(p) element(name, sname, value));
  875. }
  876. template<class Allocator>
  877. void
  878. basic_fields<Allocator>::
  879. delete_element(element& e)
  880. {
  881. auto a = rebind_type{this->get()};
  882. auto const n =
  883. (sizeof(element) + e.off_ + e.len_ + 2 + sizeof(align_type) - 1) /
  884. sizeof(align_type);
  885. e.~element();
  886. alloc_traits::deallocate(a,
  887. reinterpret_cast<align_type*>(&e), n);
  888. }
  889. template<class Allocator>
  890. void
  891. basic_fields<Allocator>::
  892. set_element(element& e)
  893. {
  894. auto it = set_.lower_bound(
  895. e.name_string(), key_compare{});
  896. if(it == set_.end() || ! beast::iequals(
  897. e.name_string(), it->name_string()))
  898. {
  899. set_.insert_before(it, e);
  900. list_.push_back(e);
  901. return;
  902. }
  903. for(;;)
  904. {
  905. auto next = it;
  906. ++next;
  907. set_.erase(it);
  908. list_.erase(list_.iterator_to(*it));
  909. delete_element(*it);
  910. it = next;
  911. if(it == set_.end() ||
  912. ! beast::iequals(e.name_string(), it->name_string()))
  913. break;
  914. }
  915. set_.insert_before(it, e);
  916. list_.push_back(e);
  917. }
  918. template<class Allocator>
  919. void
  920. basic_fields<Allocator>::
  921. realloc_string(string_view& dest, string_view s)
  922. {
  923. if(dest.empty() && s.empty())
  924. return;
  925. auto a = typename beast::detail::allocator_traits<
  926. Allocator>::template rebind_alloc<
  927. char>(this->get());
  928. char* p = nullptr;
  929. if(! s.empty())
  930. {
  931. p = a.allocate(s.size());
  932. s.copy(p, s.size());
  933. }
  934. if(! dest.empty())
  935. a.deallocate(const_cast<char*>(
  936. dest.data()), dest.size());
  937. if(p)
  938. dest = {p, s.size()};
  939. else
  940. dest = {};
  941. }
  942. template<class Allocator>
  943. void
  944. basic_fields<Allocator>::
  945. realloc_target(
  946. string_view& dest, string_view s)
  947. {
  948. // The target string are stored with an
  949. // extra space at the beginning to help
  950. // the writer class.
  951. if(dest.empty() && s.empty())
  952. return;
  953. auto a = typename beast::detail::allocator_traits<
  954. Allocator>::template rebind_alloc<
  955. char>(this->get());
  956. char* p = nullptr;
  957. if(! s.empty())
  958. {
  959. p = a.allocate(1 + s.size());
  960. p[0] = ' ';
  961. s.copy(p + 1, s.size());
  962. }
  963. if(! dest.empty())
  964. a.deallocate(const_cast<char*>(
  965. dest.data()), dest.size());
  966. if(p)
  967. dest = {p, 1 + s.size()};
  968. else
  969. dest = {};
  970. }
  971. template<class Allocator>
  972. template<class OtherAlloc>
  973. void
  974. basic_fields<Allocator>::
  975. copy_all(basic_fields<OtherAlloc> const& other)
  976. {
  977. for(auto const& e : other.list_)
  978. insert(e.name(), e.name_string(), e.value());
  979. realloc_string(method_, other.method_);
  980. realloc_string(target_or_reason_,
  981. other.target_or_reason_);
  982. }
  983. template<class Allocator>
  984. void
  985. basic_fields<Allocator>::
  986. clear_all()
  987. {
  988. clear();
  989. realloc_string(method_, {});
  990. realloc_string(target_or_reason_, {});
  991. }
  992. template<class Allocator>
  993. void
  994. basic_fields<Allocator>::
  995. delete_list()
  996. {
  997. for(auto it = list_.begin(); it != list_.end();)
  998. delete_element(*it++);
  999. }
  1000. //------------------------------------------------------------------------------
  1001. template<class Allocator>
  1002. inline
  1003. void
  1004. basic_fields<Allocator>::
  1005. move_assign(basic_fields& other, std::true_type)
  1006. {
  1007. clear_all();
  1008. set_ = std::move(other.set_);
  1009. list_ = std::move(other.list_);
  1010. method_ = other.method_;
  1011. target_or_reason_ = other.target_or_reason_;
  1012. other.method_ = {};
  1013. other.target_or_reason_ = {};
  1014. this->get() = other.get();
  1015. }
  1016. template<class Allocator>
  1017. inline
  1018. void
  1019. basic_fields<Allocator>::
  1020. move_assign(basic_fields& other, std::false_type)
  1021. {
  1022. clear_all();
  1023. if(this->get() != other.get())
  1024. {
  1025. copy_all(other);
  1026. }
  1027. else
  1028. {
  1029. set_ = std::move(other.set_);
  1030. list_ = std::move(other.list_);
  1031. method_ = other.method_;
  1032. target_or_reason_ = other.target_or_reason_;
  1033. other.method_ = {};
  1034. other.target_or_reason_ = {};
  1035. }
  1036. }
  1037. template<class Allocator>
  1038. inline
  1039. void
  1040. basic_fields<Allocator>::
  1041. copy_assign(basic_fields const& other, std::true_type)
  1042. {
  1043. clear_all();
  1044. this->get() = other.get();
  1045. copy_all(other);
  1046. }
  1047. template<class Allocator>
  1048. inline
  1049. void
  1050. basic_fields<Allocator>::
  1051. copy_assign(basic_fields const& other, std::false_type)
  1052. {
  1053. clear_all();
  1054. copy_all(other);
  1055. }
  1056. template<class Allocator>
  1057. inline
  1058. void
  1059. basic_fields<Allocator>::
  1060. swap(basic_fields& other, std::true_type)
  1061. {
  1062. using std::swap;
  1063. swap(this->get(), other.get());
  1064. swap(set_, other.set_);
  1065. swap(list_, other.list_);
  1066. swap(method_, other.method_);
  1067. swap(target_or_reason_, other.target_or_reason_);
  1068. }
  1069. template<class Allocator>
  1070. inline
  1071. void
  1072. basic_fields<Allocator>::
  1073. swap(basic_fields& other, std::false_type)
  1074. {
  1075. BOOST_ASSERT(this->get() == other.get());
  1076. using std::swap;
  1077. swap(set_, other.set_);
  1078. swap(list_, other.list_);
  1079. swap(method_, other.method_);
  1080. swap(target_or_reason_, other.target_or_reason_);
  1081. }
  1082. } // http
  1083. } // beast
  1084. } // boost
  1085. #ifdef BOOST_BEAST_HEADER_ONLY
  1086. #include <boost/beast/http/impl/fields.ipp>
  1087. #endif
  1088. #endif