fields.hpp 27 KB

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