fields.ipp 32 KB

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