fields.hpp 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268
  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 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 value)
  485. {
  486. insert(
  487. string_to_field(sname), sname, value);
  488. }
  489. template<class Allocator>
  490. void
  491. basic_fields<Allocator>::
  492. insert(
  493. field name,
  494. string_view sname,
  495. string_view value,
  496. error_code& ec)
  497. {
  498. ec = {};
  499. auto* e = try_create_new_element(name, sname, value, ec);
  500. if(ec.failed())
  501. return;
  502. insert_element(*e);
  503. }
  504. template<class Allocator>
  505. void
  506. basic_fields<Allocator>::
  507. insert(field name,
  508. string_view sname, string_view value)
  509. {
  510. insert_element(
  511. new_element(name, sname, value));
  512. }
  513. template<class Allocator>
  514. void
  515. basic_fields<Allocator>::
  516. set(field name, string_view value)
  517. {
  518. BOOST_ASSERT(name != field::unknown);
  519. set_element(
  520. new_element(name, to_string(name), value));
  521. }
  522. template<class Allocator>
  523. void
  524. basic_fields<Allocator>::
  525. set(string_view sname, string_view value)
  526. {
  527. set_element(new_element(
  528. string_to_field(sname), sname, value));
  529. }
  530. template<class Allocator>
  531. auto
  532. basic_fields<Allocator>::
  533. erase(const_iterator pos) ->
  534. const_iterator
  535. {
  536. auto next = pos;
  537. auto& e = *next++;
  538. set_.erase(set_.iterator_to(e));
  539. list_.erase(pos);
  540. delete_element(const_cast<element&>(e));
  541. return next;
  542. }
  543. template<class Allocator>
  544. std::size_t
  545. basic_fields<Allocator>::
  546. erase(field name)
  547. {
  548. BOOST_ASSERT(name != field::unknown);
  549. return erase(to_string(name));
  550. }
  551. template<class Allocator>
  552. std::size_t
  553. basic_fields<Allocator>::
  554. erase(string_view name)
  555. {
  556. std::size_t n =0;
  557. set_.erase_and_dispose(name, key_compare{},
  558. [&](element* e)
  559. {
  560. ++n;
  561. list_.erase(list_.iterator_to(*e));
  562. delete_element(*e);
  563. });
  564. return n;
  565. }
  566. template<class Allocator>
  567. void
  568. basic_fields<Allocator>::
  569. swap(basic_fields<Allocator>& other)
  570. {
  571. swap(other, pocs{});
  572. }
  573. template<class Allocator>
  574. void
  575. swap(
  576. basic_fields<Allocator>& lhs,
  577. basic_fields<Allocator>& rhs)
  578. {
  579. lhs.swap(rhs);
  580. }
  581. //------------------------------------------------------------------------------
  582. //
  583. // Lookup
  584. //
  585. //------------------------------------------------------------------------------
  586. template<class Allocator>
  587. inline
  588. bool
  589. basic_fields<Allocator>::
  590. contains(field name) const
  591. {
  592. BOOST_ASSERT(name != field::unknown);
  593. return contains(to_string(name));
  594. }
  595. template<class Allocator>
  596. bool
  597. basic_fields<Allocator>::
  598. contains(string_view name) const
  599. {
  600. return find(name) != end();
  601. }
  602. template<class Allocator>
  603. inline
  604. std::size_t
  605. basic_fields<Allocator>::
  606. count(field name) const
  607. {
  608. BOOST_ASSERT(name != field::unknown);
  609. return count(to_string(name));
  610. }
  611. template<class Allocator>
  612. std::size_t
  613. basic_fields<Allocator>::
  614. count(string_view name) const
  615. {
  616. return set_.count(name, key_compare{});
  617. }
  618. template<class Allocator>
  619. inline
  620. auto
  621. basic_fields<Allocator>::
  622. find(field name) const ->
  623. const_iterator
  624. {
  625. BOOST_ASSERT(name != field::unknown);
  626. return find(to_string(name));
  627. }
  628. template<class Allocator>
  629. auto
  630. basic_fields<Allocator>::
  631. find(string_view name) const ->
  632. const_iterator
  633. {
  634. auto const it = set_.find(
  635. name, key_compare{});
  636. if(it == set_.end())
  637. return list_.end();
  638. return list_.iterator_to(*it);
  639. }
  640. template<class Allocator>
  641. inline
  642. auto
  643. basic_fields<Allocator>::
  644. equal_range(field name) const ->
  645. std::pair<const_iterator, const_iterator>
  646. {
  647. BOOST_ASSERT(name != field::unknown);
  648. return equal_range(to_string(name));
  649. }
  650. template<class Allocator>
  651. auto
  652. basic_fields<Allocator>::
  653. equal_range(string_view name) const ->
  654. std::pair<const_iterator, const_iterator>
  655. {
  656. auto result =
  657. set_.equal_range(name, key_compare{});
  658. if(result.first == result.second)
  659. return {list_.end(), list_.end()};
  660. return {
  661. list_.iterator_to(*result.first),
  662. ++list_.iterator_to(*(--result.second))};
  663. }
  664. //------------------------------------------------------------------------------
  665. namespace detail {
  666. struct iequals_predicate
  667. {
  668. bool
  669. operator()(string_view s) const
  670. {
  671. return beast::iequals(s, sv1) || beast::iequals(s, sv2);
  672. }
  673. string_view sv1;
  674. string_view sv2;
  675. };
  676. // Filter the last item in a token list
  677. BOOST_BEAST_DECL
  678. void
  679. filter_token_list_last(
  680. beast::detail::temporary_buffer& s,
  681. string_view value,
  682. iequals_predicate const& pred);
  683. BOOST_BEAST_DECL
  684. void
  685. keep_alive_impl(
  686. beast::detail::temporary_buffer& s, string_view value,
  687. unsigned version, bool keep_alive);
  688. } // detail
  689. //------------------------------------------------------------------------------
  690. // Fields
  691. template<class Allocator>
  692. inline
  693. string_view
  694. basic_fields<Allocator>::
  695. get_method_impl() const
  696. {
  697. return method_;
  698. }
  699. template<class Allocator>
  700. inline
  701. string_view
  702. basic_fields<Allocator>::
  703. get_target_impl() const
  704. {
  705. if(target_or_reason_.empty())
  706. return target_or_reason_;
  707. return {
  708. target_or_reason_.data() + 1,
  709. target_or_reason_.size() - 1};
  710. }
  711. template<class Allocator>
  712. inline
  713. string_view
  714. basic_fields<Allocator>::
  715. get_reason_impl() const
  716. {
  717. return target_or_reason_;
  718. }
  719. template<class Allocator>
  720. bool
  721. basic_fields<Allocator>::
  722. get_chunked_impl() const
  723. {
  724. auto const te = token_list{
  725. (*this)[field::transfer_encoding]};
  726. for(auto it = te.begin(); it != te.end();)
  727. {
  728. auto const next = std::next(it);
  729. if(next == te.end())
  730. return beast::iequals(*it, "chunked");
  731. it = next;
  732. }
  733. return false;
  734. }
  735. template<class Allocator>
  736. bool
  737. basic_fields<Allocator>::
  738. get_keep_alive_impl(unsigned version) const
  739. {
  740. auto const it = find(field::connection);
  741. if(version < 11)
  742. {
  743. if(it == end())
  744. return false;
  745. return token_list{
  746. it->value()}.exists("keep-alive");
  747. }
  748. if(it == end())
  749. return true;
  750. return ! token_list{
  751. it->value()}.exists("close");
  752. }
  753. template<class Allocator>
  754. bool
  755. basic_fields<Allocator>::
  756. has_content_length_impl() const
  757. {
  758. return contains(field::content_length);
  759. }
  760. template<class Allocator>
  761. inline
  762. void
  763. basic_fields<Allocator>::
  764. set_method_impl(string_view s)
  765. {
  766. realloc_string(method_, s);
  767. }
  768. template<class Allocator>
  769. inline
  770. void
  771. basic_fields<Allocator>::
  772. set_target_impl(string_view s)
  773. {
  774. realloc_target(
  775. target_or_reason_, s);
  776. }
  777. template<class Allocator>
  778. inline
  779. void
  780. basic_fields<Allocator>::
  781. set_reason_impl(string_view s)
  782. {
  783. realloc_string(
  784. target_or_reason_, s);
  785. }
  786. template<class Allocator>
  787. void
  788. basic_fields<Allocator>::
  789. set_chunked_impl(bool value)
  790. {
  791. beast::detail::temporary_buffer buf;
  792. auto it = find(field::transfer_encoding);
  793. if(value)
  794. {
  795. // append "chunked"
  796. if(it == end())
  797. {
  798. set(field::transfer_encoding, "chunked");
  799. return;
  800. }
  801. auto const te = token_list{it->value()};
  802. for(auto itt = te.begin();;)
  803. {
  804. auto const next = std::next(itt);
  805. if(next == te.end())
  806. {
  807. if(beast::iequals(*itt, "chunked"))
  808. return; // already set
  809. break;
  810. }
  811. itt = next;
  812. }
  813. buf.append(it->value(), ", chunked");
  814. set(field::transfer_encoding, buf.view());
  815. return;
  816. }
  817. // filter "chunked"
  818. if(it == end())
  819. return;
  820. detail::filter_token_list_last(buf, it->value(), {"chunked", {}});
  821. if(! buf.empty())
  822. set(field::transfer_encoding, buf.view());
  823. else
  824. erase(field::transfer_encoding);
  825. }
  826. template<class Allocator>
  827. void
  828. basic_fields<Allocator>::
  829. set_content_length_impl(
  830. boost::optional<std::uint64_t> const& value)
  831. {
  832. if(! value)
  833. erase(field::content_length);
  834. else
  835. {
  836. auto s = to_static_string(*value);
  837. set(field::content_length,
  838. to_string_view(s));
  839. }
  840. }
  841. template<class Allocator>
  842. void
  843. basic_fields<Allocator>::
  844. set_keep_alive_impl(
  845. unsigned version, bool keep_alive)
  846. {
  847. // VFALCO What about Proxy-Connection ?
  848. auto const value = (*this)[field::connection];
  849. beast::detail::temporary_buffer buf;
  850. detail::keep_alive_impl(buf, value, version, keep_alive);
  851. if(buf.empty())
  852. erase(field::connection);
  853. else
  854. set(field::connection, buf.view());
  855. }
  856. //------------------------------------------------------------------------------
  857. template<class Allocator>
  858. auto
  859. basic_fields<Allocator>::
  860. try_create_new_element(
  861. field name,
  862. string_view sname,
  863. string_view value,
  864. error_code& ec) -> element*
  865. {
  866. if(sname.size() > max_name_size)
  867. {
  868. BOOST_BEAST_ASSIGN_EC(ec, error::header_field_name_too_large);
  869. return nullptr;
  870. }
  871. if(value.size() > max_value_size)
  872. {
  873. BOOST_BEAST_ASSIGN_EC(ec, error::header_field_value_too_large);
  874. return nullptr;
  875. }
  876. value = detail::trim(value);
  877. std::uint16_t const off =
  878. static_cast<off_t>(sname.size() + 2);
  879. std::uint16_t const len =
  880. static_cast<off_t>(value.size());
  881. auto a = rebind_type{this->get()};
  882. auto const p = alloc_traits::allocate(a,
  883. (sizeof(element) + off + len + 2 + sizeof(align_type) - 1) /
  884. sizeof(align_type));
  885. return ::new(p) element(name, sname, value);
  886. }
  887. template<class Allocator>
  888. auto
  889. basic_fields<Allocator>::
  890. new_element(
  891. field name,
  892. string_view sname,
  893. string_view value) -> element&
  894. {
  895. error_code ec;
  896. auto* e = try_create_new_element(name, sname, value, ec);
  897. if(ec.failed())
  898. BOOST_THROW_EXCEPTION(system_error{ec});
  899. return *e;
  900. }
  901. template<class Allocator>
  902. void
  903. basic_fields<Allocator>::
  904. insert_element(element& e)
  905. {
  906. auto const before =
  907. set_.upper_bound(e.name_string(), key_compare{});
  908. if(before == set_.begin())
  909. {
  910. BOOST_ASSERT(! contains(e.name_string()));
  911. set_.insert_before(before, e);
  912. list_.push_back(e);
  913. return;
  914. }
  915. auto const last = std::prev(before);
  916. // VFALCO is it worth comparing `field name` first?
  917. if(! beast::iequals(e.name_string(), last->name_string()))
  918. {
  919. BOOST_ASSERT(! contains(e.name_string()));
  920. set_.insert_before(before, e);
  921. list_.push_back(e);
  922. return;
  923. }
  924. // keep duplicate fields together in the list
  925. set_.insert_before(before, e);
  926. list_.insert(++list_.iterator_to(*last), e);
  927. }
  928. template<class Allocator>
  929. void
  930. basic_fields<Allocator>::
  931. delete_element(element& e)
  932. {
  933. auto a = rebind_type{this->get()};
  934. auto const n =
  935. (sizeof(element) + e.off_ + e.len_ + 2 + sizeof(align_type) - 1) /
  936. sizeof(align_type);
  937. e.~element();
  938. alloc_traits::deallocate(a,
  939. reinterpret_cast<align_type*>(&e), n);
  940. }
  941. template<class Allocator>
  942. void
  943. basic_fields<Allocator>::
  944. set_element(element& e)
  945. {
  946. auto it = set_.lower_bound(
  947. e.name_string(), key_compare{});
  948. if(it == set_.end() || ! beast::iequals(
  949. e.name_string(), it->name_string()))
  950. {
  951. set_.insert_before(it, e);
  952. list_.push_back(e);
  953. return;
  954. }
  955. for(;;)
  956. {
  957. auto next = it;
  958. ++next;
  959. set_.erase(it);
  960. list_.erase(list_.iterator_to(*it));
  961. delete_element(*it);
  962. it = next;
  963. if(it == set_.end() ||
  964. ! beast::iequals(e.name_string(), it->name_string()))
  965. break;
  966. }
  967. set_.insert_before(it, e);
  968. list_.push_back(e);
  969. }
  970. template<class Allocator>
  971. void
  972. basic_fields<Allocator>::
  973. realloc_string(string_view& dest, string_view s)
  974. {
  975. if(dest.empty() && s.empty())
  976. return;
  977. auto a = typename beast::detail::allocator_traits<
  978. Allocator>::template rebind_alloc<
  979. char>(this->get());
  980. char* p = nullptr;
  981. if(! s.empty())
  982. {
  983. p = a.allocate(s.size());
  984. s.copy(p, s.size());
  985. }
  986. if(! dest.empty())
  987. a.deallocate(const_cast<char*>(
  988. dest.data()), dest.size());
  989. if(p)
  990. dest = {p, s.size()};
  991. else
  992. dest = {};
  993. }
  994. template<class Allocator>
  995. void
  996. basic_fields<Allocator>::
  997. realloc_target(
  998. string_view& dest, string_view s)
  999. {
  1000. // The target string are stored with an
  1001. // extra space at the beginning to help
  1002. // the writer class.
  1003. if(dest.empty() && s.empty())
  1004. return;
  1005. auto a = typename beast::detail::allocator_traits<
  1006. Allocator>::template rebind_alloc<
  1007. char>(this->get());
  1008. char* p = nullptr;
  1009. if(! s.empty())
  1010. {
  1011. p = a.allocate(1 + s.size());
  1012. p[0] = ' ';
  1013. s.copy(p + 1, s.size());
  1014. }
  1015. if(! dest.empty())
  1016. a.deallocate(const_cast<char*>(
  1017. dest.data()), dest.size());
  1018. if(p)
  1019. dest = {p, 1 + s.size()};
  1020. else
  1021. dest = {};
  1022. }
  1023. template<class Allocator>
  1024. template<class OtherAlloc>
  1025. void
  1026. basic_fields<Allocator>::
  1027. copy_all(basic_fields<OtherAlloc> const& other)
  1028. {
  1029. for(auto const& e : other.list_)
  1030. insert(e.name(), e.name_string(), e.value());
  1031. realloc_string(method_, other.method_);
  1032. realloc_string(target_or_reason_,
  1033. other.target_or_reason_);
  1034. }
  1035. template<class Allocator>
  1036. void
  1037. basic_fields<Allocator>::
  1038. clear_all()
  1039. {
  1040. clear();
  1041. realloc_string(method_, {});
  1042. realloc_string(target_or_reason_, {});
  1043. }
  1044. template<class Allocator>
  1045. void
  1046. basic_fields<Allocator>::
  1047. delete_list()
  1048. {
  1049. for(auto it = list_.begin(); it != list_.end();)
  1050. delete_element(*it++);
  1051. }
  1052. //------------------------------------------------------------------------------
  1053. template<class Allocator>
  1054. inline
  1055. void
  1056. basic_fields<Allocator>::
  1057. move_assign(basic_fields& other, std::true_type)
  1058. {
  1059. clear_all();
  1060. this->get() = std::move(other.get());
  1061. set_ = std::move(other.set_);
  1062. list_ = std::move(other.list_);
  1063. method_ = other.method_;
  1064. target_or_reason_ = other.target_or_reason_;
  1065. other.method_ = {};
  1066. other.target_or_reason_ = {};
  1067. }
  1068. template<class Allocator>
  1069. inline
  1070. void
  1071. basic_fields<Allocator>::
  1072. move_assign(basic_fields& other, std::false_type)
  1073. {
  1074. clear_all();
  1075. if(this->get() != other.get())
  1076. {
  1077. copy_all(other);
  1078. }
  1079. else
  1080. {
  1081. set_ = std::move(other.set_);
  1082. list_ = std::move(other.list_);
  1083. method_ = other.method_;
  1084. target_or_reason_ = other.target_or_reason_;
  1085. other.method_ = {};
  1086. other.target_or_reason_ = {};
  1087. }
  1088. }
  1089. template<class Allocator>
  1090. inline
  1091. void
  1092. basic_fields<Allocator>::
  1093. copy_assign(basic_fields const& other, std::true_type)
  1094. {
  1095. clear_all();
  1096. this->get() = other.get();
  1097. copy_all(other);
  1098. }
  1099. template<class Allocator>
  1100. inline
  1101. void
  1102. basic_fields<Allocator>::
  1103. copy_assign(basic_fields const& other, std::false_type)
  1104. {
  1105. clear_all();
  1106. copy_all(other);
  1107. }
  1108. template<class Allocator>
  1109. inline
  1110. void
  1111. basic_fields<Allocator>::
  1112. swap(basic_fields& other, std::true_type)
  1113. {
  1114. using std::swap;
  1115. swap(this->get(), other.get());
  1116. swap(set_, other.set_);
  1117. swap(list_, other.list_);
  1118. swap(method_, other.method_);
  1119. swap(target_or_reason_, other.target_or_reason_);
  1120. }
  1121. template<class Allocator>
  1122. inline
  1123. void
  1124. basic_fields<Allocator>::
  1125. swap(basic_fields& other, std::false_type)
  1126. {
  1127. BOOST_ASSERT(this->get() == other.get());
  1128. using std::swap;
  1129. swap(set_, other.set_);
  1130. swap(list_, other.list_);
  1131. swap(method_, other.method_);
  1132. swap(target_or_reason_, other.target_or_reason_);
  1133. }
  1134. } // http
  1135. } // beast
  1136. } // boost
  1137. #ifdef BOOST_BEAST_HEADER_ONLY
  1138. #include <boost/beast/http/impl/fields.ipp>
  1139. #endif
  1140. #endif