LCOV - code coverage report
Current view: top level - http_proto/impl - parser.ipp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 190 349 54.4 %
Date: 2023-03-01 04:48:12 Functions: 16 23 69.6 %

          Line data    Source code
       1             : //
       2             : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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/CPPAlliance/http_proto
       8             : //
       9             : 
      10             : #ifndef BOOST_HTTP_PROTO_IMPL_PARSER_IPP
      11             : #define BOOST_HTTP_PROTO_IMPL_PARSER_IPP
      12             : 
      13             : #include <boost/http_proto/parser.hpp>
      14             : #include <boost/http_proto/context.hpp>
      15             : #include <boost/http_proto/error.hpp>
      16             : #include <boost/http_proto/service/zlib_service.hpp>
      17             : #include <boost/http_proto/detail/except.hpp>
      18             : #include <boost/buffers/buffer_copy.hpp>
      19             : #include <boost/url/grammar/ci_string.hpp>
      20             : #include <boost/assert.hpp>
      21             : #include <memory>
      22             : 
      23             : namespace boost {
      24             : namespace http_proto {
      25             : 
      26             : //------------------------------------------------
      27             : /*
      28             : Buffer Usage
      29             : 
      30             : |                                               | begin
      31             : | H |   p   |                               | f | read headers
      32             : | H |   p   |                           | T | f | set T body
      33             : | H |   p   |                       | C | T | f | make codec C
      34             : | H |   p           |       b       | C | T | f | decode p into b
      35             : | H |       p       |       b       | C | T | f | read/parse loop
      36             : | H |                                   | T | f | destroy codec
      37             : | H |                                   | T | f | finished
      38             : 
      39             : H   headers
      40             : C   codec
      41             : T   body
      42             : f   table
      43             : p   partial payload
      44             : b   body data
      45             : 
      46             : - We can compact the headers:
      47             :     move the table downwards to
      48             :     squeeze out the unused space
      49             : 
      50             :     A "plain payload" has no actionable transfer
      51             :         encoding.
      52             : 
      53             :     A "buffered payload" is any payload which is
      54             :         not plain. A second buffer is required
      55             :         for reading.
      56             : */
      57             : //------------------------------------------------
      58             : 
      59             : class parser_service
      60             :     : public service
      61             : {
      62             : public:
      63             :     parser::config_base cfg;
      64             :     std::size_t space_needed = 0;
      65             :     std::size_t max_codec = 0;
      66             :     zlib::deflate_decoder_service const*
      67             :         deflate_svc = nullptr;
      68             : 
      69             :     parser_service(
      70             :         context& ctx,
      71             :         parser::config_base const& cfg_);
      72             : 
      73             :     std::size_t
      74       40065 :     max_overread() const noexcept
      75             :     {
      76             :         return
      77       40065 :             cfg.headers.max_size +
      78       40065 :             cfg.min_buffer;
      79             :     }
      80             : };
      81             : 
      82           6 : parser_service::
      83             : parser_service(
      84             :     context& ctx,
      85           6 :     parser::config_base const& cfg_)
      86           6 :         : cfg(cfg_)
      87             : {
      88             : /*
      89             :     | fb |      cb0      |      cb1     | C | T | f |
      90             : 
      91             :     fb  flat_buffer         headers.max_size
      92             :     cb0 circular_buffer     min_buffer
      93             :     cb1 circular_buffer     min_buffer
      94             :     C   codec               max_codec
      95             :     T   body                max_type_erase
      96             :     f   table               max_table_space
      97             : 
      98             : */
      99             :     // validate
     100             :     //if(cfg.min_prepare > cfg.max_prepare)
     101             :         //detail::throw_invalid_argument();
     102             : 
     103           6 :     if( cfg.min_buffer < 1 ||
     104           6 :         cfg.min_buffer > cfg.body_limit)
     105           0 :         detail::throw_invalid_argument();
     106             : 
     107           6 :     if(cfg.max_prepare < 1)
     108           0 :         detail::throw_invalid_argument();
     109             : 
     110             :     // VFALCO TODO OVERFLOW CHECING
     111             :     {
     112             :         //fb_.size() - h_.size +
     113             :         //svc_.cfg.min_buffer +
     114             :         //svc_.cfg.min_buffer +
     115             :         //svc_.max_codec;
     116             :     }
     117             : 
     118             :     // VFALCO OVERFLOW CHECKING ON THIS
     119           6 :     space_needed +=
     120           6 :         cfg.headers.valid_space_needed();
     121             : 
     122             :     // cb0_, cb1_
     123             :     // VFALCO OVERFLOW CHECKING ON THIS
     124           6 :     space_needed +=
     125           6 :         cfg.min_buffer +
     126             :         cfg.min_buffer;
     127             : 
     128             :     // T
     129           6 :     space_needed += cfg.max_type_erase;
     130             : 
     131             :     // max_codec
     132             :     {
     133           6 :         if(cfg.apply_deflate_decoder)
     134             :         {
     135           0 :             deflate_svc = &ctx.get_service<
     136           0 :                 zlib::deflate_decoder_service>();
     137             :             auto const n = 
     138           0 :                 deflate_svc->space_needed();
     139           0 :             if( max_codec < n)
     140           0 :                 max_codec = n;
     141             :         }
     142             :     }
     143           6 :     space_needed += max_codec;
     144           6 : }
     145             : 
     146             : void
     147           6 : install_parser_service(
     148             :     context& ctx,
     149             :     parser::config_base const& cfg)
     150             : {
     151             :     ctx.make_service<
     152           6 :         parser_service>(cfg);
     153           6 : }
     154             : 
     155             : //------------------------------------------------
     156             : 
     157        6646 : parser::
     158             : parser(
     159             :     context& ctx,
     160        6646 :     detail::kind k)
     161             :     : ctx_(ctx)
     162             :     , svc_(ctx.get_service<
     163       13292 :         parser_service>())
     164             :     , h_(detail::empty{k})
     165        6646 :     , st_(state::reset)
     166             : {
     167        6646 :     auto const n =
     168        6646 :         svc_.space_needed;
     169        6646 :     ws_.allocate(n);
     170        6646 :     h_.cap = n;
     171        6646 : }
     172             : 
     173             : //------------------------------------------------
     174             : //
     175             : // Special Members
     176             : //
     177             : //------------------------------------------------
     178             : 
     179        6646 : parser::
     180        6646 : ~parser()
     181             : {
     182        6646 : }
     183             : 
     184             : parser::
     185             : parser(
     186             :     parser&&) noexcept = default;
     187             : 
     188             : //------------------------------------------------
     189             : //
     190             : // Modifiers
     191             : //
     192             : //------------------------------------------------
     193             : 
     194             : // prepare for a new stream
     195             : void
     196        6644 : parser::
     197             : reset() noexcept
     198             : {
     199        6644 :     ws_.clear();
     200        6644 :     st_ = state::start;
     201        6644 :     got_eof_ = false;
     202        6644 : }
     203             : 
     204             : void
     205        6644 : parser::
     206             : start_impl(
     207             :     bool head_response)
     208             : {
     209        6644 :     std::size_t leftover = 0;
     210        6644 :     switch(st_)
     211             :     {
     212           0 :     default:
     213             :     case state::reset:
     214             :         // reset must be called first
     215           0 :         detail::throw_logic_error();
     216             : 
     217        6644 :     case state::start:
     218        6644 :         BOOST_ASSERT(h_.size == 0);
     219        6644 :         BOOST_ASSERT(fb_.size() == 0);
     220        6644 :         BOOST_ASSERT(! got_eof_);
     221        6644 :         break;
     222             : 
     223           0 :     case state::header:
     224             :         // start() called twice
     225           0 :         detail::throw_logic_error();
     226             : 
     227           0 :     case state::body:
     228             :         // current message is incomplete
     229           0 :         detail::throw_logic_error();
     230             : 
     231           0 :     case state::complete:
     232             :     {
     233             :         // overread data is always in cb0_
     234             : 
     235           0 :         if(fb_.size() > 0)
     236             :         {
     237             :             // headers with no body
     238           0 :             BOOST_ASSERT(h_.size > 0);
     239           0 :             fb_.consume(h_.size);
     240           0 :             leftover = fb_.size();
     241             :             // move unused octets to front
     242           0 :             buffers::buffer_copy(
     243           0 :                 buffers::mutable_buffer(
     244           0 :                     ws_.data(),
     245             :                     leftover),
     246           0 :                 fb_.data());
     247             :         }
     248             :         else
     249             :         {
     250             :             // leftover data after body
     251             :         }
     252           0 :         break;
     253             :     }
     254             :     }
     255             : 
     256        6644 :     ws_.clear();
     257             : 
     258       13288 :     fb_ = {
     259        6644 :         ws_.data(),
     260        6644 :         svc_.cfg.headers.max_size +
     261        6644 :             svc_.cfg.min_buffer,
     262             :         leftover };
     263        6644 :     BOOST_ASSERT(
     264             :         fb_.capacity() == svc_.max_overread());
     265             : 
     266       13288 :     h_ = detail::header(
     267        6644 :         detail::empty{h_.kind});
     268        6644 :     h_.buf = reinterpret_cast<
     269        6644 :         char*>(ws_.data());
     270        6644 :     h_.cbuf = h_.buf;
     271        6644 :     h_.cap = ws_.size();
     272             : 
     273        6644 :     BOOST_ASSERT(! head_response ||
     274             :         h_.kind == detail::kind::response);
     275        6644 :     head_response_ = head_response;
     276             : 
     277        6644 :     body_ = body::in_place;
     278        6644 :     st_ = state::header;
     279        6644 : }
     280             : 
     281             : auto
     282       20356 : parser::
     283             : prepare() ->
     284             :     mutable_buffers_type
     285             : {
     286       20356 :     switch(st_)
     287             :     {
     288           0 :     default:
     289             :     case state::reset:
     290             :         // reset must be called first
     291           0 :         detail::throw_logic_error();
     292             : 
     293           0 :     case state::start:
     294             :         // start must be called first
     295           0 :         detail::throw_logic_error();
     296             : 
     297       19459 :     case state::header:
     298             :     {
     299       19459 :         BOOST_ASSERT(h_.size <
     300             :             svc_.cfg.headers.max_size);
     301       19459 :         auto n = fb_.capacity() - fb_.size();
     302       19459 :         BOOST_ASSERT(n <= svc_.max_overread());
     303       19459 :         if( n > svc_.cfg.max_prepare)
     304           0 :             n = svc_.cfg.max_prepare;
     305       19459 :         mbp_[0] = fb_.prepare(n);
     306       19459 :         return mutable_buffers_type(
     307       38918 :             &mbp_[0], 1);
     308             :     }
     309             : 
     310         897 :     case state::body:
     311             :     {
     312             :         // buffered payload
     313         897 :         if(body_buf_ != &cb0_)
     314             :         {
     315           0 :             auto n = cb0_.capacity() -
     316           0 :                 cb0_.size();
     317           0 :             if( n > svc_.cfg.max_prepare)
     318           0 :                 n = svc_.cfg.max_prepare;
     319           0 :             mbp_ = cb0_.prepare(n);
     320           0 :             return mutable_buffers_type(mbp_);
     321             :         }
     322             : 
     323             :         // plain payload
     324             : 
     325         897 :         if( body_ == body::in_place ||
     326           0 :             body_ == body::sink)
     327             :         {
     328         897 :             auto n = cb0_.capacity() -
     329         897 :                 cb0_.size();
     330         897 :             if( n > svc_.cfg.max_prepare)
     331           0 :                 n = svc_.cfg.max_prepare;
     332         897 :             mbp_ = cb0_.prepare(n);
     333         897 :             BOOST_ASSERT(mbp_[1].size() == 0);
     334         897 :             return mutable_buffers_type(
     335        1794 :                 &mbp_[0], 1);
     336             :         }
     337             : 
     338           0 :         if(body_ == body::dynamic)
     339             :         {
     340           0 :             BOOST_ASSERT(dyn_ != nullptr);
     341           0 :             if(h_.md.payload == payload::size)
     342             :             {
     343             :                 // exact size
     344             :                 std::size_t n =
     345           0 :                     h_.md.payload_size - dyn_->size();
     346           0 :                 if( n > svc_.cfg.max_prepare)
     347           0 :                     n = svc_.cfg.max_prepare;
     348           0 :                 return dyn_->prepare(n);
     349             :             }
     350             : 
     351             :             // heuristic size
     352           0 :             std::size_t n = svc_.cfg.min_buffer;
     353           0 :             if( n > svc_.cfg.max_prepare)
     354           0 :                 n = svc_.cfg.max_prepare;
     355           0 :             return dyn_->prepare(n);
     356             :         }
     357             : 
     358             :         // VFALCO TODO
     359           0 :         if(body_ == body::stream)
     360           0 :             detail::throw_logic_error();
     361             : 
     362             :         // VFALCO TODO
     363           0 :         detail::throw_logic_error();
     364             :     }
     365             : 
     366           0 :     case state::complete:
     367             :         // We allow the call for callers
     368             :         // who want normalized usage, but
     369             :         // just return a 0-sized sequence.
     370           0 :         return mutable_buffers_type{};
     371             :     }
     372             : }
     373             : 
     374             : void
     375       20356 : parser::
     376             : commit(
     377             :     std::size_t n)
     378             : {
     379             :     // Can't commit after eof
     380       20356 :     if(got_eof_)
     381           0 :         detail::throw_logic_error();
     382             : 
     383       20356 :     switch(st_)
     384             :     {
     385           0 :     default:
     386             :     case state::reset:
     387             :         // reset must be called first
     388           0 :         detail::throw_logic_error();
     389             : 
     390           0 :     case state::start:
     391             :         // forgot to call start()
     392           0 :         detail::throw_logic_error();
     393             : 
     394       19459 :     case state::header:
     395       19459 :         fb_.commit(n);
     396       19459 :         break;
     397             : 
     398         897 :     case state::body:
     399         897 :         if(body_buf_ != &cb0_)
     400             :         {
     401             :             // buffered body
     402           0 :             cb0_.commit(n);
     403           0 :             break;
     404             :         }
     405         897 :         if(body_ == body::in_place)
     406             :         {
     407         897 :             cb0_.commit(n);
     408         897 :             break;
     409             :         }
     410           0 :         if(body_ == body::dynamic)
     411             :         {
     412           0 :             dyn_->commit(n);
     413           0 :             break;
     414             :         }
     415           0 :         if(body_ == body::sink)
     416             :         {
     417           0 :             cb0_.commit(n);
     418           0 :             break;
     419             :         }
     420           0 :         if(body_ == body::stream)
     421             :         {
     422             :             // VFALCO TODO
     423           0 :             detail::throw_logic_error();
     424             :         }
     425           0 :         break;
     426             : 
     427           0 :     case state::complete:
     428             :         // intended no-op
     429           0 :         break;
     430             :     }
     431       20356 : }
     432             : 
     433             : void
     434        1450 : parser::
     435             : commit_eof()
     436             : {
     437        1450 :     switch(st_)
     438             :     {
     439           0 :     default:
     440             :     case state::reset:
     441             :         // reset must be called first
     442           0 :         detail::throw_logic_error();
     443             : 
     444           0 :     case state::start:
     445             :         // forgot to call prepare()
     446           0 :         detail::throw_logic_error();
     447             : 
     448           0 :     case state::header:
     449           0 :         got_eof_ = true;
     450           0 :         break;
     451             : 
     452        1450 :     case state::body:
     453        1450 :         got_eof_ = true;
     454        1450 :         break;
     455             : 
     456           0 :     case state::complete:
     457             :         // can't commit eof when complete
     458           0 :         detail::throw_logic_error();
     459             :     }
     460        1450 : }
     461             : 
     462             : //-----------------------------------------------
     463             : 
     464             : // process input data then
     465             : // eof if input data runs out.
     466             : void
     467       21806 : parser::
     468             : parse(
     469             :     system::error_code& ec)
     470             : {
     471       21806 :     ec = {};
     472       21806 :     switch(st_)
     473             :     {
     474           0 :     default:
     475             :     case state::reset:
     476             :         // reset must be called first
     477           0 :         detail::throw_logic_error();
     478             : 
     479           0 :     case state::start:
     480             :         // start must be called first
     481           0 :         detail::throw_logic_error();
     482             : 
     483       19459 :     case state::header:
     484             :     {
     485       19459 :         BOOST_ASSERT(h_.buf == static_cast<
     486             :             void const*>(ws_.data()));
     487       19459 :         BOOST_ASSERT(h_.cbuf == static_cast<
     488             :             void const*>(ws_.data()));
     489       19459 :         auto const new_size = fb_.size();
     490       19459 :         h_.parse(new_size, svc_.cfg.headers, ec);
     491       19459 :         if(ec == condition::need_more_input)
     492             :         {
     493       12815 :             if(! got_eof_)
     494             :             {
     495             :                 // headers incomplete
     496       12815 :                 return;
     497             :             }
     498           0 :             if(h_.size == 0)
     499             :             {
     500             :                 // stream closed cleanly
     501           0 :                 ec = BOOST_HTTP_PROTO_ERR(
     502             :                     error::end_of_stream);
     503           0 :                 return;
     504             :             }
     505             : 
     506             :             // stream closed with a
     507             :             // partial message received
     508           0 :             ec = BOOST_HTTP_PROTO_ERR(
     509             :                 error::incomplete);
     510           0 :             return;
     511             :         }
     512        6644 :         if(ec.failed())
     513             :         {
     514             :             // other error,
     515             :             //
     516             :             // VFALCO map this to a bad
     517             :             // request or bad response error?
     518             :             //
     519         128 :             st_ = state::reset; // unrecoverable
     520         128 :             return;
     521             :         }
     522             : 
     523             :         // headers are complete
     524        6516 :         on_headers(ec);
     525        6516 :         if(ec.failed())
     526           0 :             return;
     527        6516 :         if(st_ == state::complete)
     528        1343 :             break;
     529        5173 :         BOOST_ASSERT(st_ == state::body);
     530             :         BOOST_FALLTHROUGH;
     531             :     }
     532             : 
     533             :     case state::body:
     534             :     {
     535        7520 :         if(body_ == body::in_place)
     536             :         {
     537        7520 :             if(filt_)
     538             :             {
     539             :                 // apply filter
     540           0 :                 detail::throw_logic_error();
     541             :             }
     542        7520 :             if(h_.md.payload == payload::size)
     543             :             {
     544        4338 :                 if(cb0_.size() <
     545        4338 :                     h_.md.payload_size)
     546             :                 {
     547        1230 :                     ec = BOOST_HTTP_PROTO_ERR(
     548             :                         error::need_data);
     549         615 :                     return;
     550             :                 }
     551        3723 :                 st_ = state::complete;
     552        3723 :                 break;
     553             :             }
     554        3182 :             BOOST_ASSERT(h_.md.payload ==
     555             :                 payload::to_eof);
     556        3182 :             if(! got_eof_)
     557             :             {
     558        3464 :                 ec = BOOST_HTTP_PROTO_ERR(
     559             :                     error::need_data);
     560        1732 :                 return;
     561             :             }
     562        1450 :             st_ = state::complete;
     563        1450 :             break;
     564             :         }
     565             : 
     566             :         // VFALCO TODO
     567           0 :         detail::throw_logic_error();
     568             :     }
     569             : 
     570           0 :     case state::complete:
     571             :     {
     572             :         // This is a no-op except when set_body
     573             :         // was called and we have in-place data.
     574           0 :         switch(body_)
     575             :         {
     576           0 :         default:
     577             :         case body::in_place:
     578           0 :             break;
     579             : 
     580           0 :         case body::dynamic:
     581             :         {
     582           0 :             if(body_buf_->size() == 0)
     583           0 :                 break;
     584           0 :             BOOST_ASSERT(dyn_->size() == 0);
     585           0 :             auto n = buffers::buffer_copy(
     586           0 :                 dyn_->prepare(
     587           0 :                     body_buf_->size()),
     588           0 :                 body_buf_->data());
     589           0 :             body_buf_->consume(n);
     590           0 :             break;
     591             :         }
     592             : 
     593           0 :         case body::sink:
     594             :         {
     595           0 :             if(body_buf_->size() == 0)
     596           0 :                 break;
     597           0 :             auto rv = sink_->write(
     598           0 :                 body_buf_->data(), false);
     599           0 :             body_buf_->consume(rv.bytes);
     600           0 :             if(rv.ec.failed())
     601             :             {
     602           0 :                 ec = rv.ec;
     603           0 :                 st_ = state::reset; // unrecoverable
     604           0 :                 return;
     605             :             }
     606           0 :             break;
     607             :         }
     608             : 
     609           0 :         case body::stream:
     610             :             // VFALCO TODO
     611           0 :             detail::throw_logic_error();
     612             :         }
     613             :     }
     614             :     }
     615             : }
     616             : 
     617             : //------------------------------------------------
     618             : 
     619             : auto
     620           0 : parser::
     621             : get_stream() ->
     622             :     stream
     623             : {
     624             :     // body type already chosen
     625           0 :     if(body_ != body::in_place)
     626           0 :         detail::throw_logic_error();
     627             : 
     628           0 :     body_ = body::stream;
     629           0 :     return stream(*this);
     630             : }
     631             : 
     632             : core::string_view
     633        4543 : parser::
     634             : in_place_body() const
     635             : {
     636             :     // not in place
     637        4543 :     if(body_ != body::in_place)
     638           0 :         detail::throw_logic_error();
     639             : 
     640             :     // incomplete
     641        4543 :     if(st_ != state::complete)
     642           0 :         detail::throw_logic_error();
     643             : 
     644        4543 :     buffers::const_buffer_pair bs = body_buf_->data();
     645        4543 :     BOOST_ASSERT(bs[1].size() == 0);
     646        9086 :     return core::string_view(static_cast<
     647        4543 :         char const*>(bs[0].data()),
     648        9086 :             bs[0].size());
     649             : }
     650             : 
     651             : //------------------------------------------------
     652             : 
     653             : core::string_view
     654           0 : parser::
     655             : release_buffered_data() noexcept
     656             : {
     657           0 :     return {};
     658             : }
     659             : 
     660             : //------------------------------------------------
     661             : //
     662             : // Implementation
     663             : //
     664             : //------------------------------------------------
     665             : 
     666             : auto
     667        5969 : parser::
     668             : safe_get_header() const ->
     669             :     detail::header const*
     670             : {
     671        5969 :     switch(st_)
     672             :     {
     673           0 :     default:
     674             :     case state::start:
     675             :     case state::header:
     676             :         // Headers not received yet
     677           0 :         detail::throw_logic_error();
     678             : 
     679        5969 :     case state::body:
     680             :     case state::complete:
     681             :         // VFALCO check if headers are discarded?
     682        5969 :         break;
     683             :     }
     684        5969 :     return &h_;
     685             : }
     686             : 
     687             : // Called immediately after
     688             : // complete headers are received
     689             : void
     690        6516 : parser::
     691             : on_headers(
     692             :     system::error_code& ec)
     693             : {
     694             :     auto const overread =
     695        6516 :         fb_.size() - h_.size;
     696        6516 :     BOOST_ASSERT(
     697             :         overread <= svc_.max_overread());
     698             : 
     699             :     // reserve headers + table
     700        6516 :     ws_.reserve_front(h_.size);
     701        6516 :     ws_.reserve_back(h_.table_space());
     702             : 
     703             :     // no payload
     704        6516 :     if( h_.md.payload == payload::none ||
     705        5173 :         head_response_)
     706             :     {
     707             :         // set cb0_ to overread
     708        2686 :         cb0_ = {
     709        1343 :             ws_.data(),
     710        1343 :             fb_.capacity() - h_.size,
     711             :             overread };
     712        1343 :         st_ = state::complete;
     713        1343 :         return;
     714             :     }
     715             : 
     716             :     // metadata error
     717        5173 :     if(h_.md.payload == payload::error)
     718             :     {
     719             :         // VFALCO This needs looking at
     720           0 :         ec = BOOST_HTTP_PROTO_ERR(
     721             :             error::bad_payload);
     722           0 :         st_ = state::reset; // unrecoverable
     723           0 :         return;
     724             :     }
     725             : 
     726             :     // calculate filter
     727        5173 :     filt_ = nullptr;
     728             : 
     729             :     // plain payload
     730        5173 :     if( h_.md.payload != payload::chunked &&
     731        5173 :         ! filt_)
     732             :     {
     733             :         // payload size is known
     734        5173 :         if(h_.md.payload == payload::size)
     735             :         {
     736        3723 :             if(h_.md.payload_size >
     737        3723 :                 svc_.cfg.body_limit)
     738             :             {
     739           0 :                 ec = BOOST_HTTP_PROTO_ERR(
     740             :                     error::body_too_large);
     741           0 :                 st_ = state::reset; // unrecoverable
     742           0 :                 return;
     743             :             }
     744             :             auto n0 =
     745        3723 :                 fb_.capacity() - h_.size +
     746        3723 :                 svc_.cfg.min_buffer +
     747        3723 :                 svc_.max_codec;
     748             :             // limit the capacity of cb0_ so
     749             :             // that going over max_overread
     750             :             // is impossible.
     751        7446 :             if( n0 > h_.md.payload_size &&
     752        3723 :                 n0 - h_.md.payload_size >=
     753        3723 :                     svc_.max_overread())
     754        3723 :                 n0 =
     755        3723 :                     h_.md.payload_size +
     756        3723 :                     svc_.max_overread();
     757        3723 :             BOOST_ASSERT(n0 <= ws_.size());
     758        3723 :             cb0_ = {
     759        3723 :                 ws_.data(),
     760             :                 n0,
     761             :                 overread };
     762        3723 :             body_buf_ = &cb0_;
     763        3723 :             st_ = state::body;
     764        3723 :             return;
     765             :         }
     766             : 
     767             :         // payload to eof
     768             :         // overread is not applicable
     769             :         auto const n0 =
     770        1450 :             fb_.capacity() - h_.size +
     771        1450 :             svc_.cfg.min_buffer +
     772        1450 :             svc_.max_codec;
     773        1450 :         BOOST_ASSERT(n0 <= ws_.size());
     774        1450 :         cb0_ = {
     775        1450 :             ws_.data(),
     776             :             n0,
     777             :             overread };
     778        1450 :         body_buf_ = &cb0_;
     779        1450 :         st_ = state::body;
     780        1450 :         return;
     781             :     }
     782             : 
     783             :     // buffered payload
     784             :     auto const n0 =
     785           0 :         fb_.capacity() - h_.size;
     786           0 :     BOOST_ASSERT(
     787             :         n0 <= svc_.max_overread());
     788           0 :     auto n1 = svc_.cfg.min_buffer;
     789           0 :     if(! filt_)
     790           0 :         n1 += svc_.max_codec;
     791           0 :     BOOST_ASSERT(
     792             :         n0 + n1 <= ws_.size());
     793           0 :     cb0_ = {
     794           0 :         ws_.data(),
     795             :         n0,
     796             :         overread };
     797           0 :     cb1_ = {
     798           0 :         ws_.data() + n0,
     799             :         n1 };
     800           0 :     body_buf_ = &cb1_;
     801           0 :     st_ = state::body;
     802           0 :     return;
     803             : }
     804             : 
     805             : // Called at the end of set_body
     806             : void
     807           0 : parser::
     808             : on_set_body()
     809             : {
     810             :     // This function is called after all
     811             :     // limit checking and calculation of
     812             :     // chunked or filter.
     813             : 
     814           0 :     BOOST_ASSERT(got_header());
     815             : 
     816           0 :     if(h_.md.payload == payload::size)
     817             :     {
     818           0 :         if(body_ == body::dynamic)
     819             :         {
     820           0 :             dyn_->prepare(
     821           0 :                 h_.md.payload_size);
     822           0 :             return;
     823             :         }
     824           0 :         if(body_ == body::sink)
     825             :         {
     826             :             //sink_->size_hint(&h_.md.payload_size);
     827           0 :             return;
     828             :         }
     829           0 :         return;
     830             :     }
     831             : 
     832           0 :     return;
     833             : }
     834             : 
     835             : } // http_proto
     836             : } // boost
     837             : 
     838             : #endif

Generated by: LCOV version 1.15