basic_parser.ipp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. //
  2. // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/beast
  8. //
  9. #ifndef BOOST_BEAST_HTTP_IMPL_BASIC_PARSER_IPP
  10. #define BOOST_BEAST_HTTP_IMPL_BASIC_PARSER_IPP
  11. #include <boost/beast/core/static_string.hpp>
  12. #include <boost/beast/core/type_traits.hpp>
  13. #include <boost/beast/core/detail/clamp.hpp>
  14. #include <boost/beast/core/detail/config.hpp>
  15. #include <boost/beast/http/error.hpp>
  16. #include <boost/beast/http/rfc7230.hpp>
  17. #include <boost/asio/buffer.hpp>
  18. #include <boost/make_unique.hpp>
  19. #include <algorithm>
  20. #include <utility>
  21. namespace boost {
  22. namespace beast {
  23. namespace http {
  24. template<bool isRequest, class Derived>
  25. template<class OtherDerived>
  26. basic_parser<isRequest, Derived>::
  27. basic_parser(basic_parser<
  28. isRequest, OtherDerived>&& other)
  29. : body_limit_(other.body_limit_)
  30. , len_(other.len_)
  31. , buf_(std::move(other.buf_))
  32. , buf_len_(other.buf_len_)
  33. , skip_(other.skip_)
  34. , header_limit_(other.header_limit_)
  35. , status_(other.status_)
  36. , state_(other.state_)
  37. , f_(other.f_)
  38. {
  39. }
  40. template<bool isRequest, class Derived>
  41. bool
  42. basic_parser<isRequest, Derived>::
  43. keep_alive() const
  44. {
  45. BOOST_ASSERT(is_header_done());
  46. if(f_ & flagHTTP11)
  47. {
  48. if(f_ & flagConnectionClose)
  49. return false;
  50. }
  51. else
  52. {
  53. if(! (f_ & flagConnectionKeepAlive))
  54. return false;
  55. }
  56. return (f_ & flagNeedEOF) == 0;
  57. }
  58. template<bool isRequest, class Derived>
  59. boost::optional<std::uint64_t>
  60. basic_parser<isRequest, Derived>::
  61. content_length() const
  62. {
  63. BOOST_ASSERT(is_header_done());
  64. if(! (f_ & flagContentLength))
  65. return boost::none;
  66. return len_;
  67. }
  68. template<bool isRequest, class Derived>
  69. void
  70. basic_parser<isRequest, Derived>::
  71. skip(bool v)
  72. {
  73. BOOST_ASSERT(! got_some());
  74. if(v)
  75. f_ |= flagSkipBody;
  76. else
  77. f_ &= ~flagSkipBody;
  78. }
  79. template<bool isRequest, class Derived>
  80. template<class ConstBufferSequence>
  81. std::size_t
  82. basic_parser<isRequest, Derived>::
  83. put(ConstBufferSequence const& buffers,
  84. error_code& ec)
  85. {
  86. static_assert(boost::asio::is_const_buffer_sequence<
  87. ConstBufferSequence>::value,
  88. "ConstBufferSequence requirements not met");
  89. using boost::asio::buffer_copy;
  90. using boost::asio::buffer_size;
  91. auto const p = boost::asio::buffer_sequence_begin(buffers);
  92. auto const last = boost::asio::buffer_sequence_end(buffers);
  93. if(p == last)
  94. {
  95. ec.assign(0, ec.category());
  96. return 0;
  97. }
  98. if(std::next(p) == last)
  99. {
  100. // single buffer
  101. return put(boost::asio::const_buffer(*p), ec);
  102. }
  103. auto const size = buffer_size(buffers);
  104. if(size <= max_stack_buffer)
  105. return put_from_stack(size, buffers, ec);
  106. if(size > buf_len_)
  107. {
  108. // reallocate
  109. buf_ = boost::make_unique_noinit<char[]>(size);
  110. buf_len_ = size;
  111. }
  112. // flatten
  113. buffer_copy(boost::asio::buffer(
  114. buf_.get(), buf_len_), buffers);
  115. return put(boost::asio::const_buffer{
  116. buf_.get(), buf_len_}, ec);
  117. }
  118. template<bool isRequest, class Derived>
  119. std::size_t
  120. basic_parser<isRequest, Derived>::
  121. put(boost::asio::const_buffer const& buffer,
  122. error_code& ec)
  123. {
  124. BOOST_ASSERT(state_ != state::complete);
  125. using boost::asio::buffer_size;
  126. auto p = static_cast<char const*>(buffer.data());
  127. auto n = buffer.size();
  128. auto const p0 = p;
  129. auto const p1 = p0 + n;
  130. ec.assign(0, ec.category());
  131. loop:
  132. switch(state_)
  133. {
  134. case state::nothing_yet:
  135. if(n == 0)
  136. {
  137. ec = error::need_more;
  138. return 0;
  139. }
  140. state_ = state::start_line;
  141. BOOST_FALLTHROUGH;
  142. case state::start_line:
  143. {
  144. maybe_need_more(p, n, ec);
  145. if(ec)
  146. goto done;
  147. parse_start_line(p, p + (std::min<std::size_t>)(
  148. header_limit_, n), ec, is_request{});
  149. if(ec)
  150. {
  151. if(ec == error::need_more)
  152. {
  153. if(n >= header_limit_)
  154. {
  155. ec = error::header_limit;
  156. goto done;
  157. }
  158. if(p + 3 <= p1)
  159. skip_ = static_cast<
  160. std::size_t>(p1 - p - 3);
  161. }
  162. goto done;
  163. }
  164. BOOST_ASSERT(! is_done());
  165. n = static_cast<std::size_t>(p1 - p);
  166. if(p >= p1)
  167. {
  168. ec = error::need_more;
  169. goto done;
  170. }
  171. BOOST_FALLTHROUGH;
  172. }
  173. case state::fields:
  174. maybe_need_more(p, n, ec);
  175. if(ec)
  176. goto done;
  177. parse_fields(p, p + (std::min<std::size_t>)(
  178. header_limit_, n), ec);
  179. if(ec)
  180. {
  181. if(ec == error::need_more)
  182. {
  183. if(n >= header_limit_)
  184. {
  185. ec = error::header_limit;
  186. goto done;
  187. }
  188. if(p + 3 <= p1)
  189. skip_ = static_cast<
  190. std::size_t>(p1 - p - 3);
  191. }
  192. goto done;
  193. }
  194. finish_header(ec, is_request{});
  195. break;
  196. case state::body0:
  197. BOOST_ASSERT(! skip_);
  198. impl().on_body_init_impl(content_length(), ec);
  199. if(ec)
  200. goto done;
  201. state_ = state::body;
  202. BOOST_FALLTHROUGH;
  203. case state::body:
  204. BOOST_ASSERT(! skip_);
  205. parse_body(p, n, ec);
  206. if(ec)
  207. goto done;
  208. break;
  209. case state::body_to_eof0:
  210. BOOST_ASSERT(! skip_);
  211. impl().on_body_init_impl(content_length(), ec);
  212. if(ec)
  213. goto done;
  214. state_ = state::body_to_eof;
  215. BOOST_FALLTHROUGH;
  216. case state::body_to_eof:
  217. BOOST_ASSERT(! skip_);
  218. parse_body_to_eof(p, n, ec);
  219. if(ec)
  220. goto done;
  221. break;
  222. case state::chunk_header0:
  223. impl().on_body_init_impl(content_length(), ec);
  224. if(ec)
  225. goto done;
  226. state_ = state::chunk_header;
  227. BOOST_FALLTHROUGH;
  228. case state::chunk_header:
  229. parse_chunk_header(p, n, ec);
  230. if(ec)
  231. goto done;
  232. break;
  233. case state::chunk_body:
  234. parse_chunk_body(p, n, ec);
  235. if(ec)
  236. goto done;
  237. break;
  238. case state::complete:
  239. ec.assign(0, ec.category());
  240. goto done;
  241. }
  242. if(p < p1 && ! is_done() && eager())
  243. {
  244. n = static_cast<std::size_t>(p1 - p);
  245. goto loop;
  246. }
  247. done:
  248. return static_cast<std::size_t>(p - p0);
  249. }
  250. template<bool isRequest, class Derived>
  251. void
  252. basic_parser<isRequest, Derived>::
  253. put_eof(error_code& ec)
  254. {
  255. BOOST_ASSERT(got_some());
  256. if( state_ == state::start_line ||
  257. state_ == state::fields)
  258. {
  259. ec = error::partial_message;
  260. return;
  261. }
  262. if(f_ & (flagContentLength | flagChunked))
  263. {
  264. if(state_ != state::complete)
  265. {
  266. ec = error::partial_message;
  267. return;
  268. }
  269. ec.assign(0, ec.category());
  270. return;
  271. }
  272. impl().on_finish_impl(ec);
  273. if(ec)
  274. return;
  275. state_ = state::complete;
  276. }
  277. template<bool isRequest, class Derived>
  278. template<class ConstBufferSequence>
  279. std::size_t
  280. basic_parser<isRequest, Derived>::
  281. put_from_stack(std::size_t size,
  282. ConstBufferSequence const& buffers,
  283. error_code& ec)
  284. {
  285. char buf[max_stack_buffer];
  286. using boost::asio::buffer;
  287. using boost::asio::buffer_copy;
  288. buffer_copy(buffer(buf, sizeof(buf)), buffers);
  289. return put(boost::asio::const_buffer{
  290. buf, size}, ec);
  291. }
  292. template<bool isRequest, class Derived>
  293. inline
  294. void
  295. basic_parser<isRequest, Derived>::
  296. maybe_need_more(
  297. char const* p, std::size_t n,
  298. error_code& ec)
  299. {
  300. if(skip_ == 0)
  301. return;
  302. if( n > header_limit_)
  303. n = header_limit_;
  304. if(n < skip_ + 4)
  305. {
  306. ec = error::need_more;
  307. return;
  308. }
  309. auto const term =
  310. find_eom(p + skip_, p + n);
  311. if(! term)
  312. {
  313. skip_ = n - 3;
  314. if(skip_ + 4 > header_limit_)
  315. {
  316. ec = error::header_limit;
  317. return;
  318. }
  319. ec = error::need_more;
  320. return;
  321. }
  322. skip_ = 0;
  323. }
  324. template<bool isRequest, class Derived>
  325. inline
  326. void
  327. basic_parser<isRequest, Derived>::
  328. parse_start_line(
  329. char const*& in, char const* last,
  330. error_code& ec, std::true_type)
  331. {
  332. /*
  333. request-line = method SP request-target SP HTTP-version CRLF
  334. method = token
  335. */
  336. auto p = in;
  337. string_view method;
  338. parse_method(p, last, method, ec);
  339. if(ec)
  340. return;
  341. string_view target;
  342. parse_target(p, last, target, ec);
  343. if(ec)
  344. return;
  345. int version = 0;
  346. parse_version(p, last, version, ec);
  347. if(ec)
  348. return;
  349. if(version < 10 || version > 11)
  350. {
  351. ec = error::bad_version;
  352. return;
  353. }
  354. if(p + 2 > last)
  355. {
  356. ec = error::need_more;
  357. return;
  358. }
  359. if(p[0] != '\r' || p[1] != '\n')
  360. {
  361. ec = error::bad_version;
  362. return;
  363. }
  364. p += 2;
  365. if(version >= 11)
  366. f_ |= flagHTTP11;
  367. impl().on_request_impl(string_to_verb(method),
  368. method, target, version, ec);
  369. if(ec)
  370. return;
  371. in = p;
  372. state_ = state::fields;
  373. }
  374. template<bool isRequest, class Derived>
  375. inline
  376. void
  377. basic_parser<isRequest, Derived>::
  378. parse_start_line(
  379. char const*& in, char const* last,
  380. error_code& ec, std::false_type)
  381. {
  382. /*
  383. status-line = HTTP-version SP status-code SP reason-phrase CRLF
  384. status-code = 3*DIGIT
  385. reason-phrase = *( HTAB / SP / VCHAR / obs-text )
  386. */
  387. auto p = in;
  388. int version = 0;
  389. parse_version(p, last, version, ec);
  390. if(ec)
  391. return;
  392. if(version < 10 || version > 11)
  393. {
  394. ec = error::bad_version;
  395. return;
  396. }
  397. // SP
  398. if(p + 1 > last)
  399. {
  400. ec = error::need_more;
  401. return;
  402. }
  403. if(*p++ != ' ')
  404. {
  405. ec = error::bad_version;
  406. return;
  407. }
  408. parse_status(p, last, status_, ec);
  409. if(ec)
  410. return;
  411. // parse reason CRLF
  412. string_view reason;
  413. parse_reason(p, last, reason, ec);
  414. if(ec)
  415. return;
  416. if(version >= 11)
  417. f_ |= flagHTTP11;
  418. impl().on_response_impl(
  419. status_, reason, version, ec);
  420. if(ec)
  421. return;
  422. in = p;
  423. state_ = state::fields;
  424. }
  425. template<bool isRequest, class Derived>
  426. void
  427. basic_parser<isRequest, Derived>::
  428. parse_fields(char const*& in,
  429. char const* last, error_code& ec)
  430. {
  431. string_view name;
  432. string_view value;
  433. // https://stackoverflow.com/questions/686217/maximum-on-http-header-values
  434. static_string<max_obs_fold> buf;
  435. auto p = in;
  436. for(;;)
  437. {
  438. if(p + 2 > last)
  439. {
  440. ec = error::need_more;
  441. return;
  442. }
  443. if(p[0] == '\r')
  444. {
  445. if(p[1] != '\n')
  446. ec = error::bad_line_ending;
  447. in = p + 2;
  448. return;
  449. }
  450. parse_field(p, last, name, value, buf, ec);
  451. if(ec)
  452. return;
  453. auto const f = string_to_field(name);
  454. do_field(f, value, ec);
  455. if(ec)
  456. return;
  457. impl().on_field_impl(f, name, value, ec);
  458. if(ec)
  459. return;
  460. in = p;
  461. }
  462. }
  463. template<bool isRequest, class Derived>
  464. inline
  465. void
  466. basic_parser<isRequest, Derived>::
  467. finish_header(error_code& ec, std::true_type)
  468. {
  469. // RFC 7230 section 3.3
  470. // https://tools.ietf.org/html/rfc7230#section-3.3
  471. if(f_ & flagSkipBody)
  472. {
  473. state_ = state::complete;
  474. }
  475. else if(f_ & flagContentLength)
  476. {
  477. if(len_ > body_limit_)
  478. {
  479. ec = error::body_limit;
  480. return;
  481. }
  482. if(len_ > 0)
  483. {
  484. f_ |= flagHasBody;
  485. state_ = state::body0;
  486. }
  487. else
  488. {
  489. state_ = state::complete;
  490. }
  491. }
  492. else if(f_ & flagChunked)
  493. {
  494. f_ |= flagHasBody;
  495. state_ = state::chunk_header0;
  496. }
  497. else
  498. {
  499. len_ = 0;
  500. state_ = state::complete;
  501. }
  502. impl().on_header_impl(ec);
  503. if(ec)
  504. return;
  505. if(state_ == state::complete)
  506. {
  507. impl().on_finish_impl(ec);
  508. if(ec)
  509. return;
  510. }
  511. }
  512. template<bool isRequest, class Derived>
  513. inline
  514. void
  515. basic_parser<isRequest, Derived>::
  516. finish_header(error_code& ec, std::false_type)
  517. {
  518. // RFC 7230 section 3.3
  519. // https://tools.ietf.org/html/rfc7230#section-3.3
  520. if( (f_ & flagSkipBody) || // e.g. response to a HEAD request
  521. status_ / 100 == 1 || // 1xx e.g. Continue
  522. status_ == 204 || // No Content
  523. status_ == 304) // Not Modified
  524. {
  525. // VFALCO Content-Length may be present, but we
  526. // treat the message as not having a body.
  527. // https://github.com/boostorg/beast/issues/692
  528. state_ = state::complete;
  529. }
  530. else if(f_ & flagContentLength)
  531. {
  532. if(len_ > body_limit_)
  533. {
  534. ec = error::body_limit;
  535. return;
  536. }
  537. if(len_ > 0)
  538. {
  539. f_ |= flagHasBody;
  540. state_ = state::body0;
  541. }
  542. else
  543. {
  544. state_ = state::complete;
  545. }
  546. }
  547. else if(f_ & flagChunked)
  548. {
  549. f_ |= flagHasBody;
  550. state_ = state::chunk_header0;
  551. }
  552. else
  553. {
  554. f_ |= flagHasBody;
  555. f_ |= flagNeedEOF;
  556. state_ = state::body_to_eof0;
  557. }
  558. impl().on_header_impl(ec);
  559. if(ec)
  560. return;
  561. if(state_ == state::complete)
  562. {
  563. impl().on_finish_impl(ec);
  564. if(ec)
  565. return;
  566. }
  567. }
  568. template<bool isRequest, class Derived>
  569. inline
  570. void
  571. basic_parser<isRequest, Derived>::
  572. parse_body(char const*& p,
  573. std::size_t n, error_code& ec)
  574. {
  575. n = impl().on_body_impl(string_view{p,
  576. beast::detail::clamp(len_, n)}, ec);
  577. p += n;
  578. len_ -= n;
  579. if(ec)
  580. return;
  581. if(len_ > 0)
  582. return;
  583. impl().on_finish_impl(ec);
  584. if(ec)
  585. return;
  586. state_ = state::complete;
  587. }
  588. template<bool isRequest, class Derived>
  589. inline
  590. void
  591. basic_parser<isRequest, Derived>::
  592. parse_body_to_eof(char const*& p,
  593. std::size_t n, error_code& ec)
  594. {
  595. if(n > body_limit_)
  596. {
  597. ec = error::body_limit;
  598. return;
  599. }
  600. body_limit_ = body_limit_ - n;
  601. n = impl().on_body_impl(string_view{p, n}, ec);
  602. p += n;
  603. if(ec)
  604. return;
  605. }
  606. template<bool isRequest, class Derived>
  607. void
  608. basic_parser<isRequest, Derived>::
  609. parse_chunk_header(char const*& p0,
  610. std::size_t n, error_code& ec)
  611. {
  612. /*
  613. chunked-body = *chunk last-chunk trailer-part CRLF
  614. chunk = chunk-size [ chunk-ext ] CRLF chunk-data CRLF
  615. last-chunk = 1*("0") [ chunk-ext ] CRLF
  616. trailer-part = *( header-field CRLF )
  617. chunk-size = 1*HEXDIG
  618. chunk-data = 1*OCTET ; a sequence of chunk-size octets
  619. chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
  620. chunk-ext-name = token
  621. chunk-ext-val = token / quoted-string
  622. */
  623. auto p = p0;
  624. auto const pend = p + n;
  625. char const* eol;
  626. if(! (f_ & flagFinalChunk))
  627. {
  628. if(n < skip_ + 2)
  629. {
  630. ec = error::need_more;
  631. return;
  632. }
  633. if(f_ & flagExpectCRLF)
  634. {
  635. // Treat the last CRLF in a chunk as
  636. // part of the next chunk, so p can
  637. // be parsed in one call instead of two.
  638. if(! parse_crlf(p))
  639. {
  640. ec = error::bad_chunk;
  641. return;
  642. }
  643. }
  644. eol = find_eol(p0 + skip_, pend, ec);
  645. if(ec)
  646. return;
  647. if(! eol)
  648. {
  649. ec = error::need_more;
  650. skip_ = n - 1;
  651. return;
  652. }
  653. skip_ = static_cast<
  654. std::size_t>(eol - 2 - p0);
  655. std::uint64_t size;
  656. if(! parse_hex(p, size))
  657. {
  658. ec = error::bad_chunk;
  659. return;
  660. }
  661. if(size != 0)
  662. {
  663. if(size > body_limit_)
  664. {
  665. ec = error::body_limit;
  666. return;
  667. }
  668. body_limit_ -= size;
  669. auto const start = p;
  670. parse_chunk_extensions(p, pend, ec);
  671. if(ec)
  672. return;
  673. if(p != eol -2 )
  674. {
  675. ec = error::bad_chunk_extension;
  676. return;
  677. }
  678. auto const ext = make_string(start, p);
  679. impl().on_chunk_header_impl(size, ext, ec);
  680. if(ec)
  681. return;
  682. len_ = size;
  683. skip_ = 2;
  684. p0 = eol;
  685. f_ |= flagExpectCRLF;
  686. state_ = state::chunk_body;
  687. return;
  688. }
  689. f_ |= flagFinalChunk;
  690. }
  691. else
  692. {
  693. BOOST_ASSERT(n >= 5);
  694. if(f_ & flagExpectCRLF)
  695. BOOST_VERIFY(parse_crlf(p));
  696. std::uint64_t size;
  697. BOOST_VERIFY(parse_hex(p, size));
  698. eol = find_eol(p, pend, ec);
  699. BOOST_ASSERT(! ec);
  700. }
  701. auto eom = find_eom(p0 + skip_, pend);
  702. if(! eom)
  703. {
  704. BOOST_ASSERT(n >= 3);
  705. skip_ = n - 3;
  706. ec = error::need_more;
  707. return;
  708. }
  709. auto const start = p;
  710. parse_chunk_extensions(p, pend, ec);
  711. if(ec)
  712. return;
  713. if(p != eol - 2)
  714. {
  715. ec = error::bad_chunk_extension;
  716. return;
  717. }
  718. auto const ext = make_string(start, p);
  719. impl().on_chunk_header_impl(0, ext, ec);
  720. if(ec)
  721. return;
  722. p = eol;
  723. parse_fields(p, eom, ec);
  724. if(ec)
  725. return;
  726. BOOST_ASSERT(p == eom);
  727. p0 = eom;
  728. impl().on_finish_impl(ec);
  729. if(ec)
  730. return;
  731. state_ = state::complete;
  732. }
  733. template<bool isRequest, class Derived>
  734. inline
  735. void
  736. basic_parser<isRequest, Derived>::
  737. parse_chunk_body(char const*& p,
  738. std::size_t n, error_code& ec)
  739. {
  740. n = impl().on_chunk_body_impl(
  741. len_, string_view{p,
  742. beast::detail::clamp(len_, n)}, ec);
  743. p += n;
  744. len_ -= n;
  745. if(len_ == 0)
  746. state_ = state::chunk_header;
  747. }
  748. template<bool isRequest, class Derived>
  749. void
  750. basic_parser<isRequest, Derived>::
  751. do_field(field f,
  752. string_view value, error_code& ec)
  753. {
  754. // Connection
  755. if(f == field::connection ||
  756. f == field::proxy_connection)
  757. {
  758. auto const list = opt_token_list{value};
  759. if(! validate_list(list))
  760. {
  761. // VFALCO Should this be a field specific error?
  762. ec = error::bad_value;
  763. return;
  764. }
  765. for(auto const& s : list)
  766. {
  767. if(iequals({"close", 5}, s))
  768. {
  769. f_ |= flagConnectionClose;
  770. continue;
  771. }
  772. if(iequals({"keep-alive", 10}, s))
  773. {
  774. f_ |= flagConnectionKeepAlive;
  775. continue;
  776. }
  777. if(iequals({"upgrade", 7}, s))
  778. {
  779. f_ |= flagConnectionUpgrade;
  780. continue;
  781. }
  782. }
  783. ec.assign(0, ec.category());
  784. return;
  785. }
  786. // Content-Length
  787. if(f == field::content_length)
  788. {
  789. if(f_ & flagContentLength)
  790. {
  791. // duplicate
  792. ec = error::bad_content_length;
  793. return;
  794. }
  795. if(f_ & flagChunked)
  796. {
  797. // conflicting field
  798. ec = error::bad_content_length;
  799. return;
  800. }
  801. std::uint64_t v;
  802. if(! parse_dec(
  803. value.begin(), value.end(), v))
  804. {
  805. ec = error::bad_content_length;
  806. return;
  807. }
  808. ec.assign(0, ec.category());
  809. len_ = v;
  810. f_ |= flagContentLength;
  811. return;
  812. }
  813. // Transfer-Encoding
  814. if(f == field::transfer_encoding)
  815. {
  816. if(f_ & flagChunked)
  817. {
  818. // duplicate
  819. ec = error::bad_transfer_encoding;
  820. return;
  821. }
  822. if(f_ & flagContentLength)
  823. {
  824. // conflicting field
  825. ec = error::bad_transfer_encoding;
  826. return;
  827. }
  828. ec.assign(0, ec.category());
  829. auto const v = token_list{value};
  830. auto const p = std::find_if(v.begin(), v.end(),
  831. [&](typename token_list::value_type const& s)
  832. {
  833. return iequals({"chunked", 7}, s);
  834. });
  835. if(p == v.end())
  836. return;
  837. if(std::next(p) != v.end())
  838. return;
  839. len_ = 0;
  840. f_ |= flagChunked;
  841. return;
  842. }
  843. // Upgrade
  844. if(f == field::upgrade)
  845. {
  846. ec.assign(0, ec.category());
  847. f_ |= flagUpgrade;
  848. return;
  849. }
  850. ec.assign(0, ec.category());
  851. }
  852. } // http
  853. } // beast
  854. } // boost
  855. #endif