fields.hpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212
  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. other.clear_all();
  337. }
  338. else
  339. {
  340. set_ = std::move(other.set_);
  341. list_ = std::move(other.list_);
  342. method_ = other.method_;
  343. target_or_reason_ = other.target_or_reason_;
  344. }
  345. }
  346. template<class Allocator>
  347. basic_fields<Allocator>::
  348. basic_fields(basic_fields const& other)
  349. : boost::empty_value<Allocator>(boost::empty_init_t(), alloc_traits::
  350. select_on_container_copy_construction(other.get()))
  351. {
  352. copy_all(other);
  353. }
  354. template<class Allocator>
  355. basic_fields<Allocator>::
  356. basic_fields(basic_fields const& other,
  357. Allocator const& alloc)
  358. : boost::empty_value<Allocator>(boost::empty_init_t(), alloc)
  359. {
  360. copy_all(other);
  361. }
  362. template<class Allocator>
  363. template<class OtherAlloc>
  364. basic_fields<Allocator>::
  365. basic_fields(basic_fields<OtherAlloc> const& other)
  366. {
  367. copy_all(other);
  368. }
  369. template<class Allocator>
  370. template<class OtherAlloc>
  371. basic_fields<Allocator>::
  372. basic_fields(basic_fields<OtherAlloc> const& other,
  373. Allocator const& alloc)
  374. : boost::empty_value<Allocator>(boost::empty_init_t(), alloc)
  375. {
  376. copy_all(other);
  377. }
  378. template<class Allocator>
  379. auto
  380. basic_fields<Allocator>::
  381. operator=(basic_fields&& other) noexcept(
  382. alloc_traits::propagate_on_container_move_assignment::value)
  383. -> basic_fields&
  384. {
  385. static_assert(is_nothrow_move_assignable<Allocator>::value,
  386. "Allocator must be noexcept assignable.");
  387. if(this == &other)
  388. return *this;
  389. move_assign(other, std::integral_constant<bool,
  390. alloc_traits:: propagate_on_container_move_assignment::value>{});
  391. return *this;
  392. }
  393. template<class Allocator>
  394. auto
  395. basic_fields<Allocator>::
  396. operator=(basic_fields const& other) ->
  397. basic_fields&
  398. {
  399. copy_assign(other, std::integral_constant<bool,
  400. alloc_traits::propagate_on_container_copy_assignment::value>{});
  401. return *this;
  402. }
  403. template<class Allocator>
  404. template<class OtherAlloc>
  405. auto
  406. basic_fields<Allocator>::
  407. operator=(basic_fields<OtherAlloc> const& other) ->
  408. basic_fields&
  409. {
  410. clear_all();
  411. copy_all(other);
  412. return *this;
  413. }
  414. //------------------------------------------------------------------------------
  415. //
  416. // Element access
  417. //
  418. //------------------------------------------------------------------------------
  419. template<class Allocator>
  420. string_view const
  421. basic_fields<Allocator>::
  422. at(field name) const
  423. {
  424. BOOST_ASSERT(name != field::unknown);
  425. auto const it = find(name);
  426. if(it == end())
  427. BOOST_THROW_EXCEPTION(std::out_of_range{
  428. "field not found"});
  429. return it->value();
  430. }
  431. template<class Allocator>
  432. string_view const
  433. basic_fields<Allocator>::
  434. at(string_view name) const
  435. {
  436. auto const it = find(name);
  437. if(it == end())
  438. BOOST_THROW_EXCEPTION(std::out_of_range{
  439. "field not found"});
  440. return it->value();
  441. }
  442. template<class Allocator>
  443. string_view const
  444. basic_fields<Allocator>::
  445. operator[](field name) const
  446. {
  447. BOOST_ASSERT(name != field::unknown);
  448. auto const it = find(name);
  449. if(it == end())
  450. return {};
  451. return it->value();
  452. }
  453. template<class Allocator>
  454. string_view const
  455. basic_fields<Allocator>::
  456. operator[](string_view name) const
  457. {
  458. auto const it = find(name);
  459. if(it == end())
  460. return {};
  461. return it->value();
  462. }
  463. //------------------------------------------------------------------------------
  464. //
  465. // Modifiers
  466. //
  467. //------------------------------------------------------------------------------
  468. template<class Allocator>
  469. void
  470. basic_fields<Allocator>::
  471. clear()
  472. {
  473. delete_list();
  474. set_.clear();
  475. list_.clear();
  476. }
  477. template<class Allocator>
  478. inline
  479. void
  480. basic_fields<Allocator>::
  481. insert(field name, string_param const& value)
  482. {
  483. BOOST_ASSERT(name != field::unknown);
  484. insert(name, to_string(name), value);
  485. }
  486. template<class Allocator>
  487. void
  488. basic_fields<Allocator>::
  489. insert(string_view sname, string_param const& value)
  490. {
  491. auto const name =
  492. string_to_field(sname);
  493. insert(name, sname, value);
  494. }
  495. template<class Allocator>
  496. void
  497. basic_fields<Allocator>::
  498. insert(field name,
  499. string_view sname, string_param const& value)
  500. {
  501. auto& e = new_element(name, sname,
  502. static_cast<string_view>(value));
  503. auto const before =
  504. set_.upper_bound(sname, key_compare{});
  505. if(before == set_.begin())
  506. {
  507. BOOST_ASSERT(count(sname) == 0);
  508. set_.insert_before(before, e);
  509. list_.push_back(e);
  510. return;
  511. }
  512. auto const last = std::prev(before);
  513. // VFALCO is it worth comparing `field name` first?
  514. if(! beast::iequals(sname, last->name_string()))
  515. {
  516. BOOST_ASSERT(count(sname) == 0);
  517. set_.insert_before(before, e);
  518. list_.push_back(e);
  519. return;
  520. }
  521. // keep duplicate fields together in the list
  522. set_.insert_before(before, e);
  523. list_.insert(++list_.iterator_to(*last), e);
  524. }
  525. template<class Allocator>
  526. void
  527. basic_fields<Allocator>::
  528. set(field name, string_param const& value)
  529. {
  530. BOOST_ASSERT(name != field::unknown);
  531. set_element(new_element(name, to_string(name),
  532. static_cast<string_view>(value)));
  533. }
  534. template<class Allocator>
  535. void
  536. basic_fields<Allocator>::
  537. set(string_view sname, string_param const& value)
  538. {
  539. set_element(new_element(
  540. string_to_field(sname), sname,
  541. static_cast<string_view>(value)));
  542. }
  543. template<class Allocator>
  544. auto
  545. basic_fields<Allocator>::
  546. erase(const_iterator pos) ->
  547. const_iterator
  548. {
  549. auto next = pos;
  550. auto& e = *next++;
  551. set_.erase(e);
  552. list_.erase(pos);
  553. delete_element(const_cast<element&>(e));
  554. return next;
  555. }
  556. template<class Allocator>
  557. std::size_t
  558. basic_fields<Allocator>::
  559. erase(field name)
  560. {
  561. BOOST_ASSERT(name != field::unknown);
  562. return erase(to_string(name));
  563. }
  564. template<class Allocator>
  565. std::size_t
  566. basic_fields<Allocator>::
  567. erase(string_view name)
  568. {
  569. std::size_t n =0;
  570. set_.erase_and_dispose(name, key_compare{},
  571. [&](element* e)
  572. {
  573. ++n;
  574. list_.erase(list_.iterator_to(*e));
  575. delete_element(*e);
  576. });
  577. return n;
  578. }
  579. template<class Allocator>
  580. void
  581. basic_fields<Allocator>::
  582. swap(basic_fields<Allocator>& other)
  583. {
  584. swap(other, std::integral_constant<bool,
  585. alloc_traits::propagate_on_container_swap::value>{});
  586. }
  587. template<class Allocator>
  588. void
  589. swap(
  590. basic_fields<Allocator>& lhs,
  591. basic_fields<Allocator>& rhs)
  592. {
  593. lhs.swap(rhs);
  594. }
  595. //------------------------------------------------------------------------------
  596. //
  597. // Lookup
  598. //
  599. //------------------------------------------------------------------------------
  600. template<class Allocator>
  601. inline
  602. std::size_t
  603. basic_fields<Allocator>::
  604. count(field name) const
  605. {
  606. BOOST_ASSERT(name != field::unknown);
  607. return count(to_string(name));
  608. }
  609. template<class Allocator>
  610. std::size_t
  611. basic_fields<Allocator>::
  612. count(string_view name) const
  613. {
  614. return set_.count(name, key_compare{});
  615. }
  616. template<class Allocator>
  617. inline
  618. auto
  619. basic_fields<Allocator>::
  620. find(field name) const ->
  621. const_iterator
  622. {
  623. BOOST_ASSERT(name != field::unknown);
  624. return find(to_string(name));
  625. }
  626. template<class Allocator>
  627. auto
  628. basic_fields<Allocator>::
  629. find(string_view name) const ->
  630. const_iterator
  631. {
  632. auto const it = set_.find(
  633. name, key_compare{});
  634. if(it == set_.end())
  635. return list_.end();
  636. return list_.iterator_to(*it);
  637. }
  638. template<class Allocator>
  639. inline
  640. auto
  641. basic_fields<Allocator>::
  642. equal_range(field name) const ->
  643. std::pair<const_iterator, const_iterator>
  644. {
  645. BOOST_ASSERT(name != field::unknown);
  646. return equal_range(to_string(name));
  647. }
  648. template<class Allocator>
  649. auto
  650. basic_fields<Allocator>::
  651. equal_range(string_view name) const ->
  652. std::pair<const_iterator, const_iterator>
  653. {
  654. auto result =
  655. set_.equal_range(name, key_compare{});
  656. if(result.first == result.second)
  657. return {list_.end(), list_.end()};
  658. return {
  659. list_.iterator_to(*result.first),
  660. ++list_.iterator_to(*(--result.second))};
  661. }
  662. //------------------------------------------------------------------------------
  663. namespace detail {
  664. struct iequals_predicate
  665. {
  666. bool
  667. operator()(string_view s) const
  668. {
  669. return beast::iequals(s, sv1) || beast::iequals(s, sv2);
  670. }
  671. string_view sv1;
  672. string_view sv2;
  673. };
  674. // Filter the last item in a token list
  675. BOOST_BEAST_DECL
  676. void
  677. filter_token_list_last(
  678. beast::detail::temporary_buffer& s,
  679. string_view value,
  680. iequals_predicate const& pred);
  681. BOOST_BEAST_DECL
  682. void
  683. keep_alive_impl(
  684. beast::detail::temporary_buffer& s, string_view value,
  685. unsigned version, bool keep_alive);
  686. } // detail
  687. //------------------------------------------------------------------------------
  688. // Fields
  689. template<class Allocator>
  690. inline
  691. string_view
  692. basic_fields<Allocator>::
  693. get_method_impl() const
  694. {
  695. return method_;
  696. }
  697. template<class Allocator>
  698. inline
  699. string_view
  700. basic_fields<Allocator>::
  701. get_target_impl() const
  702. {
  703. if(target_or_reason_.empty())
  704. return target_or_reason_;
  705. return {
  706. target_or_reason_.data() + 1,
  707. target_or_reason_.size() - 1};
  708. }
  709. template<class Allocator>
  710. inline
  711. string_view
  712. basic_fields<Allocator>::
  713. get_reason_impl() const
  714. {
  715. return target_or_reason_;
  716. }
  717. template<class Allocator>
  718. bool
  719. basic_fields<Allocator>::
  720. get_chunked_impl() const
  721. {
  722. auto const te = token_list{
  723. (*this)[field::transfer_encoding]};
  724. for(auto it = te.begin(); it != te.end();)
  725. {
  726. auto const next = std::next(it);
  727. if(next == te.end())
  728. return beast::iequals(*it, "chunked");
  729. it = next;
  730. }
  731. return false;
  732. }
  733. template<class Allocator>
  734. bool
  735. basic_fields<Allocator>::
  736. get_keep_alive_impl(unsigned version) const
  737. {
  738. auto const it = find(field::connection);
  739. if(version < 11)
  740. {
  741. if(it == end())
  742. return false;
  743. return token_list{
  744. it->value()}.exists("keep-alive");
  745. }
  746. if(it == end())
  747. return true;
  748. return ! token_list{
  749. it->value()}.exists("close");
  750. }
  751. template<class Allocator>
  752. bool
  753. basic_fields<Allocator>::
  754. has_content_length_impl() const
  755. {
  756. return count(field::content_length) > 0;
  757. }
  758. template<class Allocator>
  759. inline
  760. void
  761. basic_fields<Allocator>::
  762. set_method_impl(string_view s)
  763. {
  764. realloc_string(method_, s);
  765. }
  766. template<class Allocator>
  767. inline
  768. void
  769. basic_fields<Allocator>::
  770. set_target_impl(string_view s)
  771. {
  772. realloc_target(
  773. target_or_reason_, s);
  774. }
  775. template<class Allocator>
  776. inline
  777. void
  778. basic_fields<Allocator>::
  779. set_reason_impl(string_view s)
  780. {
  781. realloc_string(
  782. target_or_reason_, s);
  783. }
  784. template<class Allocator>
  785. void
  786. basic_fields<Allocator>::
  787. set_chunked_impl(bool value)
  788. {
  789. beast::detail::temporary_buffer buf;
  790. auto it = find(field::transfer_encoding);
  791. if(value)
  792. {
  793. // append "chunked"
  794. if(it == end())
  795. {
  796. set(field::transfer_encoding, "chunked");
  797. return;
  798. }
  799. auto const te = token_list{it->value()};
  800. for(auto itt = te.begin();;)
  801. {
  802. auto const next = std::next(itt);
  803. if(next == te.end())
  804. {
  805. if(beast::iequals(*itt, "chunked"))
  806. return; // already set
  807. break;
  808. }
  809. itt = next;
  810. }
  811. buf.append(it->value(), ", chunked");
  812. set(field::transfer_encoding, buf.view());
  813. return;
  814. }
  815. // filter "chunked"
  816. if(it == end())
  817. return;
  818. detail::filter_token_list_last(buf, it->value(), {"chunked", {}});
  819. if(! buf.empty())
  820. set(field::transfer_encoding, buf.view());
  821. else
  822. erase(field::transfer_encoding);
  823. }
  824. template<class Allocator>
  825. void
  826. basic_fields<Allocator>::
  827. set_content_length_impl(
  828. boost::optional<std::uint64_t> const& value)
  829. {
  830. if(! value)
  831. erase(field::content_length);
  832. else
  833. set(field::content_length, *value);
  834. }
  835. template<class Allocator>
  836. void
  837. basic_fields<Allocator>::
  838. set_keep_alive_impl(
  839. unsigned version, bool keep_alive)
  840. {
  841. // VFALCO What about Proxy-Connection ?
  842. auto const value = (*this)[field::connection];
  843. beast::detail::temporary_buffer buf;
  844. detail::keep_alive_impl(buf, value, version, keep_alive);
  845. if(buf.empty())
  846. erase(field::connection);
  847. else
  848. set(field::connection, buf.view());
  849. }
  850. //------------------------------------------------------------------------------
  851. template<class Allocator>
  852. auto
  853. basic_fields<Allocator>::
  854. new_element(field name,
  855. string_view sname, string_view value) ->
  856. element&
  857. {
  858. if(sname.size() + 2 >
  859. (std::numeric_limits<off_t>::max)())
  860. BOOST_THROW_EXCEPTION(std::length_error{
  861. "field name too large"});
  862. if(value.size() + 2 >
  863. (std::numeric_limits<off_t>::max)())
  864. BOOST_THROW_EXCEPTION(std::length_error{
  865. "field value too large"});
  866. value = detail::trim(value);
  867. std::uint16_t const off =
  868. static_cast<off_t>(sname.size() + 2);
  869. std::uint16_t const len =
  870. static_cast<off_t>(value.size());
  871. auto a = rebind_type{this->get()};
  872. auto const p = alloc_traits::allocate(a,
  873. (sizeof(element) + off + len + 2 + sizeof(align_type) - 1) /
  874. sizeof(align_type));
  875. return *(::new(p) element(name, sname, value));
  876. }
  877. template<class Allocator>
  878. void
  879. basic_fields<Allocator>::
  880. delete_element(element& e)
  881. {
  882. auto a = rebind_type{this->get()};
  883. auto const n =
  884. (sizeof(element) + e.off_ + e.len_ + 2 + sizeof(align_type) - 1) /
  885. sizeof(align_type);
  886. e.~element();
  887. alloc_traits::deallocate(a,
  888. reinterpret_cast<align_type*>(&e), n);
  889. }
  890. template<class Allocator>
  891. void
  892. basic_fields<Allocator>::
  893. set_element(element& e)
  894. {
  895. auto it = set_.lower_bound(
  896. e.name_string(), key_compare{});
  897. if(it == set_.end() || ! beast::iequals(
  898. e.name_string(), it->name_string()))
  899. {
  900. set_.insert_before(it, e);
  901. list_.push_back(e);
  902. return;
  903. }
  904. for(;;)
  905. {
  906. auto next = it;
  907. ++next;
  908. set_.erase(it);
  909. list_.erase(list_.iterator_to(*it));
  910. delete_element(*it);
  911. it = next;
  912. if(it == set_.end() ||
  913. ! beast::iequals(e.name_string(), it->name_string()))
  914. break;
  915. }
  916. set_.insert_before(it, e);
  917. list_.push_back(e);
  918. }
  919. template<class Allocator>
  920. void
  921. basic_fields<Allocator>::
  922. realloc_string(string_view& dest, string_view s)
  923. {
  924. if(dest.empty() && s.empty())
  925. return;
  926. auto a = typename beast::detail::allocator_traits<
  927. Allocator>::template rebind_alloc<
  928. char>(this->get());
  929. char* p = nullptr;
  930. if(! s.empty())
  931. {
  932. p = a.allocate(s.size());
  933. s.copy(p, s.size());
  934. }
  935. if(! dest.empty())
  936. a.deallocate(const_cast<char*>(
  937. dest.data()), dest.size());
  938. if(p)
  939. dest = {p, s.size()};
  940. else
  941. dest = {};
  942. }
  943. template<class Allocator>
  944. void
  945. basic_fields<Allocator>::
  946. realloc_target(
  947. string_view& dest, string_view s)
  948. {
  949. // The target string are stored with an
  950. // extra space at the beginning to help
  951. // the writer class.
  952. if(dest.empty() && s.empty())
  953. return;
  954. auto a = typename beast::detail::allocator_traits<
  955. Allocator>::template rebind_alloc<
  956. char>(this->get());
  957. char* p = nullptr;
  958. if(! s.empty())
  959. {
  960. p = a.allocate(1 + s.size());
  961. p[0] = ' ';
  962. s.copy(p + 1, s.size());
  963. }
  964. if(! dest.empty())
  965. a.deallocate(const_cast<char*>(
  966. dest.data()), dest.size());
  967. if(p)
  968. dest = {p, 1 + s.size()};
  969. else
  970. dest = {};
  971. }
  972. template<class Allocator>
  973. template<class OtherAlloc>
  974. void
  975. basic_fields<Allocator>::
  976. copy_all(basic_fields<OtherAlloc> const& other)
  977. {
  978. for(auto const& e : other.list_)
  979. insert(e.name(), e.name_string(), e.value());
  980. realloc_string(method_, other.method_);
  981. realloc_string(target_or_reason_,
  982. other.target_or_reason_);
  983. }
  984. template<class Allocator>
  985. void
  986. basic_fields<Allocator>::
  987. clear_all()
  988. {
  989. clear();
  990. realloc_string(method_, {});
  991. realloc_string(target_or_reason_, {});
  992. }
  993. template<class Allocator>
  994. void
  995. basic_fields<Allocator>::
  996. delete_list()
  997. {
  998. for(auto it = list_.begin(); it != list_.end();)
  999. delete_element(*it++);
  1000. }
  1001. //------------------------------------------------------------------------------
  1002. template<class Allocator>
  1003. inline
  1004. void
  1005. basic_fields<Allocator>::
  1006. move_assign(basic_fields& other, std::true_type)
  1007. {
  1008. clear_all();
  1009. set_ = std::move(other.set_);
  1010. list_ = std::move(other.list_);
  1011. method_ = other.method_;
  1012. target_or_reason_ = other.target_or_reason_;
  1013. other.method_ = {};
  1014. other.target_or_reason_ = {};
  1015. this->get() = other.get();
  1016. }
  1017. template<class Allocator>
  1018. inline
  1019. void
  1020. basic_fields<Allocator>::
  1021. move_assign(basic_fields& other, std::false_type)
  1022. {
  1023. clear_all();
  1024. if(this->get() != other.get())
  1025. {
  1026. copy_all(other);
  1027. other.clear_all();
  1028. }
  1029. else
  1030. {
  1031. set_ = std::move(other.set_);
  1032. list_ = std::move(other.list_);
  1033. method_ = other.method_;
  1034. target_or_reason_ = other.target_or_reason_;
  1035. other.method_ = {};
  1036. other.target_or_reason_ = {};
  1037. }
  1038. }
  1039. template<class Allocator>
  1040. inline
  1041. void
  1042. basic_fields<Allocator>::
  1043. copy_assign(basic_fields const& other, std::true_type)
  1044. {
  1045. clear_all();
  1046. this->get() = other.get();
  1047. copy_all(other);
  1048. }
  1049. template<class Allocator>
  1050. inline
  1051. void
  1052. basic_fields<Allocator>::
  1053. copy_assign(basic_fields const& other, std::false_type)
  1054. {
  1055. clear_all();
  1056. copy_all(other);
  1057. }
  1058. template<class Allocator>
  1059. inline
  1060. void
  1061. basic_fields<Allocator>::
  1062. swap(basic_fields& other, std::true_type)
  1063. {
  1064. using std::swap;
  1065. swap(this->get(), other.get());
  1066. swap(set_, other.set_);
  1067. swap(list_, other.list_);
  1068. swap(method_, other.method_);
  1069. swap(target_or_reason_, other.target_or_reason_);
  1070. }
  1071. template<class Allocator>
  1072. inline
  1073. void
  1074. basic_fields<Allocator>::
  1075. swap(basic_fields& other, std::false_type)
  1076. {
  1077. BOOST_ASSERT(this->get() == other.get());
  1078. using std::swap;
  1079. swap(set_, other.set_);
  1080. swap(list_, other.list_);
  1081. swap(method_, other.method_);
  1082. swap(target_or_reason_, other.target_or_reason_);
  1083. }
  1084. } // http
  1085. } // beast
  1086. } // boost
  1087. #ifdef BOOST_BEAST_HEADER_ONLY
  1088. #include <boost/beast/http/impl/fields.ipp>
  1089. #endif
  1090. #endif