fields.hpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215
  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 BHO_BEAST_HTTP_IMPL_FIELDS_HPP
  10. #define BHO_BEAST_HTTP_IMPL_FIELDS_HPP
  11. #include <asio2/bho/beast/core/buffers_cat.hpp>
  12. #include <asio2/bho/beast/core/string.hpp>
  13. #include <asio2/bho/beast/core/detail/buffers_ref.hpp>
  14. #include <asio2/bho/beast/core/detail/clamp.hpp>
  15. #include <asio2/bho/beast/core/detail/static_string.hpp>
  16. #include <asio2/bho/beast/core/detail/temporary_buffer.hpp>
  17. #include <asio2/bho/beast/core/static_string.hpp>
  18. #include <asio2/bho/beast/http/verb.hpp>
  19. #include <asio2/bho/beast/http/rfc7230.hpp>
  20. #include <asio2/bho/beast/http/status.hpp>
  21. #include <asio2/bho/beast/http/chunk_encode.hpp>
  22. #include <asio2/bho/core/exchange.hpp>
  23. #include <asio2/bho/throw_exception.hpp>
  24. #include <stdexcept>
  25. #include <string>
  26. namespace bho {
  27. namespace beast {
  28. namespace http {
  29. template<class Allocator>
  30. class basic_fields<Allocator>::writer
  31. {
  32. public:
  33. using iter_type = typename list_t::const_iterator;
  34. struct field_iterator
  35. {
  36. iter_type it_;
  37. using value_type = net::const_buffer;
  38. using pointer = value_type const*;
  39. using reference = value_type const;
  40. using difference_type = std::ptrdiff_t;
  41. using iterator_category =
  42. std::bidirectional_iterator_tag;
  43. field_iterator() = default;
  44. field_iterator(field_iterator&& other) = default;
  45. field_iterator(field_iterator const& other) = default;
  46. field_iterator& operator=(field_iterator&& other) = default;
  47. field_iterator& operator=(field_iterator const& other) = default;
  48. explicit
  49. field_iterator(iter_type it)
  50. : it_(it)
  51. {
  52. }
  53. bool
  54. operator==(field_iterator const& other) const
  55. {
  56. return it_ == other.it_;
  57. }
  58. bool
  59. operator!=(field_iterator const& other) const
  60. {
  61. return !(*this == other);
  62. }
  63. reference
  64. operator*() const
  65. {
  66. return it_->buffer();
  67. }
  68. field_iterator&
  69. operator++()
  70. {
  71. ++it_;
  72. return *this;
  73. }
  74. field_iterator
  75. operator++(int)
  76. {
  77. auto temp = *this;
  78. ++(*this);
  79. return temp;
  80. }
  81. field_iterator&
  82. operator--()
  83. {
  84. --it_;
  85. return *this;
  86. }
  87. field_iterator
  88. operator--(int)
  89. {
  90. auto temp = *this;
  91. --(*this);
  92. return temp;
  93. }
  94. };
  95. class field_range
  96. {
  97. field_iterator first_;
  98. field_iterator last_;
  99. public:
  100. using const_iterator =
  101. field_iterator;
  102. using value_type =
  103. typename const_iterator::value_type;
  104. field_range(iter_type first, iter_type last)
  105. : first_(first)
  106. , last_(last)
  107. {
  108. }
  109. const_iterator
  110. begin() const
  111. {
  112. return first_;
  113. }
  114. const_iterator
  115. end() const
  116. {
  117. return last_;
  118. }
  119. };
  120. using view_type = buffers_cat_view<
  121. net::const_buffer,
  122. net::const_buffer,
  123. net::const_buffer,
  124. field_range,
  125. chunk_crlf>;
  126. basic_fields const& f_;
  127. std::optional<view_type> view_;
  128. char buf_[13];
  129. public:
  130. using const_buffers_type =
  131. beast::detail::buffers_ref<view_type>;
  132. writer(basic_fields const& f,
  133. unsigned version, verb v);
  134. writer(basic_fields const& f,
  135. unsigned version, unsigned code);
  136. writer(basic_fields const& f);
  137. const_buffers_type
  138. get() const
  139. {
  140. return const_buffers_type(*view_);
  141. }
  142. };
  143. template<class Allocator>
  144. basic_fields<Allocator>::writer::
  145. writer(basic_fields const& f)
  146. : f_(f)
  147. {
  148. view_.emplace(
  149. net::const_buffer{nullptr, 0},
  150. net::const_buffer{nullptr, 0},
  151. net::const_buffer{nullptr, 0},
  152. field_range(f_.list_.begin(), f_.list_.end()),
  153. chunk_crlf());
  154. }
  155. template<class Allocator>
  156. basic_fields<Allocator>::writer::
  157. writer(basic_fields const& f,
  158. unsigned version, verb v)
  159. : f_(f)
  160. {
  161. /*
  162. request
  163. "<method>"
  164. " <target>"
  165. " HTTP/X.Y\r\n" (11 chars)
  166. */
  167. string_view sv;
  168. if(v == verb::unknown)
  169. sv = f_.get_method_impl();
  170. else
  171. sv = to_string(v);
  172. // target_or_reason_ has a leading SP
  173. buf_[0] = ' ';
  174. buf_[1] = 'H';
  175. buf_[2] = 'T';
  176. buf_[3] = 'T';
  177. buf_[4] = 'P';
  178. buf_[5] = '/';
  179. buf_[6] = '0' + static_cast<char>(version / 10);
  180. buf_[7] = '.';
  181. buf_[8] = '0' + static_cast<char>(version % 10);
  182. buf_[9] = '\r';
  183. buf_[10]= '\n';
  184. view_.emplace(
  185. net::const_buffer{sv.data(), sv.size()},
  186. net::const_buffer{
  187. f_.target_or_reason_.data(),
  188. f_.target_or_reason_.size()},
  189. net::const_buffer{buf_, 11},
  190. field_range(f_.list_.begin(), f_.list_.end()),
  191. chunk_crlf());
  192. }
  193. template<class Allocator>
  194. basic_fields<Allocator>::writer::
  195. writer(basic_fields const& f,
  196. unsigned version, unsigned code)
  197. : f_(f)
  198. {
  199. /*
  200. response
  201. "HTTP/X.Y ### " (13 chars)
  202. "<reason>"
  203. "\r\n"
  204. */
  205. buf_[0] = 'H';
  206. buf_[1] = 'T';
  207. buf_[2] = 'T';
  208. buf_[3] = 'P';
  209. buf_[4] = '/';
  210. buf_[5] = '0' + static_cast<char>(version / 10);
  211. buf_[6] = '.';
  212. buf_[7] = '0' + static_cast<char>(version % 10);
  213. buf_[8] = ' ';
  214. buf_[9] = '0' + static_cast<char>(code / 100);
  215. buf_[10]= '0' + static_cast<char>((code / 10) % 10);
  216. buf_[11]= '0' + static_cast<char>(code % 10);
  217. buf_[12]= ' ';
  218. string_view sv;
  219. if(! f_.target_or_reason_.empty())
  220. sv = f_.target_or_reason_;
  221. else
  222. sv = obsolete_reason(static_cast<status>(code));
  223. view_.emplace(
  224. net::const_buffer{buf_, 13},
  225. net::const_buffer{sv.data(), sv.size()},
  226. net::const_buffer{"\r\n", 2},
  227. field_range(f_.list_.begin(), f_.list_.end()),
  228. chunk_crlf{});
  229. }
  230. //------------------------------------------------------------------------------
  231. template<class Allocator>
  232. char*
  233. basic_fields<Allocator>::
  234. value_type::
  235. data() const
  236. {
  237. return const_cast<char*>(
  238. reinterpret_cast<char const*>(
  239. static_cast<element const*>(this) + 1));
  240. }
  241. template<class Allocator>
  242. net::const_buffer
  243. basic_fields<Allocator>::
  244. value_type::
  245. buffer() const
  246. {
  247. return net::const_buffer{data(),
  248. static_cast<std::size_t>(off_) + len_ + 2};
  249. }
  250. template<class Allocator>
  251. basic_fields<Allocator>::
  252. value_type::
  253. value_type(field name,
  254. string_view sname, string_view value)
  255. : off_(static_cast<off_t>(sname.size() + 2))
  256. , len_(static_cast<off_t>(value.size()))
  257. , f_(name)
  258. {
  259. //BHO_ASSERT(name == field::unknown ||
  260. // iequals(sname, to_string(name)));
  261. char* p = data();
  262. p[off_-2] = ':';
  263. p[off_-1] = ' ';
  264. p[off_ + len_] = '\r';
  265. p[off_ + len_ + 1] = '\n';
  266. sname.copy(p, sname.size());
  267. value.copy(p + off_, value.size());
  268. }
  269. template<class Allocator>
  270. field
  271. basic_fields<Allocator>::
  272. value_type::
  273. name() const
  274. {
  275. return f_;
  276. }
  277. template<class Allocator>
  278. string_view const
  279. basic_fields<Allocator>::
  280. value_type::
  281. name_string() const
  282. {
  283. return {data(),
  284. static_cast<std::size_t>(off_ - 2)};
  285. }
  286. template<class Allocator>
  287. string_view const
  288. basic_fields<Allocator>::
  289. value_type::
  290. value() const
  291. {
  292. return {data() + off_,
  293. static_cast<std::size_t>(len_)};
  294. }
  295. template<class Allocator>
  296. basic_fields<Allocator>::
  297. element::
  298. element(field name,
  299. string_view sname, string_view value)
  300. : value_type(name, sname, value)
  301. {
  302. }
  303. //------------------------------------------------------------------------------
  304. template<class Allocator>
  305. basic_fields<Allocator>::
  306. ~basic_fields()
  307. {
  308. delete_list();
  309. realloc_string(method_, {});
  310. realloc_string(
  311. target_or_reason_, {});
  312. }
  313. template<class Allocator>
  314. basic_fields<Allocator>::
  315. basic_fields(Allocator const& alloc) noexcept
  316. : bho::empty_value<Allocator>(bho::empty_init_t(), alloc)
  317. {
  318. }
  319. template<class Allocator>
  320. basic_fields<Allocator>::
  321. basic_fields(basic_fields&& other) noexcept
  322. : bho::empty_value<Allocator>(bho::empty_init_t(),
  323. std::move(other.get()))
  324. , set_(std::move(other.set_))
  325. , list_(std::move(other.list_))
  326. , method_(std::exchange(other.method_, {}))
  327. , target_or_reason_(std::exchange(other.target_or_reason_, {}))
  328. {
  329. }
  330. template<class Allocator>
  331. basic_fields<Allocator>::
  332. basic_fields(basic_fields&& other, Allocator const& alloc)
  333. : bho::empty_value<Allocator>(bho::empty_init_t(), alloc)
  334. {
  335. if(this->get() != other.get())
  336. {
  337. copy_all(other);
  338. }
  339. else
  340. {
  341. set_ = std::move(other.set_);
  342. list_ = std::move(other.list_);
  343. method_ = other.method_;
  344. target_or_reason_ = other.target_or_reason_;
  345. }
  346. }
  347. template<class Allocator>
  348. basic_fields<Allocator>::
  349. basic_fields(basic_fields const& other)
  350. : bho::empty_value<Allocator>(bho::empty_init_t(), alloc_traits::
  351. select_on_container_copy_construction(other.get()))
  352. {
  353. copy_all(other);
  354. }
  355. template<class Allocator>
  356. basic_fields<Allocator>::
  357. basic_fields(basic_fields const& other,
  358. Allocator const& alloc)
  359. : bho::empty_value<Allocator>(bho::empty_init_t(), alloc)
  360. {
  361. copy_all(other);
  362. }
  363. template<class Allocator>
  364. template<class OtherAlloc>
  365. basic_fields<Allocator>::
  366. basic_fields(basic_fields<OtherAlloc> const& other)
  367. {
  368. copy_all(other);
  369. }
  370. template<class Allocator>
  371. template<class OtherAlloc>
  372. basic_fields<Allocator>::
  373. basic_fields(basic_fields<OtherAlloc> const& other,
  374. Allocator const& alloc)
  375. : bho::empty_value<Allocator>(bho::empty_init_t(), alloc)
  376. {
  377. copy_all(other);
  378. }
  379. template<class Allocator>
  380. auto
  381. basic_fields<Allocator>::
  382. operator=(basic_fields&& other) noexcept(
  383. alloc_traits::propagate_on_container_move_assignment::value)
  384. -> basic_fields&
  385. {
  386. static_assert(std::is_nothrow_move_assignable<Allocator>::value,
  387. "Allocator must be noexcept assignable.");
  388. if(this == &other)
  389. return *this;
  390. move_assign(other, std::integral_constant<bool,
  391. alloc_traits:: propagate_on_container_move_assignment::value>{});
  392. return *this;
  393. }
  394. template<class Allocator>
  395. auto
  396. basic_fields<Allocator>::
  397. operator=(basic_fields const& other) ->
  398. basic_fields&
  399. {
  400. copy_assign(other, std::integral_constant<bool,
  401. alloc_traits::propagate_on_container_copy_assignment::value>{});
  402. return *this;
  403. }
  404. template<class Allocator>
  405. template<class OtherAlloc>
  406. auto
  407. basic_fields<Allocator>::
  408. operator=(basic_fields<OtherAlloc> const& other) ->
  409. basic_fields&
  410. {
  411. clear_all();
  412. copy_all(other);
  413. return *this;
  414. }
  415. //------------------------------------------------------------------------------
  416. //
  417. // Element access
  418. //
  419. //------------------------------------------------------------------------------
  420. template<class Allocator>
  421. string_view const
  422. basic_fields<Allocator>::
  423. at(field name) const
  424. {
  425. BHO_ASSERT(name != field::unknown);
  426. auto const it = find(name);
  427. if(it == end())
  428. BHO_THROW_EXCEPTION(std::out_of_range{
  429. "field not found"});
  430. return it->value();
  431. }
  432. template<class Allocator>
  433. string_view const
  434. basic_fields<Allocator>::
  435. at(string_view name) const
  436. {
  437. auto const it = find(name);
  438. if(it == end())
  439. BHO_THROW_EXCEPTION(std::out_of_range{
  440. "field not found"});
  441. return it->value();
  442. }
  443. template<class Allocator>
  444. string_view const
  445. basic_fields<Allocator>::
  446. operator[](field name) const
  447. {
  448. BHO_ASSERT(name != field::unknown);
  449. auto const it = find(name);
  450. if(it == end())
  451. return {};
  452. return it->value();
  453. }
  454. template<class Allocator>
  455. string_view const
  456. basic_fields<Allocator>::
  457. operator[](string_view name) const
  458. {
  459. auto const it = find(name);
  460. if(it == end())
  461. return {};
  462. return it->value();
  463. }
  464. //------------------------------------------------------------------------------
  465. //
  466. // Modifiers
  467. //
  468. //------------------------------------------------------------------------------
  469. template<class Allocator>
  470. void
  471. basic_fields<Allocator>::
  472. clear()
  473. {
  474. delete_list();
  475. set_.clear();
  476. list_.clear();
  477. }
  478. template<class Allocator>
  479. inline
  480. void
  481. basic_fields<Allocator>::
  482. insert(field name, string_view const& value)
  483. {
  484. BHO_ASSERT(name != field::unknown);
  485. insert(name, to_string(name), value);
  486. }
  487. template<class Allocator>
  488. void
  489. basic_fields<Allocator>::
  490. insert(string_view sname, string_view const& value)
  491. {
  492. auto const name =
  493. string_to_field(sname);
  494. insert(name, sname, value);
  495. }
  496. template<class Allocator>
  497. void
  498. basic_fields<Allocator>::
  499. insert(field name,
  500. string_view sname, string_view const& value)
  501. {
  502. auto& e = new_element(name, sname,
  503. static_cast<string_view>(value));
  504. auto const before =
  505. set_.upper_bound(sname, key_compare{});
  506. if(before == set_.begin())
  507. {
  508. BHO_ASSERT(count(sname) == 0);
  509. set_.insert_before(before, e);
  510. list_.push_back(e);
  511. return;
  512. }
  513. auto const last = std::prev(before);
  514. // VFALCO is it worth comparing `field name` first?
  515. if(! beast::iequals(sname, last->name_string()))
  516. {
  517. BHO_ASSERT(count(sname) == 0);
  518. set_.insert_before(before, e);
  519. list_.push_back(e);
  520. return;
  521. }
  522. // keep duplicate fields together in the list
  523. set_.insert_before(before, e);
  524. list_.insert(++list_.iterator_to(*last), e);
  525. }
  526. template<class Allocator>
  527. void
  528. basic_fields<Allocator>::
  529. set(field name, string_view const& value)
  530. {
  531. BHO_ASSERT(name != field::unknown);
  532. set_element(new_element(name, to_string(name),
  533. static_cast<string_view>(value)));
  534. }
  535. template<class Allocator>
  536. void
  537. basic_fields<Allocator>::
  538. set(string_view sname, string_view const& value)
  539. {
  540. set_element(new_element(
  541. string_to_field(sname), sname, 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(set_.iterator_to(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. BHO_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. BHO_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. BHO_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. BHO_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. BHO_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. BHO_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. std::optional<std::uint64_t> const& value)
  829. {
  830. if(! value)
  831. erase(field::content_length);
  832. else
  833. {
  834. auto s = to_static_string(*value);
  835. set(field::content_length,
  836. to_string_view(s));
  837. }
  838. }
  839. template<class Allocator>
  840. void
  841. basic_fields<Allocator>::
  842. set_keep_alive_impl(
  843. unsigned version, bool keep_alive)
  844. {
  845. // VFALCO What about Proxy-Connection ?
  846. auto const value = (*this)[field::connection];
  847. beast::detail::temporary_buffer buf;
  848. detail::keep_alive_impl(buf, value, version, keep_alive);
  849. if(buf.empty())
  850. erase(field::connection);
  851. else
  852. set(field::connection, buf.view());
  853. }
  854. //------------------------------------------------------------------------------
  855. template<class Allocator>
  856. auto
  857. basic_fields<Allocator>::
  858. new_element(field name,
  859. string_view sname, string_view value) ->
  860. element&
  861. {
  862. if(sname.size() + 2 >
  863. (std::numeric_limits<off_t>::max)())
  864. BHO_THROW_EXCEPTION(std::length_error{
  865. "field name too large"});
  866. if(value.size() + 2 >
  867. (std::numeric_limits<off_t>::max)())
  868. BHO_THROW_EXCEPTION(std::length_error{
  869. "field value too large"});
  870. value = detail::trim(value);
  871. std::uint16_t const off =
  872. static_cast<off_t>(sname.size() + 2);
  873. std::uint16_t const len =
  874. static_cast<off_t>(value.size());
  875. auto a = rebind_type{this->get()};
  876. auto const p = alloc_traits::allocate(a,
  877. (sizeof(element) + off + len + 2 + sizeof(align_type) - 1) /
  878. sizeof(align_type));
  879. return *(::new(p) element(name, sname, value));
  880. }
  881. template<class Allocator>
  882. void
  883. basic_fields<Allocator>::
  884. delete_element(element& e)
  885. {
  886. auto a = rebind_type{this->get()};
  887. auto const n =
  888. (sizeof(element) + e.off_ + e.len_ + 2 + sizeof(align_type) - 1) /
  889. sizeof(align_type);
  890. e.~element();
  891. alloc_traits::deallocate(a,
  892. reinterpret_cast<align_type*>(&e), n);
  893. }
  894. template<class Allocator>
  895. void
  896. basic_fields<Allocator>::
  897. set_element(element& e)
  898. {
  899. auto it = set_.lower_bound(
  900. e.name_string(), key_compare{});
  901. if(it == set_.end() || ! beast::iequals(
  902. e.name_string(), it->name_string()))
  903. {
  904. set_.insert_before(it, e);
  905. list_.push_back(e);
  906. return;
  907. }
  908. for(;;)
  909. {
  910. auto next = it;
  911. ++next;
  912. set_.erase(it);
  913. list_.erase(list_.iterator_to(*it));
  914. delete_element(*it);
  915. it = next;
  916. if(it == set_.end() ||
  917. ! beast::iequals(e.name_string(), it->name_string()))
  918. break;
  919. }
  920. set_.insert_before(it, e);
  921. list_.push_back(e);
  922. }
  923. template<class Allocator>
  924. void
  925. basic_fields<Allocator>::
  926. realloc_string(string_view& dest, string_view s)
  927. {
  928. if(dest.empty() && s.empty())
  929. return;
  930. auto a = typename beast::detail::allocator_traits<
  931. Allocator>::template rebind_alloc<
  932. char>(this->get());
  933. char* p = nullptr;
  934. if(! s.empty())
  935. {
  936. p = a.allocate(s.size());
  937. s.copy(p, s.size());
  938. }
  939. if(! dest.empty())
  940. a.deallocate(const_cast<char*>(
  941. dest.data()), dest.size());
  942. if(p)
  943. dest = {p, s.size()};
  944. else
  945. dest = {};
  946. }
  947. template<class Allocator>
  948. void
  949. basic_fields<Allocator>::
  950. realloc_target(
  951. string_view& dest, string_view s)
  952. {
  953. // The target string are stored with an
  954. // extra space at the beginning to help
  955. // the writer class.
  956. if(dest.empty() && s.empty())
  957. return;
  958. auto a = typename beast::detail::allocator_traits<
  959. Allocator>::template rebind_alloc<
  960. char>(this->get());
  961. char* p = nullptr;
  962. if(! s.empty())
  963. {
  964. p = a.allocate(1 + s.size());
  965. p[0] = ' ';
  966. s.copy(p + 1, s.size());
  967. }
  968. if(! dest.empty())
  969. a.deallocate(const_cast<char*>(
  970. dest.data()), dest.size());
  971. if(p)
  972. dest = {p, 1 + s.size()};
  973. else
  974. dest = {};
  975. }
  976. template<class Allocator>
  977. template<class OtherAlloc>
  978. void
  979. basic_fields<Allocator>::
  980. copy_all(basic_fields<OtherAlloc> const& other)
  981. {
  982. for(auto const& e : other.list_)
  983. insert(e.name(), e.name_string(), e.value());
  984. realloc_string(method_, other.method_);
  985. realloc_string(target_or_reason_,
  986. other.target_or_reason_);
  987. }
  988. template<class Allocator>
  989. void
  990. basic_fields<Allocator>::
  991. clear_all()
  992. {
  993. clear();
  994. realloc_string(method_, {});
  995. realloc_string(target_or_reason_, {});
  996. }
  997. template<class Allocator>
  998. void
  999. basic_fields<Allocator>::
  1000. delete_list()
  1001. {
  1002. for(auto it = list_.begin(); it != list_.end();)
  1003. delete_element(*it++);
  1004. }
  1005. //------------------------------------------------------------------------------
  1006. template<class Allocator>
  1007. inline
  1008. void
  1009. basic_fields<Allocator>::
  1010. move_assign(basic_fields& other, std::true_type)
  1011. {
  1012. clear_all();
  1013. set_ = std::move(other.set_);
  1014. list_ = std::move(other.list_);
  1015. method_ = other.method_;
  1016. target_or_reason_ = other.target_or_reason_;
  1017. other.method_ = {};
  1018. other.target_or_reason_ = {};
  1019. this->get() = other.get();
  1020. }
  1021. template<class Allocator>
  1022. inline
  1023. void
  1024. basic_fields<Allocator>::
  1025. move_assign(basic_fields& other, std::false_type)
  1026. {
  1027. clear_all();
  1028. if(this->get() != other.get())
  1029. {
  1030. copy_all(other);
  1031. }
  1032. else
  1033. {
  1034. set_ = std::move(other.set_);
  1035. list_ = std::move(other.list_);
  1036. method_ = other.method_;
  1037. target_or_reason_ = other.target_or_reason_;
  1038. other.method_ = {};
  1039. other.target_or_reason_ = {};
  1040. }
  1041. }
  1042. template<class Allocator>
  1043. inline
  1044. void
  1045. basic_fields<Allocator>::
  1046. copy_assign(basic_fields const& other, std::true_type)
  1047. {
  1048. clear_all();
  1049. this->get() = other.get();
  1050. copy_all(other);
  1051. }
  1052. template<class Allocator>
  1053. inline
  1054. void
  1055. basic_fields<Allocator>::
  1056. copy_assign(basic_fields const& other, std::false_type)
  1057. {
  1058. clear_all();
  1059. copy_all(other);
  1060. }
  1061. template<class Allocator>
  1062. inline
  1063. void
  1064. basic_fields<Allocator>::
  1065. swap(basic_fields& other, std::true_type)
  1066. {
  1067. using std::swap;
  1068. swap(this->get(), other.get());
  1069. swap(set_, other.set_);
  1070. swap(list_, other.list_);
  1071. swap(method_, other.method_);
  1072. swap(target_or_reason_, other.target_or_reason_);
  1073. }
  1074. template<class Allocator>
  1075. inline
  1076. void
  1077. basic_fields<Allocator>::
  1078. swap(basic_fields& other, std::false_type)
  1079. {
  1080. BHO_ASSERT(this->get() == other.get());
  1081. using std::swap;
  1082. swap(set_, other.set_);
  1083. swap(list_, other.list_);
  1084. swap(method_, other.method_);
  1085. swap(target_or_reason_, other.target_or_reason_);
  1086. }
  1087. } // http
  1088. } // beast
  1089. } // bho
  1090. #ifdef BEAST_HEADER_ONLY
  1091. #include <asio2/bho/beast/http/impl/fields.ipp>
  1092. #endif
  1093. #endif