fields.hpp 26 KB

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