LCOV - code coverage report
Current view: top level - http_proto/impl - parser.ipp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 437 579 75.5 %
Date: 2023-12-11 14:11:20 Functions: 26 33 78.8 %

          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             :     Principles for fixed-size buffer design
      28             : 
      29             :     axiom 1:
      30             :         To read data you must have a buffer.
      31             : 
      32             :     axiom 2:
      33             :         The size of the HTTP header is not
      34             :         known in advance.
      35             : 
      36             :     conclusion 3:
      37             :         A single I/O can produce a complete
      38             :         HTTP header and additional payload
      39             :         data.
      40             : 
      41             :     conclusion 4:
      42             :         A single I/O can produce multiple
      43             :         complete HTTP headers, complete
      44             :         payloads, and a partial header or
      45             :         payload.
      46             : 
      47             :     axiom 5:
      48             :         A process is in one of two states:
      49             :             1. at or below capacity
      50             :             2. above capacity
      51             : 
      52             :     axiom 6:
      53             :         A program which can allocate an
      54             :         unbounded number of resources can
      55             :         go above capacity.
      56             : 
      57             :     conclusion 7:
      58             :         A program can guarantee never going
      59             :         above capacity if all resources are
      60             :         provisioned at program startup.
      61             : 
      62             :     corollary 8:
      63             :         `parser` and `serializer` should each
      64             :         allocate a single buffer of calculated
      65             :         size, and never resize it.
      66             : 
      67             :     axiom #:
      68             :         A parser and a serializer are always
      69             :         used in pairs.
      70             : 
      71             : Buffer Usage
      72             : 
      73             : |                                               | begin
      74             : | H |   p   |                               | f | read headers
      75             : | H |   p   |                           | T | f | set T body
      76             : | H |   p   |                       | C | T | f | make codec C
      77             : | H |   p           |       b       | C | T | f | decode p into b
      78             : | H |       p       |       b       | C | T | f | read/parse loop
      79             : | H |                                   | T | f | destroy codec
      80             : | H |                                   | T | f | finished
      81             : 
      82             :     H   headers
      83             :     C   codec
      84             :     T   body
      85             :     f   table
      86             :     p   partial payload
      87             :     b   body data
      88             : 
      89             :     "payload" is the bytes coming in from
      90             :         the stream.
      91             : 
      92             :     "body" is the logical body, after transfer
      93             :         encoding is removed. This can be the
      94             :         same as the payload.
      95             : 
      96             :     A "plain payload" is when the payload and
      97             :         body are identical (no transfer encodings).
      98             : 
      99             :     A "buffered payload" is any payload which is
     100             :         not plain. A second buffer is required
     101             :         for reading.
     102             : 
     103             :     "overread" is additional data received past
     104             :     the end of the headers when reading headers,
     105             :     or additional data received past the end of
     106             :     the message payload.
     107             : */
     108             : //-----------------------------------------------
     109             : 
     110             : class parser_service
     111             :     : public service
     112             : {
     113             : public:
     114             :     parser::config_base cfg;
     115             :     std::size_t space_needed = 0;
     116             :     std::size_t max_codec = 0;
     117             :     zlib::deflate_decoder_service const*
     118             :         deflate_svc = nullptr;
     119             : 
     120             :     parser_service(
     121             :         context& ctx,
     122             :         parser::config_base const& cfg_);
     123             : 
     124             :     std::size_t
     125        7504 :     max_overread() const noexcept
     126             :     {
     127             :         return
     128        7504 :             cfg.headers.max_size +
     129        7504 :             cfg.min_buffer;
     130             :     }
     131             : };
     132             : 
     133          31 : parser_service::
     134             : parser_service(
     135             :     context& ctx,
     136          31 :     parser::config_base const& cfg_)
     137          31 :         : cfg(cfg_)
     138             : {
     139             : /*
     140             :     | fb |     cb0     |     cb1     | C | T | f |
     141             : 
     142             :     fb  flat_buffer         headers.max_size
     143             :     cb0 circular_buffer     min_buffer
     144             :     cb1 circular_buffer     min_buffer
     145             :     C   codec               max_codec
     146             :     T   body                max_type_erase
     147             :     f   table               max_table_space
     148             : 
     149             : */
     150             :     // validate
     151             :     //if(cfg.min_prepare > cfg.max_prepare)
     152             :         //detail::throw_invalid_argument();
     153             : 
     154          31 :     if( cfg.min_buffer < 1 ||
     155          31 :         cfg.min_buffer > cfg.body_limit)
     156           0 :         detail::throw_invalid_argument();
     157             : 
     158          31 :     if(cfg.max_prepare < 1)
     159           0 :         detail::throw_invalid_argument();
     160             : 
     161             :     // VFALCO TODO OVERFLOW CHECING
     162             :     {
     163             :         //fb_.size() - h_.size +
     164             :         //svc_.cfg.min_buffer +
     165             :         //svc_.cfg.min_buffer +
     166             :         //svc_.max_codec;
     167             :     }
     168             : 
     169             :     // VFALCO OVERFLOW CHECKING ON THIS
     170          31 :     space_needed +=
     171          31 :         cfg.headers.valid_space_needed();
     172             : 
     173             :     // cb0_, cb1_
     174             :     // VFALCO OVERFLOW CHECKING ON THIS
     175          31 :     space_needed +=
     176          31 :         cfg.min_buffer +
     177             :         cfg.min_buffer;
     178             : 
     179             :     // T
     180          31 :     space_needed += cfg.max_type_erase;
     181             : 
     182             :     // max_codec
     183             :     {
     184          31 :         if(cfg.apply_deflate_decoder)
     185             :         {
     186           0 :             deflate_svc = &ctx.get_service<
     187           0 :                 zlib::deflate_decoder_service>();
     188             :             auto const n = 
     189           0 :                 deflate_svc->space_needed();
     190           0 :             if( max_codec < n)
     191           0 :                 max_codec = n;
     192             :         }
     193             :     }
     194          31 :     space_needed += max_codec;
     195             : 
     196             :     // round up to alignof(detail::header::entry)
     197          31 :     auto const al = alignof(
     198             :         detail::header::entry);
     199          31 :     space_needed = al * ((
     200          31 :         space_needed + al - 1) / al);
     201          31 : }
     202             : 
     203             : void
     204          31 : install_parser_service(
     205             :     context& ctx,
     206             :     parser::config_base const& cfg)
     207             : {
     208             :     ctx.make_service<
     209          31 :         parser_service>(cfg);
     210          31 : }
     211             : 
     212             : //------------------------------------------------
     213             : //
     214             : // Special Members
     215             : //
     216             : //------------------------------------------------
     217             : 
     218         791 : parser::
     219             : parser(
     220             :     context& ctx,
     221         791 :     detail::kind k)
     222             :     : ctx_(ctx)
     223             :     , svc_(ctx.get_service<
     224        1582 :         parser_service>())
     225             :     , h_(detail::empty{k})
     226         791 :     , st_(state::reset)
     227             : {
     228         791 :     auto const n =
     229         791 :         svc_.space_needed;
     230         791 :     ws_.allocate(n);
     231         791 :     h_.cap = n;
     232         791 : }
     233             : 
     234             : //------------------------------------------------
     235             : 
     236         791 : parser::
     237         791 : ~parser()
     238             : {
     239         791 : }
     240             : 
     241             : //------------------------------------------------
     242             : //
     243             : // Modifiers
     244             : //
     245             : //------------------------------------------------
     246             : 
     247             : // prepare for a new stream
     248             : void
     249        1247 : parser::
     250             : reset() noexcept
     251             : {
     252        1247 :     ws_.clear();
     253        1247 :     st_ = state::start;
     254        1247 :     got_eof_ = false;
     255        1247 : }
     256             : 
     257             : void
     258        1488 : parser::
     259             : start_impl(
     260             :     bool head_response)
     261             : {
     262        1488 :     std::size_t leftover = 0;
     263        1488 :     switch(st_)
     264             :     {
     265           1 :     default:
     266             :     case state::reset:
     267             :         // reset must be called first
     268           1 :         detail::throw_logic_error();
     269             : 
     270        1243 :     case state::start:
     271             :         // reset required on eof
     272        1243 :         if(got_eof_)
     273           0 :             detail::throw_logic_error();
     274        1243 :         break;
     275             : 
     276           3 :     case state::header:
     277           3 :         if(fb_.size() == 0)
     278             :         {
     279             :             // start() called twice
     280           2 :             detail::throw_logic_error();
     281             :         }
     282             :         BOOST_FALLTHROUGH;
     283             : 
     284             :     case state::body:
     285             :     case state::set_body:
     286             :         // current message is incomplete
     287           2 :         detail::throw_logic_error();
     288             : 
     289         240 :     case state::complete:
     290             :     {
     291             :         // remove partial body.
     292         240 :         if(body_buf_ == &cb0_)
     293         240 :             cb0_.consume(body_avail_);
     294             : 
     295         240 :         if(cb0_.size() > 0)
     296             :         {
     297             :             // headers with no body
     298           0 :             BOOST_ASSERT(h_.size > 0);
     299           0 :             fb_.consume(h_.size);
     300           0 :             leftover = fb_.size();
     301             :             // move unused octets to front
     302           0 :             buffers::buffer_copy(
     303           0 :                 buffers::mutable_buffer(
     304           0 :                     ws_.data(),
     305             :                     leftover),
     306           0 :                 fb_.data());
     307             :         }
     308             :         else
     309             :         {
     310             :             // leftover data after body
     311             :         }
     312         240 :         break;
     313             :     }
     314             :     }
     315             : 
     316        1483 :     ws_.clear();
     317             : 
     318        2966 :     fb_ = {
     319        1483 :         ws_.data(),
     320        1483 :         svc_.cfg.headers.max_size +
     321        1483 :             svc_.cfg.min_buffer,
     322             :         leftover };
     323        1483 :     BOOST_ASSERT(fb_.capacity() ==
     324             :         svc_.max_overread());
     325             : 
     326        2966 :     h_ = detail::header(
     327        1483 :         detail::empty{h_.kind});
     328        1483 :     h_.buf = reinterpret_cast<
     329        1483 :         char*>(ws_.data());
     330        1483 :     h_.cbuf = h_.buf;
     331        1483 :     h_.cap = ws_.size();
     332             : 
     333        1483 :     BOOST_ASSERT(! head_response ||
     334             :         h_.kind == detail::kind::response);
     335        1483 :     head_response_ = head_response;
     336             : 
     337             :     // begin with in_place mode
     338        1483 :     how_ = how::in_place;
     339        1483 :     st_ = state::header;
     340        1483 :     nprepare_ = 0;
     341        1483 : }
     342             : 
     343             : auto
     344        4494 : parser::
     345             : prepare() ->
     346             :     mutable_buffers_type
     347             : {
     348        4494 :     nprepare_ = 0;
     349             : 
     350        4494 :     switch(st_)
     351             :     {
     352           1 :     default:
     353             :     case state::reset:
     354             :         // reset must be called first
     355           1 :         detail::throw_logic_error();
     356             : 
     357           1 :     case state::start:
     358             :         // start must be called first
     359           1 :         detail::throw_logic_error();
     360             : 
     361        4431 :     case state::header:
     362             :     {
     363        4431 :         BOOST_ASSERT(h_.size <
     364             :             svc_.cfg.headers.max_size);
     365        4431 :         auto n = fb_.capacity() - fb_.size();
     366        4431 :         BOOST_ASSERT(n <= svc_.max_overread());
     367        4431 :         if( n > svc_.cfg.max_prepare)
     368          29 :             n = svc_.cfg.max_prepare;
     369        4431 :         mbp_[0] = fb_.prepare(n);
     370        4431 :         nprepare_ = n;
     371        4431 :         return mutable_buffers_type(
     372        8862 :             &mbp_[0], 1);
     373             :     }
     374             : 
     375          31 :     case state::body:
     376             :     {
     377          31 :         if(got_eof_)
     378           0 :             return mutable_buffers_type{};
     379             : 
     380          31 :     do_body:
     381          55 :         if(! is_plain())
     382             :         {
     383             :             // buffered payload
     384           0 :             auto n = cb0_.capacity() -
     385           0 :                 cb0_.size();
     386           0 :             if( n > svc_.cfg.max_prepare)
     387           0 :                 n = svc_.cfg.max_prepare;
     388           0 :             mbp_ = cb0_.prepare(n);
     389           0 :             nprepare_ = n;
     390           0 :             return mutable_buffers_type(mbp_);
     391             :         }
     392             : 
     393             :         // plain payload
     394             : 
     395          55 :         if(how_ == how::in_place)
     396             :         {
     397             :             auto n =
     398          29 :                 body_buf_->capacity() -
     399          29 :                 body_buf_->size();
     400          29 :             if( n > svc_.cfg.max_prepare)
     401           1 :                 n = svc_.cfg.max_prepare;
     402          29 :             mbp_ = body_buf_->prepare(n);
     403          29 :             nprepare_ = n;
     404          29 :             return mutable_buffers_type(mbp_);
     405             :         }
     406             : 
     407          26 :         if(how_ == how::dynamic)
     408             :         {
     409             :             // Overreads are not allowed, or
     410             :             // else the caller will see extra
     411             :             // unrelated data.
     412             : 
     413          26 :             if(h_.md.payload == payload::size)
     414             :             {
     415             :                 // set_body moves avail to dyn
     416           9 :                 BOOST_ASSERT(body_buf_->size() == 0);
     417           9 :                 BOOST_ASSERT(body_avail_ == 0);
     418           9 :                 auto n = payload_remain_;
     419           9 :                 if( n > svc_.cfg.max_prepare)
     420           1 :                     n = svc_.cfg.max_prepare;
     421           9 :                 nprepare_ = n;
     422           9 :                 return dyn_->prepare(n);
     423             :             }
     424             : 
     425          17 :             BOOST_ASSERT(
     426             :                 h_.md.payload == payload::to_eof);
     427          17 :             std::size_t n = 0;
     428          17 :             if(! got_eof_)
     429             :             {
     430             :                 // calculate n heuristically
     431          17 :                 n = svc_.cfg.min_buffer;
     432          17 :                 if( n > svc_.cfg.max_prepare)
     433           1 :                     n = svc_.cfg.max_prepare;
     434             :                 {
     435             :                     // apply max_size()
     436             :                     auto avail =
     437          17 :                         dyn_->max_size() -
     438          17 :                             dyn_->size();
     439          17 :                     if( n > avail)
     440           8 :                         n = avail;
     441             :                 }
     442             :                 // fill capacity() first,
     443             :                 // to avoid an allocation
     444             :                 {
     445             :                     auto avail = 
     446          17 :                         dyn_->capacity() -
     447          17 :                             dyn_->size();
     448          17 :                     if( n > avail &&
     449             :                             avail != 0)
     450           1 :                         n = avail;
     451             :                 }
     452          17 :                 if(n == 0)
     453             :                 {
     454             :                     // dynamic buffer is full
     455             :                     // attempt a 1 byte read so
     456             :                     // we can detect overflow
     457           2 :                     BOOST_ASSERT(
     458             :                         body_buf_->size() == 0);
     459             :                     // handled in init_dynamic
     460           2 :                     BOOST_ASSERT(
     461             :                         body_avail_ == 0);
     462           2 :                     mbp_ = body_buf_->prepare(1);
     463           2 :                     nprepare_ = 1;
     464             :                     return
     465           2 :                         mutable_buffers_type(mbp_);
     466             :                 }
     467             :             }
     468          15 :             nprepare_ = n;
     469          15 :             return dyn_->prepare(n);
     470             :         }
     471             : 
     472             :         // VFALCO TODO
     473           0 :         if(how_ == how::pull)
     474           0 :             detail::throw_logic_error();
     475             : 
     476             :         // VFALCO TODO
     477           0 :         detail::throw_logic_error();
     478             :     }
     479             : 
     480          27 :     case state::set_body:
     481             :     {
     482          27 :         BOOST_ASSERT(is_plain());
     483             : 
     484          27 :         if(how_ == how::dynamic)
     485             :         {
     486             :             // attempt to transfer in-place
     487             :             // body into the dynamic buffer.
     488          27 :             system::error_code ec;
     489          27 :             init_dynamic(ec);
     490          27 :             if(! ec.failed())
     491             :             {
     492          26 :                 if(st_ == state::body)
     493          24 :                     goto do_body;
     494           2 :                 BOOST_ASSERT(
     495             :                     st_ == state::complete);
     496           2 :                 return mutable_buffers_type{};
     497             :             }
     498             : 
     499             :             // not enough room, so we
     500             :             // return this error from parse()
     501             :             return
     502           1 :                 mutable_buffers_type{};
     503             :         }
     504             : 
     505           0 :         if(how_ == how::sink)
     506             :         {
     507             :             // this is a no-op, to get the
     508             :             // caller to call parse next.
     509           0 :             return mutable_buffers_type{};
     510             :         }
     511             : 
     512             :         // VFALCO TODO
     513           0 :         detail::throw_logic_error();
     514             :     }
     515             : 
     516           3 :     case state::complete:
     517             :         // intended no-op
     518           3 :         return mutable_buffers_type{};
     519             :     }
     520             : }
     521             : 
     522             : void
     523        4485 : parser::
     524             : commit(
     525             :     std::size_t n)
     526             : {
     527        4485 :     switch(st_)
     528             :     {
     529           1 :     default:
     530             :     case state::reset:
     531             :     {
     532             :         // reset must be called first
     533           1 :         detail::throw_logic_error();
     534             :     }
     535             : 
     536           1 :     case state::start:
     537             :     {
     538             :         // forgot to call start()
     539           1 :         detail::throw_logic_error();
     540             :     }
     541             : 
     542        4431 :     case state::header:
     543             :     {
     544        4431 :         if(n > nprepare_)
     545             :         {
     546             :             // n can't be greater than size of
     547             :             // the buffers returned by prepare()
     548           1 :             detail::throw_invalid_argument();
     549             :         }
     550             : 
     551        4430 :         if(got_eof_)
     552             :         {
     553             :             // can't commit after EOF
     554           1 :             detail::throw_logic_error();
     555             :         }
     556             : 
     557        4429 :         nprepare_ = 0; // invalidate
     558        4429 :         fb_.commit(n);
     559        4429 :         break;
     560             :     }
     561             : 
     562          46 :     case state::body:
     563             :     {
     564          46 :         if(n > nprepare_)
     565             :         {
     566             :             // n can't be greater than size of
     567             :             // the buffers returned by prepare()
     568           1 :             detail::throw_invalid_argument();
     569             :         }
     570             : 
     571          45 :         BOOST_ASSERT(! got_eof_ || n == 0);
     572             : 
     573          45 :         if(! is_plain())
     574             :         {
     575             :             // buffered payload
     576           0 :             cb0_.commit(n);
     577           0 :             break;
     578             :         }
     579             : 
     580             :         // plain payload
     581             : 
     582          45 :         if(how_ == how::in_place)
     583             :         {
     584          26 :             BOOST_ASSERT(body_buf_ == &cb0_);
     585          26 :             cb0_.commit(n);
     586          26 :             if(h_.md.payload == payload::size)
     587             :             {
     588          12 :                 if(cb0_.size() <
     589          12 :                     h_.md.payload_size)
     590             :                 {
     591           4 :                     body_avail_ += n;
     592           4 :                     payload_remain_ -= n;
     593           4 :                     break;
     594             :                 }
     595           8 :                 body_avail_ = h_.md.payload_size;
     596           8 :                 payload_remain_ = 0;
     597           8 :                 st_ = state::complete;
     598           8 :                 break;
     599             :             }
     600             : 
     601          14 :             BOOST_ASSERT(
     602             :                 h_.md.payload == payload::to_eof);
     603          14 :             body_avail_ += n;
     604          14 :             break;
     605             :         }
     606             : 
     607          19 :         if(how_ == how::dynamic)
     608             :         {
     609          19 :             if(dyn_->size() < dyn_->max_size())
     610             :             {
     611          18 :                 BOOST_ASSERT(body_avail_ == 0);
     612          18 :                 BOOST_ASSERT(
     613             :                     body_buf_->size() == 0);
     614          18 :                 dyn_->commit(n);
     615             :             }
     616             :             else
     617             :             {
     618             :                 // If we get here then either
     619             :                 // n==0 as a no-op, or n==1 for
     620             :                 // an intended one byte read.
     621           1 :                 BOOST_ASSERT(n <= 1);
     622           1 :                 body_buf_->commit(n);
     623           1 :                 body_avail_ += n;
     624             :             }
     625          19 :             body_total_ += n;
     626          19 :             if(h_.md.payload == payload::size)
     627             :             {
     628           6 :                 BOOST_ASSERT(
     629             :                     n <= payload_remain_);
     630           6 :                 payload_remain_ -= n;
     631           6 :                 if(payload_remain_ == 0)
     632           6 :                     st_ = state::complete;
     633             :             }
     634          19 :             break;
     635             :         }
     636             : 
     637           0 :         if(how_ == how::sink)
     638             :         {
     639           0 :             cb0_.commit(n);
     640           0 :             break;
     641             :         }
     642             : 
     643           0 :         if(how_ == how::pull)
     644             :         {
     645             :             // VFALCO TODO
     646           0 :             detail::throw_logic_error();
     647             :         }
     648           0 :         break;
     649             :     }
     650             : 
     651           2 :     case state::set_body:
     652             :     {
     653           2 :         if(n > nprepare_)
     654             :         {
     655             :             // n can't be greater than size of
     656             :             // the buffers returned by prepare()
     657           1 :             detail::throw_invalid_argument();
     658             :         }
     659             : 
     660           1 :         BOOST_ASSERT(is_plain());
     661           1 :         BOOST_ASSERT(n == 0);
     662           1 :         if( how_ == how::dynamic ||
     663           0 :             how_ == how::sink)
     664             :         {
     665             :             // intended no-op
     666             :             break;
     667             :         }
     668             : 
     669             :         // VFALCO TODO
     670           0 :         detail::throw_logic_error();
     671             :     }
     672             : 
     673           4 :     case state::complete:
     674             :     {
     675           4 :         BOOST_ASSERT(nprepare_ == 0);
     676             : 
     677           4 :         if(n > 0)
     678             :         {
     679             :             // n can't be greater than size of
     680             :             // the buffers returned by prepare()
     681           1 :             detail::throw_invalid_argument();
     682             :         }
     683             : 
     684             :         // intended no-op
     685           3 :         break;
     686             :     }
     687             :     }
     688        4478 : }
     689             : 
     690             : void
     691         363 : parser::
     692             : commit_eof()
     693             : {
     694         363 :     nprepare_ = 0; // invalidate
     695             : 
     696         363 :     switch(st_)
     697             :     {
     698           1 :     default:
     699             :     case state::reset:
     700             :         // reset must be called first
     701           1 :         detail::throw_logic_error();
     702             : 
     703           1 :     case state::start:
     704             :         // forgot to call prepare()
     705           1 :         detail::throw_logic_error();
     706             : 
     707          21 :     case state::header:
     708          21 :         got_eof_ = true;
     709          21 :         break;
     710             : 
     711         127 :     case state::body:
     712         127 :         got_eof_ = true;
     713         127 :         break;
     714             : 
     715         212 :     case state::set_body:
     716         212 :         got_eof_ = true;
     717         212 :         break;
     718             : 
     719           1 :     case state::complete:
     720             :         // can't commit eof when complete
     721           1 :         detail::throw_logic_error();
     722             :     }
     723         360 : }
     724             : 
     725             : //-----------------------------------------------
     726             : 
     727             : // process input data then
     728             : // eof if input data runs out.
     729             : void
     730        5407 : parser::
     731             : parse(
     732             :     system::error_code& ec)
     733             : {
     734        5407 :     ec = {};
     735        5407 :     switch(st_)
     736             :     {
     737           1 :     default:
     738             :     case state::reset:
     739             :         // reset must be called first
     740           1 :         detail::throw_logic_error();
     741             : 
     742           1 :     case state::start:
     743             :         // start must be called first
     744           1 :         detail::throw_logic_error();
     745             : 
     746        4445 :     case state::header:
     747             :     {
     748        4445 :         BOOST_ASSERT(h_.buf == static_cast<
     749             :             void const*>(ws_.data()));
     750        4445 :         BOOST_ASSERT(h_.cbuf == static_cast<
     751             :             void const*>(ws_.data()));
     752        4445 :         auto const new_size = fb_.size();
     753        4445 :         h_.parse(new_size, svc_.cfg.headers, ec);
     754        4445 :         if(ec == condition::need_more_input)
     755             :         {
     756        2990 :             if(! got_eof_)
     757             :             {
     758             :                 // headers incomplete
     759        2972 :                 return;
     760             :             }
     761             : 
     762          18 :             if(fb_.size() == 0)
     763             :             {
     764             :                 // stream closed cleanly
     765           8 :                 st_ = state::complete;
     766          16 :                 ec = BOOST_HTTP_PROTO_ERR(
     767             :                     error::end_of_stream);
     768           8 :                 return;
     769             :             }
     770             : 
     771             :             // stream closed with a
     772             :             // partial message received
     773          10 :             st_ = state::reset;
     774          20 :             ec = BOOST_HTTP_PROTO_ERR(
     775             :                 error::incomplete);
     776          10 :             return;
     777             :         }
     778        1455 :         if(ec.failed())
     779             :         {
     780             :             // other error,
     781             :             //
     782             :             // VFALCO map this to a bad
     783             :             // request or bad response error?
     784             :             //
     785         128 :             st_ = state::reset; // unrecoverable
     786         128 :             return;
     787             :         }
     788             : 
     789             :         // headers are complete
     790        1327 :         on_headers(ec);
     791        1327 :         if(ec.failed())
     792         120 :             return;
     793        1207 :         if(st_ == state::complete)
     794         722 :             break;
     795             :         BOOST_FALLTHROUGH;
     796             :     }
     797             : 
     798             :     case state::body:
     799             :     {
     800         485 :     do_body:
     801         744 :         BOOST_ASSERT(st_ == state::body);
     802         744 :         BOOST_ASSERT(
     803             :             h_.md.payload != payload::none);
     804         744 :         BOOST_ASSERT(
     805             :             h_.md.payload != payload::error);
     806         744 :         if(h_.md.payload == payload::chunked)
     807             :         {
     808             :             // VFALCO parse chunked
     809           0 :             detail::throw_logic_error();
     810             :         }
     811         744 :         else if(filt_)
     812             :         {
     813             :             // VFALCO TODO apply filter
     814           0 :             detail::throw_logic_error();
     815             :         }
     816             : 
     817         744 :         if(how_ == how::in_place)
     818             :         {
     819         618 :             BOOST_ASSERT(body_avail_ ==
     820             :                 body_buf_->size());
     821         618 :             if(h_.md.payload == payload::size)
     822             :             {
     823         255 :                 if(body_avail_ <
     824         255 :                     h_.md.payload_size)
     825             :                 {
     826          30 :                     if(got_eof_)
     827             :                     {
     828             :                         // incomplete
     829           2 :                         ec = BOOST_HTTP_PROTO_ERR(
     830             :                             error::incomplete);
     831           1 :                         return;
     832             :                     }
     833          29 :                     if(body_buf_->capacity() == 0)
     834             :                     {
     835             :                         // in_place buffer limit
     836           2 :                         ec = BOOST_HTTP_PROTO_ERR(
     837             :                             error::in_place_overflow);
     838           1 :                         return;
     839             :                     }
     840          56 :                     ec = BOOST_HTTP_PROTO_ERR(
     841             :                         error::need_data);
     842          28 :                     return;
     843             :                 }
     844         225 :                 BOOST_ASSERT(body_avail_ ==
     845             :                     h_.md.payload_size);
     846         225 :                 st_ = state::complete;
     847         225 :                 break;
     848             :             }
     849         363 :             if(body_avail_ > svc_.cfg.body_limit)
     850             :             {
     851           2 :                 ec = BOOST_HTTP_PROTO_ERR(
     852             :                     error::body_too_large);
     853           1 :                 st_ = state::reset; // unrecoverable
     854           1 :                 return;
     855             :             }
     856         362 :             if( h_.md.payload == payload::chunked ||
     857         362 :                 ! got_eof_)
     858             :             {
     859         496 :                 ec = BOOST_HTTP_PROTO_ERR(
     860             :                     error::need_data);
     861         248 :                 return;
     862             :             }
     863         114 :             BOOST_ASSERT(got_eof_);
     864         114 :             st_ = state::complete;
     865         114 :             break;
     866             :         }
     867             : 
     868         126 :         if(how_ == how::dynamic)
     869             :         {
     870             :             // state already updated in commit
     871         126 :             if(h_.md.payload == payload::size)
     872             :             {
     873           0 :                 BOOST_ASSERT(body_total_ <
     874             :                     h_.md.payload_size);
     875           0 :                 BOOST_ASSERT(payload_remain_ > 0);
     876           0 :                 if(body_avail_ != 0)
     877             :                 {
     878           0 :                     BOOST_ASSERT(
     879             :                         dyn_->max_size() -
     880             :                             dyn_->size() <
     881             :                         payload_remain_);
     882           0 :                     ec = BOOST_HTTP_PROTO_ERR(
     883             :                         error::buffer_overflow);
     884           0 :                     st_ = state::reset; // unrecoverable
     885           0 :                     return;
     886             :                 }
     887           0 :                 if(got_eof_)
     888             :                 {
     889           0 :                     ec = BOOST_HTTP_PROTO_ERR(
     890             :                         error::incomplete);
     891           0 :                     st_ = state::reset; // unrecoverable
     892           0 :                     return;
     893             :                 }
     894           0 :                 return;
     895             :             }
     896         126 :             BOOST_ASSERT(
     897             :                 h_.md.payload == payload::to_eof);
     898         172 :             if( dyn_->size() == dyn_->max_size() &&
     899          46 :                 body_avail_ > 0)
     900             :             {
     901             :                 // got here from the 1-byte read
     902           0 :                 ec = BOOST_HTTP_PROTO_ERR(
     903             :                     error::buffer_overflow);
     904           0 :                 st_ = state::reset; // unrecoverable
     905           0 :                 return;
     906             :             }
     907         126 :             if(got_eof_)
     908             :             {
     909         113 :                 BOOST_ASSERT(body_avail_ == 0);
     910         113 :                 st_ = state::complete;
     911         113 :                 break;
     912             :             }
     913          13 :             BOOST_ASSERT(body_avail_ == 0);
     914          13 :             break;
     915             :         }
     916             : 
     917             :         // VFALCO TODO
     918           0 :         detail::throw_logic_error();
     919             :     }
     920             : 
     921         211 :     case state::set_body:
     922             :     {
     923         211 :         BOOST_ASSERT(is_plain());
     924             : 
     925             :         // transfer in_place data into set body
     926             : 
     927         211 :         if(how_ == how::dynamic)
     928             :         {
     929         211 :             init_dynamic(ec);
     930         211 :             if(! ec.failed())
     931             :             {
     932         211 :                 if(st_ == state::body)
     933         102 :                     goto do_body;
     934         109 :                 BOOST_ASSERT(
     935             :                     st_ == state::complete);
     936         109 :                 break;
     937             :             }
     938           0 :             st_ = state::reset; // unrecoverable
     939           0 :             return;
     940             :         }
     941             : 
     942           0 :         if(how_ == how::sink)
     943             :         {
     944           0 :             auto n = body_buf_->size();
     945           0 :             if(h_.md.payload == payload::size)
     946             :             {
     947             :                 // sink_->size_hint(h_.md.payload_size, ec);
     948             : 
     949           0 :                 if(n < h_.md.payload_size)
     950             :                 {
     951           0 :                     auto rv = sink_->write(
     952           0 :                         body_buf_->data(), false);
     953           0 :                     BOOST_ASSERT(rv.ec.failed() ||
     954             :                         rv.bytes == body_buf_->size());
     955           0 :                     BOOST_ASSERT(
     956             :                         rv.bytes >= body_avail_);
     957           0 :                     BOOST_ASSERT(
     958             :                         rv.bytes < payload_remain_);
     959           0 :                     body_buf_->consume(rv.bytes);
     960           0 :                     body_avail_ -= rv.bytes;
     961           0 :                     body_total_ += rv.bytes;
     962           0 :                     payload_remain_ -= rv.bytes;
     963           0 :                     if(rv.ec.failed())
     964             :                     {
     965           0 :                         ec = rv.ec;
     966           0 :                         st_ = state::reset; // unrecoverable
     967           0 :                         return;
     968             :                     }
     969           0 :                     st_ = state::body;
     970           0 :                     goto do_body;
     971             :                 }
     972             : 
     973           0 :                 n = h_.md.payload_size;
     974             :             }
     975             :             // complete
     976           0 :             BOOST_ASSERT(body_buf_ == &cb0_);
     977           0 :             auto rv = sink_->write(
     978           0 :                 body_buf_->data(), true);
     979           0 :             BOOST_ASSERT(rv.ec.failed() ||
     980             :                 rv.bytes == body_buf_->size());
     981           0 :             body_buf_->consume(rv.bytes);
     982           0 :             if(rv.ec.failed())
     983             :             {
     984           0 :                 ec = rv.ec;
     985           0 :                 st_ = state::reset; // unrecoverable
     986           0 :                 return;
     987             :             }
     988           0 :             st_ = state::complete;
     989           0 :             return;
     990             :         }
     991             : 
     992             :         // VFALCO TODO
     993           0 :         detail::throw_logic_error();
     994             :     }
     995             : 
     996         592 :     case state::complete:
     997             :     {
     998             :         // This is a no-op except when set_body
     999             :         // was called and we have in-place data.
    1000         592 :         switch(how_)
    1001             :         {
    1002         296 :         default:
    1003             :         case how::in_place:
    1004         296 :             break;
    1005             : 
    1006         296 :         case how::dynamic:
    1007             :         {
    1008         296 :             if(body_buf_->size() == 0)
    1009         296 :                 break;
    1010           0 :             BOOST_ASSERT(dyn_->size() == 0);
    1011           0 :             auto n = buffers::buffer_copy(
    1012           0 :                 dyn_->prepare(
    1013           0 :                     body_buf_->size()),
    1014           0 :                 body_buf_->data());
    1015           0 :             body_buf_->consume(n);
    1016           0 :             break;
    1017             :         }
    1018             : 
    1019           0 :         case how::sink:
    1020             :         {
    1021           0 :             if(body_buf_->size() == 0)
    1022           0 :                 break;
    1023           0 :             auto rv = sink_->write(
    1024           0 :                 body_buf_->data(), false);
    1025           0 :             body_buf_->consume(rv.bytes);
    1026           0 :             if(rv.ec.failed())
    1027             :             {
    1028           0 :                 ec = rv.ec;
    1029           0 :                 st_ = state::reset; // unrecoverable
    1030           0 :                 return;
    1031             :             }
    1032           0 :             break;
    1033             :         }
    1034             : 
    1035           0 :         case how::pull:
    1036             :             // VFALCO TODO
    1037           0 :             detail::throw_logic_error();
    1038             :         }
    1039             :     }
    1040             :     }
    1041             : }
    1042             : 
    1043             : //------------------------------------------------
    1044             : 
    1045             : auto
    1046           0 : parser::
    1047             : pull_some() ->
    1048             :     const_buffers_type
    1049             : {
    1050           0 :     return {};
    1051             : }
    1052             : 
    1053             : core::string_view
    1054        1271 : parser::
    1055             : body() const noexcept
    1056             : {
    1057        1271 :     switch(st_)
    1058             :     {
    1059         349 :     default:
    1060             :     case state::reset:
    1061             :     case state::start:
    1062             :     case state::header:
    1063             :     case state::body:
    1064             :     case state::set_body:
    1065             :         // not complete
    1066         349 :         return {};
    1067             : 
    1068         922 :     case state::complete:
    1069         922 :         if(how_ != how::in_place)
    1070             :         {
    1071             :             // not in_place
    1072         346 :             return {};
    1073             :         }
    1074         576 :         auto cbp = body_buf_->data();
    1075         576 :         BOOST_ASSERT(cbp[1].size() == 0);
    1076         576 :         BOOST_ASSERT(cbp[0].size() >= body_avail_);
    1077         576 :         return core::string_view(
    1078             :             static_cast<char const*>(
    1079         576 :                 cbp[0].data()),
    1080        1152 :             body_avail_);
    1081             :     }
    1082             : }
    1083             : 
    1084             : core::string_view
    1085           0 : parser::
    1086             : release_buffered_data() noexcept
    1087             : {
    1088           0 :     return {};
    1089             : }
    1090             : 
    1091             : //------------------------------------------------
    1092             : //
    1093             : // Implementation
    1094             : //
    1095             : //------------------------------------------------
    1096             : 
    1097             : auto
    1098          55 : parser::
    1099             : safe_get_header() const ->
    1100             :     detail::header const*
    1101             : {
    1102             :     // headers must be received
    1103         110 :     if( ! got_header() ||
    1104          55 :         fb_.size() == 0) // happens on eof
    1105           0 :         detail::throw_logic_error();
    1106             : 
    1107          55 :     return &h_;
    1108             : }
    1109             : 
    1110             : bool
    1111         824 : parser::
    1112             : is_plain() const noexcept
    1113             : {
    1114        1648 :     return ! filt_ &&
    1115         824 :         h_.md.payload !=
    1116         824 :             payload::chunked;
    1117             : }
    1118             : 
    1119             : // Called immediately after complete headers
    1120             : // are received. We leave fb_ as-is to indicate
    1121             : // whether any data was received before eof.
    1122             : //
    1123             : void
    1124        1327 : parser::
    1125             : on_headers(
    1126             :     system::error_code& ec)
    1127             : {
    1128        1327 :     auto const overread = fb_.size() - h_.size;
    1129        1327 :     BOOST_ASSERT(
    1130             :         overread <= svc_.max_overread());
    1131             : 
    1132             :     // metadata error
    1133        1327 :     if(h_.md.payload == payload::error)
    1134             :     {
    1135             :         // VFALCO This needs looking at
    1136         240 :         ec = BOOST_HTTP_PROTO_ERR(
    1137             :             error::bad_payload);
    1138         120 :         st_ = state::reset; // unrecoverable
    1139         120 :         return;
    1140             :     }
    1141             : 
    1142             :     // reserve headers + table
    1143        1207 :     ws_.reserve_front(h_.size);
    1144        1207 :     ws_.reserve_back(h_.table_space());
    1145             : 
    1146             :     // no payload
    1147        1207 :     if( h_.md.payload == payload::none ||
    1148         485 :         head_response_)
    1149             :     {
    1150             :         // set cb0_ to overread
    1151        1444 :         cb0_ = {
    1152         722 :             ws_.data(),
    1153         722 :             fb_.capacity() - h_.size,
    1154             :             overread };
    1155         722 :         body_avail_ = 0;
    1156         722 :         body_total_ = 0;
    1157         722 :         body_buf_ = &cb0_;
    1158         722 :         st_ = state::complete;
    1159         722 :         return;
    1160             :     }
    1161             : 
    1162             :     // calculate filter
    1163         485 :     filt_ = nullptr; // VFALCO TODO
    1164             : 
    1165         485 :     if(is_plain())
    1166             :     {
    1167             :         // plain payload
    1168             : 
    1169         485 :         if(h_.md.payload == payload::size)
    1170             :         {
    1171         250 :             if(h_.md.payload_size >
    1172         250 :                 svc_.cfg.body_limit)
    1173             :             {
    1174           0 :                 ec = BOOST_HTTP_PROTO_ERR(
    1175             :                     error::body_too_large);
    1176           0 :                 st_ = state::reset; // unrecoverable
    1177           0 :                 return;
    1178             :             }
    1179             :             auto n0 =
    1180         250 :                 fb_.capacity() - h_.size +
    1181         250 :                 svc_.cfg.min_buffer +
    1182         250 :                 svc_.max_codec;
    1183             :             // limit the capacity of cb0_ so
    1184             :             // that going over max_overread
    1185             :             // is impossible.
    1186         499 :             if( n0 > h_.md.payload_size &&
    1187         249 :                 n0 - h_.md.payload_size >=
    1188         249 :                     svc_.max_overread())
    1189          14 :                 n0 = h_.md.payload_size +
    1190          14 :                     svc_.max_overread();
    1191         250 :             BOOST_ASSERT(n0 <= ws_.size());
    1192         250 :             cb0_ = { ws_.data(), n0, overread };
    1193         250 :             body_buf_ = &cb0_;
    1194         250 :             body_avail_ = cb0_.size();
    1195         250 :             if( body_avail_ >= h_.md.payload_size)
    1196         225 :                 body_avail_ = h_.md.payload_size;
    1197         250 :             body_total_ = body_avail_;
    1198         250 :             payload_remain_ =
    1199         250 :                 h_.md.payload_size - body_total_;
    1200         250 :             st_ = state::body;
    1201         250 :             return;
    1202             :         }
    1203             : 
    1204             :         // overread is not applicable
    1205         235 :         BOOST_ASSERT(
    1206             :             h_.md.payload == payload::to_eof);
    1207             :         auto const n0 =
    1208         235 :             fb_.capacity() - h_.size +
    1209         235 :             svc_.cfg.min_buffer +
    1210         235 :             svc_.max_codec;
    1211         235 :         BOOST_ASSERT(n0 <= ws_.size());
    1212         235 :         cb0_ = { ws_.data(), n0, overread };
    1213         235 :         body_buf_ = &cb0_;
    1214         235 :         body_avail_ = cb0_.size();
    1215         235 :         body_total_ = body_avail_;
    1216         235 :         st_ = state::body;
    1217         235 :         return;
    1218             :     }
    1219             : 
    1220             :     // buffered payload
    1221           0 :     auto const n0 = fb_.capacity() - h_.size;
    1222           0 :     BOOST_ASSERT(n0 <= svc_.max_overread());
    1223           0 :     auto n1 = svc_.cfg.min_buffer;
    1224           0 :     if(! filt_)
    1225           0 :         n1 += svc_.max_codec;
    1226           0 :     BOOST_ASSERT(n0 + n1 <= ws_.size());
    1227           0 :     cb0_ = { ws_.data(), n0, overread };
    1228           0 :     cb1_ = { ws_.data() + n0, n1 };
    1229           0 :     body_buf_ = &cb1_;
    1230           0 :     body_avail_ = 0;
    1231           0 :     body_total_ = 0;
    1232           0 :     st_ = state::body;
    1233             : }
    1234             : 
    1235             : // Called at the end of set_body
    1236             : void
    1237         299 : parser::
    1238             : on_set_body()
    1239             : {
    1240             :     // This function is called after all
    1241             :     // limit checking and calculation of
    1242             :     // chunked or filter.
    1243             : 
    1244         299 :     BOOST_ASSERT(got_header());
    1245             : 
    1246         299 :     nprepare_ = 0; // invalidate
    1247             :  
    1248         299 :     if(how_ == how::dynamic)
    1249             :     {
    1250         299 :         if(h_.md.payload == payload::none)
    1251             :         {
    1252          58 :             BOOST_ASSERT(st_ == state::complete);
    1253          58 :             return;
    1254             :         }
    1255             : 
    1256         241 :         st_ = state::set_body;
    1257         241 :         return;
    1258             :     }
    1259             : 
    1260           0 :     if(how_ == how::sink)
    1261             :     {
    1262           0 :         if(h_.md.payload == payload::none)
    1263             :         {
    1264           0 :             BOOST_ASSERT(st_ == state::complete);
    1265             :             // force a trip through parse so
    1266             :             // we can calculate any error.
    1267           0 :             st_ = state::set_body;
    1268           0 :             return;
    1269             :         }
    1270             : 
    1271           0 :         st_ = state::set_body;
    1272           0 :         return;
    1273             :     }
    1274             : 
    1275             :     // VFALCO TODO
    1276           0 :     detail::throw_logic_error();
    1277             : }
    1278             : 
    1279             : void
    1280         238 : parser::
    1281             : init_dynamic(
    1282             :     system::error_code& ec)
    1283             : {
    1284             :     // attempt to transfer in-place
    1285             :     // body into the dynamic buffer.
    1286         238 :     BOOST_ASSERT(
    1287             :         body_avail_ == body_buf_->size());
    1288         238 :     BOOST_ASSERT(
    1289             :         body_total_ == body_avail_);
    1290             :     auto const space_left =
    1291         238 :         dyn_->max_size() - dyn_->size();
    1292             : 
    1293         238 :     if(h_.md.payload == payload::size)
    1294             :     {
    1295         121 :         if(space_left < h_.md.payload_size)
    1296             :         {
    1297           2 :             ec = BOOST_HTTP_PROTO_ERR(
    1298             :                 error::buffer_overflow);
    1299           1 :             return;
    1300             :         }
    1301             :         // reserve the full size
    1302         120 :         dyn_->prepare(h_.md.payload_size);
    1303             :         // transfer in-place body
    1304         120 :         auto n = body_avail_;
    1305         120 :         if( n > h_.md.payload_size)
    1306           0 :             n = h_.md.payload_size;
    1307         120 :         dyn_->commit(
    1308             :             buffers::buffer_copy(
    1309         120 :                 dyn_->prepare(n),
    1310         120 :                 body_buf_->data()));
    1311         120 :         BOOST_ASSERT(body_avail_ == n);
    1312         120 :         BOOST_ASSERT(body_total_ == n);
    1313         120 :         BOOST_ASSERT(payload_remain_ ==
    1314             :             h_.md.payload_size - n);
    1315         120 :         body_buf_->consume(n);
    1316         120 :         body_avail_ = 0;
    1317         120 :         if(n < h_.md.payload_size)
    1318             :         {
    1319           9 :             BOOST_ASSERT(
    1320             :                 body_buf_->size() == 0);
    1321           9 :             st_ = state::body;
    1322           9 :             return;
    1323             :         }
    1324             :         // complete
    1325         111 :         st_ = state::complete;
    1326         111 :         return;
    1327             :     }
    1328             : 
    1329         117 :     BOOST_ASSERT(h_.md.payload ==
    1330             :         payload::to_eof);
    1331         117 :     if(space_left < body_avail_)
    1332             :     {
    1333           0 :         ec = BOOST_HTTP_PROTO_ERR(
    1334             :             error::buffer_overflow);
    1335           0 :         return;
    1336             :     }
    1337         117 :     dyn_->commit(
    1338             :         buffers::buffer_copy(
    1339         117 :             dyn_->prepare(body_avail_),
    1340         117 :             body_buf_->data()));
    1341         117 :     body_buf_->consume(body_avail_);
    1342         117 :     body_avail_ = 0;
    1343         117 :     BOOST_ASSERT(
    1344             :         body_buf_->size() == 0);
    1345         117 :     st_ = state::body;
    1346             : }
    1347             : 
    1348             : } // http_proto
    1349             : } // boost
    1350             : 
    1351             : #endif

Generated by: LCOV version 1.15