LCOV - code coverage report
Current view: top level - libs/http_proto/src/detail/header.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 94.1 % 596 561
Test Date: 2024-07-03 18:58:30 Functions: 83.9 % 56 47

            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              : #include <boost/http_proto/detail/header.hpp>
      11              : #include <boost/http_proto/detail/align_up.hpp>
      12              : #include <boost/http_proto/field.hpp>
      13              : #include <boost/http_proto/fields_view_base.hpp>
      14              : #include <boost/http_proto/header_limits.hpp>
      15              : #include <boost/http_proto/rfc/list_rule.hpp>
      16              : #include <boost/http_proto/rfc/token_rule.hpp>
      17              : #include <boost/http_proto/rfc/upgrade_rule.hpp>
      18              : #include <boost/http_proto/rfc/detail/rules.hpp>
      19              : #include <boost/url/grammar/ci_string.hpp>
      20              : #include <boost/url/grammar/parse.hpp>
      21              : #include <boost/url/grammar/range_rule.hpp>
      22              : #include <boost/url/grammar/recycled.hpp>
      23              : #include <boost/url/grammar/unsigned_rule.hpp>
      24              : #include <boost/assert.hpp>
      25              : #include <boost/assert/source_location.hpp>
      26              : #include <boost/static_assert.hpp>
      27              : #include <string>
      28              : #include <utility>
      29              : 
      30              : #include "../rfc/transfer_encoding_rule.hpp"
      31              : 
      32              : namespace boost {
      33              : namespace http_proto {
      34              : namespace detail {
      35              : 
      36              : //------------------------------------------------
      37              : 
      38              : auto
      39          115 : header::
      40              : entry::
      41              : operator+(
      42              :     std::size_t dv) const noexcept ->
      43              :         entry
      44              : {
      45              :     return {
      46              :         static_cast<
      47          115 :             offset_type>(np + dv),
      48          115 :         nn,
      49              :         static_cast<
      50          115 :             offset_type>(vp + dv),
      51          115 :         vn,
      52          115 :         id };
      53              : }
      54              : 
      55              : auto
      56           79 : header::
      57              : entry::
      58              : operator-(
      59              :     std::size_t dv) const noexcept ->
      60              :         entry
      61              : {
      62              :     return {
      63              :         static_cast<
      64           79 :             offset_type>(np - dv),
      65           79 :         nn,
      66              :         static_cast<
      67           79 :             offset_type>(vp - dv),
      68           79 :         vn,
      69           79 :         id };
      70              : }
      71              : 
      72              : //------------------------------------------------
      73              : 
      74              : constexpr
      75              : header::
      76              : header(fields_tag) noexcept
      77              :     : kind(detail::kind::fields)
      78              :     , cbuf("\r\n")
      79              :     , size(2)
      80              :     , fld{}
      81              : {
      82              : }
      83              : 
      84              : constexpr
      85              : header::
      86              : header(request_tag) noexcept
      87              :     : kind(detail::kind::request)
      88              :     , cbuf("GET / HTTP/1.1\r\n\r\n")
      89              :     , size(18)
      90              :     , prefix(16)
      91              :     , req{ 3, 1,
      92              :         http_proto::method::get }
      93              : {
      94              : }
      95              : 
      96              : constexpr
      97              : header::
      98              : header(response_tag) noexcept
      99              :     : kind(detail::kind::response)
     100              :     , cbuf("HTTP/1.1 200 OK\r\n\r\n")
     101              :     , size(19)
     102              :     , prefix(17)
     103              :     , res{ 200,
     104              :         http_proto::status::ok }
     105              : {
     106              : }
     107              : 
     108              : //------------------------------------------------
     109              : 
     110              : header const*
     111          249 : header::
     112              : get_default(detail::kind k) noexcept
     113              : {
     114              :     static constexpr header h[3] = {
     115              :         fields_tag{},
     116              :         request_tag{},
     117              :         response_tag{}};
     118          249 :     return &h[k];
     119              : }
     120              : 
     121         3314 : header::
     122         3314 : header(empty v) noexcept
     123         3314 :     : kind(v.param)
     124              : {
     125         3314 : }
     126              : 
     127          230 : header::
     128          230 : header(detail::kind k) noexcept
     129          230 :     : header(*get_default(k))
     130              : {
     131          230 : }
     132              : 
     133              : void
     134           74 : header::
     135              : swap(header& h) noexcept
     136              : {
     137           74 :     std::swap(cbuf, h.cbuf);
     138           74 :     std::swap(buf, h.buf);
     139           74 :     std::swap(cap, h.cap);
     140           74 :     std::swap(max_cap, h.max_cap);
     141           74 :     std::swap(size, h.size);
     142           74 :     std::swap(count, h.count);
     143           74 :     std::swap(prefix, h.prefix);
     144           74 :     std::swap(version, h.version);
     145           74 :     std::swap(md, h.md);
     146           74 :     switch(kind)
     147              :     {
     148           18 :     default:
     149              :     case detail::kind::fields:
     150           18 :         break;
     151           47 :     case detail::kind::request:
     152           47 :         std::swap(
     153           47 :             req.method_len, h.req.method_len);
     154           47 :         std::swap(
     155           47 :             req.target_len, h.req.target_len);
     156           47 :         std::swap(req.method, h.req.method);
     157           47 :         break;
     158            9 :     case detail::kind::response:
     159            9 :         std::swap(
     160            9 :             res.status_int, h.res.status_int);
     161            9 :         std::swap(res.status, h.res.status);
     162            9 :         break;
     163              :     }
     164           74 : }
     165              : 
     166              : /*  References:
     167              : 
     168              :     6.3.  Persistence
     169              :     https://datatracker.ietf.org/doc/html/rfc7230#section-6.3
     170              : */
     171              : bool
     172           22 : header::
     173              : keep_alive() const noexcept
     174              : {
     175           22 :     if(md.payload == payload::error)
     176            1 :         return false;
     177           21 :     if( version ==
     178              :         http_proto::version::http_1_1)
     179              :     {
     180           13 :         if(md.connection.close)
     181            3 :             return false;
     182              :     }
     183              :     else
     184              :     {
     185            8 :         if(! md.connection.keep_alive)
     186            4 :             return false;
     187              :     }
     188              :     // can't use to_eof in requests
     189           14 :     BOOST_ASSERT(
     190              :         kind != detail::kind::request ||
     191              :         md.payload != payload::to_eof);
     192           14 :     if(md.payload == payload::to_eof)
     193            3 :         return false;
     194           11 :     return true;
     195              : }
     196              : 
     197              : //------------------------------------------------
     198              : 
     199              : // return total bytes needed
     200              : // to store message of `size`
     201              : // bytes and `count` fields.
     202              : std::size_t
     203          904 : header::
     204              : bytes_needed(
     205              :     std::size_t size,
     206              :     std::size_t count) noexcept
     207              : {
     208              :     // make sure `size` is big enough
     209              :     // to hold the largest default buffer:
     210              :     // "HTTP/1.1 200 OK\r\n\r\n"
     211          904 :     if( size < 19)
     212          172 :         size = 19;
     213              :     static constexpr auto A =
     214              :         alignof(header::entry);
     215          904 :     return align_up(size, A) +
     216          904 :             (count * sizeof(
     217          904 :                 header::entry));
     218              : }
     219              : 
     220              : std::size_t
     221         1329 : header::
     222              : table_space(
     223              :     std::size_t count) noexcept
     224              : {
     225              :     return count *
     226         1329 :         sizeof(header::entry);
     227              : }
     228              : 
     229              : std::size_t
     230         1329 : header::
     231              : table_space() const noexcept
     232              : {
     233         1329 :     return table_space(count);
     234              : }
     235              : 
     236              : auto
     237         2732 : header::
     238              : tab() const noexcept ->
     239              :     table
     240              : {
     241         2732 :     BOOST_ASSERT(cap > 0);
     242         2732 :     BOOST_ASSERT(buf != nullptr);
     243         2732 :     return table(buf + cap);
     244              : }
     245              : 
     246              : auto
     247          857 : header::
     248              : tab_() const noexcept ->
     249              :     entry*
     250              : {
     251              :     return reinterpret_cast<
     252          857 :         entry*>(buf + cap);
     253              : }
     254              : 
     255              : // return true if header cbuf is a default
     256              : bool
     257           43 : header::
     258              : is_default() const noexcept
     259              : {
     260           43 :     return buf == nullptr;
     261              : }
     262              : 
     263              : std::size_t
     264          138 : header::
     265              : find(
     266              :     field id) const noexcept
     267              : {
     268          138 :     if(count == 0)
     269            6 :         return 0;
     270          132 :     std::size_t i = 0;
     271          132 :     auto const* p = &tab()[0];
     272          153 :     while(i < count)
     273              :     {
     274          153 :         if(p->id == id)
     275          132 :             break;
     276           21 :         ++i;
     277           21 :         --p;
     278              :     }
     279          132 :     return i;
     280              : }
     281              : 
     282              : std::size_t
     283           68 : header::
     284              : find(
     285              :     core::string_view name) const noexcept
     286              : {
     287           68 :     if(count == 0)
     288           53 :         return 0;
     289           15 :     std::size_t i = 0;
     290           15 :     auto const* p = &tab()[0];
     291           21 :     while(i < count)
     292              :     {
     293              :         core::string_view s(
     294           21 :             cbuf + prefix + p->np,
     295           21 :             p->nn);
     296           21 :         if(grammar::ci_is_equal(s, name))
     297           15 :             break;
     298            6 :         ++i;
     299            6 :         --p;
     300              :     }
     301           15 :     return i;
     302              : }
     303              : 
     304              : void
     305           30 : header::
     306              : copy_table(
     307              :     void* dest,
     308              :     std::size_t n) const noexcept
     309              : {
     310           30 :     std::memcpy(
     311              :         reinterpret_cast<
     312           30 :             entry*>(dest) - n,
     313              :         reinterpret_cast<
     314              :             entry const*>(
     315           30 :                 cbuf + cap) - n,
     316              :         n * sizeof(entry));
     317           30 : }
     318              : 
     319              : void
     320           30 : header::
     321              : copy_table(
     322              :     void* dest) const noexcept
     323              : {
     324           30 :     copy_table(dest, count);
     325           30 : }
     326              : 
     327              : // assign all the members but
     328              : // preserve the allocated memory
     329              : void
     330           30 : header::
     331              : assign_to(
     332              :     header& dest) const noexcept
     333              : {
     334           30 :     auto const buf_ = dest.buf;
     335           30 :     auto const cbuf_ = dest.cbuf;
     336           30 :     auto const cap_ = dest.cap;
     337           30 :     dest = *this;
     338           30 :     dest.buf = buf_;
     339           30 :     dest.cbuf = cbuf_;
     340           30 :     dest.cap = cap_;
     341           30 : }
     342              : 
     343              : //------------------------------------------------
     344              : //
     345              : // Metadata
     346              : //
     347              : //------------------------------------------------
     348              : 
     349              : std::size_t
     350            0 : header::
     351              : maybe_count(
     352              :     field id) const noexcept
     353              : {
     354            0 :     if(kind == detail::kind::fields)
     355            0 :         return std::size_t(-1);
     356            0 :     switch(id)
     357              :     {
     358            0 :     case field::connection:
     359            0 :         return md.connection.count;
     360            0 :     case field::content_length:
     361            0 :         return md.content_length.count;
     362            0 :     case field::expect:
     363            0 :         return md.expect.count;
     364            0 :     case field::transfer_encoding:
     365            0 :         return md.transfer_encoding.count;
     366            0 :     case field::upgrade:
     367            0 :         return md.upgrade.count;
     368            0 :     default:
     369            0 :         break;
     370              :     }
     371            0 :     return std::size_t(-1);
     372              : }
     373              : 
     374              : bool
     375           21 : header::
     376              : is_special(
     377              :     field id) const noexcept
     378              : {
     379           21 :     if(kind == detail::kind::fields)
     380            4 :         return false;
     381           17 :     switch(id)
     382              :     {
     383            9 :     case field::connection:
     384              :     case field::content_length:
     385              :     case field::expect:
     386              :     case field::transfer_encoding:
     387              :     case field::upgrade:
     388            9 :         return true;
     389            8 :     default:
     390            8 :         break;
     391              :     }
     392            8 :     return false;
     393              : }
     394              : 
     395              : //------------------------------------------------
     396              : 
     397              : // called when the start-line changes
     398              : void
     399         2033 : header::
     400              : on_start_line()
     401              : {
     402              :     // items in both the request-line
     403              :     // and the status-line can affect
     404              :     // the payload, for example whether
     405              :     // or not EOF marks the end of the
     406              :     // payload.
     407              : 
     408         2033 :     update_payload();
     409         2033 : }
     410              : 
     411              : // called after a field is inserted
     412              : void
     413         2987 : header::
     414              : on_insert(
     415              :     field id,
     416              :     core::string_view v)
     417              : {
     418         2987 :     if(kind == detail::kind::fields)
     419          510 :         return;
     420         2477 :     switch(id)
     421              :     {
     422          590 :     case field::content_length:
     423          590 :         return on_insert_content_length(v);
     424          147 :     case field::connection:
     425          147 :         return on_insert_connection(v);
     426           47 :     case field::expect:
     427           47 :         return on_insert_expect(v);
     428          119 :     case field::transfer_encoding:
     429          119 :         return on_insert_transfer_encoding();
     430           24 :     case field::upgrade:
     431           24 :         return on_insert_upgrade(v);
     432         1550 :     default:
     433         1550 :         break;
     434              :     }
     435              : }
     436              : 
     437              : // called when one field is erased
     438              : void
     439           40 : header::
     440              : on_erase(field id)
     441              : {
     442           40 :     if(kind == detail::kind::fields)
     443            3 :         return;
     444           37 :     switch(id)
     445              :     {
     446            9 :     case field::connection:
     447            9 :         return on_erase_connection();
     448            4 :     case field::content_length:
     449            4 :         return on_erase_content_length();
     450           10 :     case field::expect:
     451           10 :         return on_erase_expect();
     452            5 :     case field::transfer_encoding:
     453            5 :         return on_erase_transfer_encoding();
     454            4 :     case field::upgrade:
     455            4 :         return on_erase_upgrade();
     456            5 :     default:
     457            5 :         break;
     458              :     }
     459              : }
     460              : 
     461              : //------------------------------------------------
     462              : 
     463              : /*
     464              :     https://datatracker.ietf.org/doc/html/rfc7230#section-6.1
     465              : */
     466              : void
     467          151 : header::
     468              : on_insert_connection(
     469              :     core::string_view v)
     470              : {
     471          151 :     ++md.connection.count;
     472          151 :     if(md.connection.ec.failed())
     473            5 :         return;
     474              :     auto rv = grammar::parse(
     475          150 :         v, list_rule(token_rule, 1));
     476          150 :     if(! rv)
     477              :     {
     478            4 :         md.connection.ec =
     479            8 :             BOOST_HTTP_PROTO_ERR(
     480              :                 error::bad_connection);
     481            4 :         return;
     482              :     }
     483          146 :     md.connection.ec = {};
     484          303 :     for(auto t : *rv)
     485              :     {
     486          157 :         if(grammar::ci_is_equal(
     487              :                 t, "close"))
     488          107 :             md.connection.close = true;
     489           50 :         else if(grammar::ci_is_equal(
     490              :                 t, "keep-alive"))
     491           26 :             md.connection.keep_alive = true;
     492           24 :         else if(grammar::ci_is_equal(
     493              :                 t, "upgrade"))
     494           19 :             md.connection.upgrade = true;
     495              :     }
     496          150 : }
     497              : 
     498              : void
     499          591 : header::
     500              : on_insert_content_length(
     501              :     core::string_view v)
     502              : {
     503              :     static
     504              :     constexpr
     505              :     grammar::unsigned_rule<
     506              :         std::uint64_t> num_rule{};
     507              : 
     508          591 :     ++md.content_length.count;
     509          591 :     if(md.content_length.ec.failed())
     510          468 :         return;
     511              :     auto rv =
     512          589 :         grammar::parse(v, num_rule);
     513          589 :     if(! rv)
     514              :     {
     515              :         // parse failure
     516            5 :         md.content_length.ec =
     517           10 :             BOOST_HTTP_PROTO_ERR(
     518              :             error::bad_content_length);
     519            5 :         md.content_length.value = 0;
     520            5 :         update_payload();
     521            5 :         return;
     522              :     }
     523          584 :     if(md.content_length.count == 1)
     524              :     {
     525              :         // one value
     526          454 :         md.content_length.ec = {};
     527          454 :         md.content_length.value = *rv;
     528          454 :         update_payload();
     529          454 :         return;
     530              :     }
     531          130 :     if(*rv == md.content_length.value)
     532              :     {
     533              :         // ok: duplicate value
     534            7 :         return;
     535              :     }
     536              :     // bad: different values
     537          123 :     md.content_length.ec =
     538          246 :         BOOST_HTTP_PROTO_ERR(
     539              :             error::multiple_content_length);
     540          123 :     md.content_length.value = 0;
     541          123 :     update_payload();
     542              : }
     543              : 
     544              : void
     545           53 : header::
     546              : on_insert_expect(
     547              :     core::string_view v)
     548              : {
     549           53 :     ++md.expect.count;
     550           53 :     if(kind != detail::kind::request)
     551            8 :         return;
     552           45 :     if(md.expect.ec.failed())
     553            4 :         return;
     554              :     // VFALCO Should we allow duplicate
     555              :     // Expect fields that have 100-continue?
     556           73 :     if( md.expect.count > 1 ||
     557           73 :         ! grammar::ci_is_equal(v,
     558              :             "100-continue"))
     559              :     {
     560           19 :         md.expect.ec =
     561           38 :             BOOST_HTTP_PROTO_ERR(
     562              :                 error::bad_expect);
     563           19 :         md.expect.is_100_continue = false;
     564           19 :         return;
     565              :     }
     566           22 :     md.expect.is_100_continue = true;
     567              : }
     568              : 
     569              : void
     570          122 : header::
     571              : on_insert_transfer_encoding()
     572              : {
     573          122 :     ++md.transfer_encoding.count;
     574          122 :     if(md.transfer_encoding.ec.failed())
     575            5 :         return;
     576          117 :     auto const n =
     577              :         md.transfer_encoding.count;
     578          117 :     md.transfer_encoding = {};
     579          117 :     md.transfer_encoding.count = n;
     580          117 :     for(auto s :
     581              :         fields_view_base::subrange(
     582          372 :             this, find(field::transfer_encoding)))
     583              :     {
     584              :         auto rv = grammar::parse(
     585          149 :             s, transfer_encoding_rule);
     586          149 :         if(! rv)
     587              :         {
     588              :             // parse error
     589            4 :             md.transfer_encoding.ec =
     590            8 :                 BOOST_HTTP_PROTO_ERR(
     591              :                     error::bad_transfer_encoding);
     592            4 :             md.transfer_encoding.codings = 0;
     593            4 :             md.transfer_encoding.is_chunked = false;
     594            4 :             update_payload();
     595            4 :             return;
     596              :         }
     597          145 :         md.transfer_encoding.codings += rv->size();
     598          292 :         for(auto t : *rv)
     599              :         {
     600          154 :             auto& mte = md.transfer_encoding;
     601              : 
     602          154 :             if(! mte.is_chunked )
     603              :             {
     604          150 :                 if( t.id == transfer_encoding::chunked )
     605              :                 {
     606           49 :                     mte.is_chunked = true;
     607           49 :                     continue;
     608              :                 }
     609              : 
     610          101 :                 auto b =
     611          101 :                     mte.encoding ==
     612              :                     http_proto::encoding::identity;
     613              : 
     614          101 :                 if( t.id == transfer_encoding::deflate )
     615           37 :                     mte.encoding = http_proto::encoding::deflate;
     616              : 
     617          101 :                 if( t.id == transfer_encoding::gzip )
     618           43 :                     mte.encoding = http_proto::encoding::gzip;
     619              : 
     620          101 :                 if( b )
     621           98 :                     continue;
     622              :             }
     623            7 :             if(t.id == transfer_encoding::chunked)
     624              :             {
     625              :                 // chunked appears twice
     626            2 :                 md.transfer_encoding.ec =
     627            4 :                     BOOST_HTTP_PROTO_ERR(
     628              :                         error::bad_transfer_encoding);
     629            2 :                 md.transfer_encoding.codings = 0;
     630            2 :                 md.transfer_encoding.is_chunked = false;
     631            2 :                 md.transfer_encoding.encoding =
     632              :                     http_proto::encoding::identity;
     633            2 :                 update_payload();
     634            2 :                 return;
     635              :             }
     636              :             // chunked must be last
     637            5 :             md.transfer_encoding.ec =
     638           10 :                 BOOST_HTTP_PROTO_ERR(
     639              :                     error::bad_transfer_encoding);
     640            5 :             md.transfer_encoding.codings = 0;
     641            5 :             md.transfer_encoding.is_chunked = false;
     642            5 :             md.transfer_encoding.encoding =
     643              :                 http_proto::encoding::identity;
     644            5 :             update_payload();
     645            5 :             return;
     646          306 :         }
     647          149 :     }
     648          106 :     update_payload();
     649              : }
     650              : 
     651              : void
     652           26 : header::
     653              : on_insert_upgrade(
     654              :     core::string_view v)
     655              : {
     656           26 :     ++md.upgrade.count;
     657           26 :     if(md.upgrade.ec.failed())
     658            5 :         return;
     659           25 :     if( version !=
     660              :         http_proto::version::http_1_1)
     661              :     {
     662            1 :         md.upgrade.ec =
     663            2 :             BOOST_HTTP_PROTO_ERR(
     664              :                 error::bad_upgrade);
     665            1 :         md.upgrade.websocket = false;
     666            1 :         return;
     667              :     }
     668              :     auto rv = grammar::parse(
     669           24 :         v, upgrade_rule);
     670           24 :     if(! rv)
     671              :     {
     672            3 :         md.upgrade.ec =
     673            6 :             BOOST_HTTP_PROTO_ERR(
     674              :                 error::bad_upgrade);
     675            3 :         md.upgrade.websocket = false;
     676            3 :         return;
     677              :     }
     678           21 :     if(! md.upgrade.websocket)
     679              :     {
     680           23 :         for(auto t : *rv)
     681              :         {
     682           16 :             if( grammar::ci_is_equal(
     683           26 :                     t.name, "websocket") &&
     684           10 :                 t.version.empty())
     685              :             {
     686            9 :                 md.upgrade.websocket = true;
     687            9 :                 break;
     688              :             }
     689              :         }
     690              :     }
     691           24 : }
     692              : 
     693              : //------------------------------------------------
     694              : 
     695              : void
     696            9 : header::
     697              : on_erase_connection()
     698              : {
     699            9 :     BOOST_ASSERT(
     700              :         md.connection.count > 0);
     701              :     // reset and re-insert
     702            9 :     auto n = md.connection.count - 1;
     703            9 :     auto const p = cbuf + prefix;
     704            9 :     auto const* e = &tab()[0];
     705            9 :     md.connection = {};
     706           14 :     while(n > 0)
     707              :     {
     708            5 :         if(e->id == field::connection)
     709            4 :             on_insert_connection(
     710              :                 core::string_view(
     711            4 :                     p + e->vp, e->vn));
     712            5 :         --n;
     713            5 :         --e;
     714              :     }
     715            9 : }
     716              : 
     717              : void
     718            4 : header::
     719              : on_erase_content_length()
     720              : {
     721            4 :     BOOST_ASSERT(
     722              :         md.content_length.count > 0);
     723            4 :     --md.content_length.count;
     724            4 :     if(md.content_length.count == 0)
     725              :     {
     726              :         // no Content-Length
     727            1 :         md.content_length = {};
     728            1 :         update_payload();
     729            1 :         return;
     730              :     }
     731            3 :     if(! md.content_length.ec.failed())
     732              :     {
     733              :         // removing a duplicate value
     734            2 :         return;
     735              :     }
     736              :     // reset and re-insert
     737            1 :     auto n = md.content_length.count;
     738            1 :     auto const p = cbuf + prefix;
     739            1 :     auto const* e = &tab()[0];
     740            1 :     md.content_length = {};
     741            2 :     while(n > 0)
     742              :     {
     743            1 :         if(e->id == field::content_length)
     744            1 :             on_insert_content_length(
     745              :                 core::string_view(
     746            1 :                     p + e->vp, e->vn));
     747            1 :         --n;
     748            1 :         --e;
     749              :     }
     750            1 :     update_payload();
     751              : }
     752              : 
     753              : void
     754           10 : header::
     755              : on_erase_expect()
     756              : {
     757           10 :     BOOST_ASSERT(
     758              :         md.expect.count > 0);
     759           10 :     --md.expect.count;
     760           10 :     if(kind != detail::kind::request)
     761            1 :         return;
     762            9 :     if(md.expect.count == 0)
     763              :     {
     764              :         // no Expect
     765            3 :         md.expect = {};
     766            3 :         return;
     767              :     }
     768              :     // VFALCO This should be uncommented
     769              :     // if we want to allow multiple Expect
     770              :     // fields with the value 100-continue
     771              :     /*
     772              :     if(! md.expect.ec.failed())
     773              :         return;
     774              :     */
     775              :     // reset and re-insert
     776            6 :     auto n = count;
     777            6 :     auto const p = cbuf + prefix;
     778            6 :     auto const* e = &tab()[0];
     779            6 :     md.expect = {};
     780           19 :     while(n > 0)
     781              :     {
     782           13 :         if(e->id == field::expect)
     783            6 :             on_insert_expect(
     784              :                 core::string_view(
     785            6 :                     p + e->vp, e->vn));
     786           13 :         --n;
     787           13 :         --e;
     788              :     }
     789              : }
     790              : 
     791              : void
     792            5 : header::
     793              : on_erase_transfer_encoding()
     794              : {
     795            5 :     BOOST_ASSERT(
     796              :         md.transfer_encoding.count > 0);
     797            5 :     --md.transfer_encoding.count;
     798            5 :     if(md.transfer_encoding.count == 0)
     799              :     {
     800              :         // no Transfer-Encoding
     801            2 :         md.transfer_encoding = {};
     802            2 :         update_payload();
     803            2 :         return;
     804              :     }
     805              :     // re-insert everything
     806            3 :     --md.transfer_encoding.count;
     807            3 :     on_insert_transfer_encoding();
     808              : }
     809              : 
     810              : // called when Upgrade is erased
     811              : void
     812            4 : header::
     813              : on_erase_upgrade()
     814              : {
     815            4 :     BOOST_ASSERT(
     816              :         md.upgrade.count > 0);
     817            4 :     --md.upgrade.count;
     818            4 :     if(md.upgrade.count == 0)
     819              :     {
     820              :         // no Upgrade
     821            2 :         md.upgrade = {};
     822            2 :         return;
     823              :     }
     824              :     // reset and re-insert
     825            2 :     auto n = md.upgrade.count;
     826            2 :     auto const p = cbuf + prefix;
     827            2 :     auto const* e = &tab()[0];
     828            2 :     md.upgrade = {};
     829            4 :     while(n > 0)
     830              :     {
     831            2 :         if(e->id == field::upgrade)
     832            2 :             on_insert_upgrade(
     833              :                 core::string_view(
     834            2 :                     p + e->vp, e->vn));
     835            2 :         --n;
     836            2 :         --e;
     837              :     }
     838              : }
     839              : 
     840              : //------------------------------------------------
     841              : 
     842              : // called when all fields with id are removed
     843              : void
     844           60 : header::
     845              : on_erase_all(
     846              :     field id)
     847              : {
     848           60 :     if(kind == detail::kind::fields)
     849           17 :         return;
     850           43 :     switch(id)
     851              :     {
     852            3 :     case field::connection:
     853            3 :         md.connection = {};
     854            3 :         return;
     855              : 
     856            2 :     case field::content_length:
     857            2 :         md.content_length = {};
     858            2 :         update_payload();
     859            2 :         return;
     860              : 
     861            5 :     case field::expect:
     862            5 :         md.expect = {};
     863            5 :         update_payload();
     864            5 :         return;
     865              : 
     866            1 :     case field::transfer_encoding:
     867            1 :         md.transfer_encoding = {};
     868            1 :         update_payload();
     869            1 :         return;
     870              : 
     871            1 :     case field::upgrade:
     872            1 :         md.upgrade = {};
     873            1 :         return;
     874              : 
     875           31 :     default:
     876           31 :         break;
     877              :     }
     878              : }
     879              : 
     880              : //------------------------------------------------
     881              : 
     882              : /*  References:
     883              : 
     884              :     3.3.  Message Body
     885              :     https://datatracker.ietf.org/doc/html/rfc7230#section-3.3
     886              : 
     887              :     3.3.1.  Transfer-Encoding
     888              :     https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.1
     889              : 
     890              :     3.3.2.  Content-Length
     891              :     https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
     892              : */
     893              : void
     894         2744 : header::
     895              : update_payload() noexcept
     896              : {
     897         2744 :     BOOST_ASSERT(kind !=
     898              :         detail::kind::fields);
     899         2744 :     if(md.payload_override)
     900              :     {
     901              :         // e.g. response to
     902              :         // a HEAD request
     903            0 :         return;
     904              :     }
     905              : 
     906              : /*  If there is an error in either Content-Length
     907              :     or Transfer-Encoding, then the payload is
     908              :     undefined. Clients should probably close the
     909              :     connection. Servers can send a Bad Request
     910              :     and avoid reading any payload bytes.
     911              : */
     912         2744 :     if(md.content_length.ec.failed())
     913              :     {
     914              :         // invalid Content-Length
     915          128 :         md.payload = payload::error;
     916          128 :         md.payload_size = 0;
     917          128 :         return;
     918              :     }
     919         2616 :     if(md.transfer_encoding.ec.failed())
     920              :     {
     921              :         // invalid Transfer-Encoding
     922           11 :         md.payload = payload::error;
     923           11 :         md.payload_size = 0;
     924           11 :         return;
     925              :     }
     926              : 
     927              : /*  A sender MUST NOT send a Content-Length
     928              :     header field in any message that contains
     929              :     a Transfer-Encoding header field.
     930              :     https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
     931              : */
     932         2605 :     if( md.content_length.count > 0 &&
     933          458 :         md.transfer_encoding.count > 0)
     934              :     {
     935            3 :         md.payload = payload::error;
     936            3 :         md.payload_size = 0;
     937            3 :         return;
     938              :     }
     939              : 
     940         2602 :     if(kind == detail::kind::response)
     941          709 :         goto do_response;
     942              : 
     943              :     //--------------------------------------------
     944              : 
     945              : /*  The presence of a message body in a
     946              :     request is signaled by a Content-Length
     947              :     or Transfer-Encoding header field. Request
     948              :     message framing is independent of method
     949              :     semantics, even if the method does not
     950              :     define any use for a message body.
     951              : */
     952         1893 :     if(md.content_length.count > 0)
     953              :     {
     954          297 :         if(md.content_length.value > 0)
     955              :         {
     956              :             // non-zero Content-Length
     957          291 :             md.payload = payload::size;
     958          291 :             md.payload_size = md.content_length.value;
     959          291 :             return;
     960              :         }
     961              :         // Content-Length: 0
     962            6 :         md.payload = payload::none;
     963            6 :         md.payload_size = 0;
     964            6 :         return;
     965              :     }
     966         1596 :     if(md.transfer_encoding.is_chunked)
     967              :     {
     968              :         // chunked
     969           10 :         md.payload = payload::chunked;
     970           10 :         md.payload_size = 0;
     971           10 :         return;
     972              :     }
     973              :     // no payload
     974         1586 :     md.payload = payload::none;
     975         1586 :     md.payload_size = 0;
     976         1586 :     return;
     977              : 
     978              :     //--------------------------------------------
     979          709 : do_response:
     980              : 
     981          709 :     if( res.status_int /  100 == 1 ||   // 1xx e.g. Continue
     982          699 :         res.status_int == 204 ||        // No Content
     983          697 :         res.status_int == 304)          // Not Modified
     984              :     {
     985              :     /*  The correctness of any Content-Length
     986              :         here is defined by the particular
     987              :         resource, and cannot be determined
     988              :         here. In any case there is no payload.
     989              :     */
     990           14 :         md.payload = payload::none;
     991           14 :         md.payload_size = 0;
     992           14 :         return;
     993              :     }
     994          695 :     if(md.content_length.count > 0)
     995              :     {
     996          155 :         if(md.content_length.value > 0)
     997              :         {
     998              :             // Content-Length > 0
     999          142 :             md.payload = payload::size;
    1000          142 :             md.payload_size = md.content_length.value;
    1001          142 :             return;
    1002              :         }
    1003              :         // Content-Length: 0
    1004           13 :         md.payload = payload::none;
    1005           13 :         md.payload_size = 0;
    1006           13 :         return;
    1007              :     }
    1008          540 :     if(md.transfer_encoding.is_chunked)
    1009              :     {
    1010              :         // chunked
    1011           32 :         md.payload = payload::chunked;
    1012           32 :         md.payload_size = 0;
    1013           32 :         return;
    1014              :     }
    1015              : 
    1016              :     // eof needed
    1017          508 :     md.payload = payload::to_eof;
    1018          508 :     md.payload_size = 0;
    1019              : }
    1020              : 
    1021              : //------------------------------------------------
    1022              : 
    1023              : std::size_t
    1024          534 : header::
    1025              : count_crlf(
    1026              :     core::string_view s) noexcept
    1027              : {
    1028          534 :     auto it = s.data();
    1029          534 :     auto len = s.size();
    1030          534 :     std::size_t n = 0;
    1031        18789 :     while(len >= 2)
    1032              :     {
    1033        18255 :         if( it[0] == '\r' &&
    1034         1711 :             it[1] != '\r')
    1035              :         {
    1036         1711 :             if(it[1] == '\n')
    1037         1711 :                 n++;
    1038         1711 :             it += 2;
    1039         1711 :             len -= 2;
    1040              :         }
    1041              :         else
    1042              :         {
    1043        16544 :             it++;
    1044        16544 :             len--;
    1045              :         }
    1046              :     }
    1047          534 :     return n;
    1048              : }
    1049              : 
    1050              : static
    1051              : void
    1052         3959 : parse_start_line(
    1053              :     header& h,
    1054              :     header_limits const& lim,
    1055              :     std::size_t new_size,
    1056              :     system::error_code& ec) noexcept
    1057              : {
    1058         3959 :     BOOST_ASSERT(h.size == 0);
    1059         3959 :     BOOST_ASSERT(h.prefix == 0);
    1060         3959 :     BOOST_ASSERT(h.cbuf != nullptr);
    1061         3959 :     BOOST_ASSERT(
    1062              :         h.kind != detail::kind::fields);
    1063              : 
    1064         3959 :     auto const it0 = h.cbuf;
    1065         3959 :     auto const end = it0 + new_size;
    1066         3959 :     char const* it = it0;
    1067         3959 :     if( new_size > lim.max_start_line)
    1068            0 :         new_size = lim.max_start_line;
    1069         3959 :     if(h.kind == detail::kind::request)
    1070              :     {
    1071              :         auto rv = grammar::parse(
    1072         3356 :             it, end, request_line_rule);
    1073         3356 :         if(! rv)
    1074              :         {
    1075         1809 :             ec = rv.error();
    1076         3618 :             if( ec == grammar::error::need_more &&
    1077         1809 :                 new_size == lim.max_start_line)
    1078            0 :                 ec = BOOST_HTTP_PROTO_ERR(
    1079              :                     error::start_line_limit);
    1080         1809 :             return;
    1081              :         }
    1082              :         // method
    1083         1547 :         auto sm = std::get<0>(*rv);
    1084         1547 :         h.req.method = string_to_method(sm);
    1085         1547 :         h.req.method_len =
    1086         1547 :             static_cast<offset_type>(sm.size());
    1087              :         // target
    1088         1547 :         auto st = std::get<1>(*rv);
    1089         1547 :         h.req.target_len =
    1090         1547 :             static_cast<offset_type>(st.size());
    1091              :         // version
    1092         1547 :         switch(std::get<2>(*rv))
    1093              :         {
    1094           20 :         case 10:
    1095           20 :             h.version =
    1096              :                 http_proto::version::http_1_0;
    1097           20 :             break;
    1098         1527 :         case 11:
    1099         1527 :             h.version =
    1100              :                 http_proto::version::http_1_1;
    1101         1527 :             break;
    1102            0 :         default:
    1103              :         {
    1104            0 :             ec = BOOST_HTTP_PROTO_ERR(
    1105              :                 error::bad_version);
    1106            0 :             return;
    1107              :         }
    1108              :         }
    1109              :     }
    1110              :     else
    1111              :     {
    1112              :         auto rv = grammar::parse(
    1113          603 :             it, end, status_line_rule);
    1114          603 :         if(! rv)
    1115              :         {
    1116          151 :             ec = rv.error();
    1117          302 :             if( ec == grammar::error::need_more &&
    1118          151 :                 new_size == lim.max_start_line)
    1119            0 :                 ec = BOOST_HTTP_PROTO_ERR(
    1120              :                     error::start_line_limit);
    1121          151 :             return;
    1122              :         }
    1123              :         // version
    1124          452 :         switch(std::get<0>(*rv))
    1125              :         {
    1126            5 :         case 10:
    1127            5 :             h.version =
    1128              :                 http_proto::version::http_1_0;
    1129            5 :             break;
    1130          447 :         case 11:
    1131          447 :             h.version =
    1132              :                 http_proto::version::http_1_1;
    1133          447 :             break;
    1134            0 :         default:
    1135              :         {
    1136            0 :             ec = BOOST_HTTP_PROTO_ERR(
    1137              :                 error::bad_version);
    1138            0 :             return;
    1139              :         }
    1140              :         }
    1141              :         // status-code
    1142          452 :         h.res.status_int =
    1143              :             static_cast<unsigned short>(
    1144          452 :                 std::get<1>(*rv).v);
    1145          452 :         h.res.status = std::get<1>(*rv).st;
    1146              :     }
    1147         1999 :     h.prefix = static_cast<offset_type>(it - it0);
    1148         1999 :     h.size = h.prefix;
    1149         1999 :     h.on_start_line();
    1150              : }
    1151              : 
    1152              : // returns: true if we added a field
    1153              : static
    1154              : void
    1155         6779 : parse_field(
    1156              :     header& h,
    1157              :     header_limits const& lim,
    1158              :     std::size_t new_size,
    1159              :     system::error_code& ec) noexcept
    1160              : {
    1161         6779 :     if( new_size > lim.max_field)
    1162            0 :         new_size = lim.max_field;
    1163         6779 :     auto const it0 = h.cbuf + h.size;
    1164         6779 :     auto const end = h.cbuf + new_size;
    1165         6779 :     char const* it = it0;
    1166         6779 :     auto rv = grammar::parse(
    1167              :         it, end, field_rule);
    1168         6779 :     if(rv.has_error())
    1169              :     {
    1170         4071 :         ec = rv.error();
    1171         4071 :         if(ec == grammar::error::end_of_range)
    1172              :         {
    1173              :             // final CRLF
    1174         1980 :             h.size = static_cast<
    1175         1980 :                 offset_type>(it - h.cbuf);
    1176         4071 :             return;
    1177              :         }
    1178         3923 :         if( ec == grammar::error::need_more &&
    1179         1832 :             new_size == lim.max_field)
    1180              :         {
    1181            0 :             ec = BOOST_HTTP_PROTO_ERR(
    1182              :                 error::field_size_limit);
    1183              :         }
    1184         2091 :         return;
    1185              :     }
    1186         2708 :     if(h.count >= lim.max_fields)
    1187              :     {
    1188            0 :         ec = BOOST_HTTP_PROTO_ERR(
    1189              :             error::fields_limit);
    1190            0 :         return;
    1191              :     }
    1192         2708 :     if(rv->has_obs_fold)
    1193              :     {
    1194              :         // obs fold not allowed in test views
    1195          210 :         BOOST_ASSERT(h.buf != nullptr);
    1196          210 :         remove_obs_fold(h.buf + h.size, it);
    1197              :     }
    1198         2708 :     auto id = string_to_field(rv->name);
    1199         2708 :     h.size = static_cast<offset_type>(it - h.cbuf);
    1200              : 
    1201              :     // add field table entry
    1202         2708 :     if(h.buf != nullptr)
    1203              :     {
    1204         5416 :         auto& e = header::table(
    1205         2708 :             h.buf + h.cap)[h.count];
    1206         2708 :         auto const base =
    1207         2708 :             h.buf + h.prefix;
    1208         2708 :         e.np = static_cast<offset_type>(
    1209         2708 :             rv->name.data() - base);
    1210         2708 :         e.nn = static_cast<offset_type>(
    1211         2708 :             rv->name.size());
    1212         2708 :         e.vp = static_cast<offset_type>(
    1213         2708 :             rv->value.data() - base);
    1214         2708 :         e.vn = static_cast<offset_type>(
    1215         2708 :             rv->value.size());
    1216         2708 :         e.id = id;
    1217              :     }
    1218         2708 :     ++h.count;
    1219         2708 :     h.on_insert(id, rv->value);
    1220         2708 :     ec = {};
    1221              : }
    1222              : 
    1223              : void
    1224         6031 : header::
    1225              : parse(
    1226              :     std::size_t new_size,
    1227              :     header_limits const& lim,
    1228              :     system::error_code& ec) noexcept
    1229              : {
    1230         6031 :     if( new_size > lim.max_size)
    1231            0 :         new_size = lim.max_size;
    1232         6031 :     if( this->prefix == 0 &&
    1233         4199 :         this->kind !=
    1234              :             detail::kind::fields)
    1235              :     {
    1236         3959 :         parse_start_line(
    1237              :             *this, lim, new_size, ec);
    1238         3959 :         if(ec.failed())
    1239              :         {
    1240         3920 :             if( ec == grammar::error::need_more &&
    1241         1960 :                 new_size == lim.max_fields)
    1242              :             {
    1243            0 :                 ec = BOOST_HTTP_PROTO_ERR(
    1244              :                     error::headers_limit);
    1245              :             }
    1246         1960 :             return;
    1247              :         }
    1248              :     }
    1249              :     for(;;)
    1250              :     {
    1251         6779 :         parse_field(
    1252              :             *this, lim, new_size, ec);
    1253         6779 :         if(ec.failed())
    1254              :         {
    1255         5903 :             if( ec == grammar::error::need_more &&
    1256         1832 :                 new_size == lim.max_size)
    1257              :             {
    1258            0 :                 ec = BOOST_HTTP_PROTO_ERR(
    1259              :                     error::headers_limit);
    1260            0 :                 return;
    1261              :             }
    1262         4071 :             break;
    1263              :         }
    1264         2708 :     }
    1265         4071 :     if(ec == grammar::error::end_of_range)
    1266         1980 :         ec = {};
    1267              : }
    1268              : 
    1269              : } // detail
    1270              : } // http_proto
    1271              : } // boost
        

Generated by: LCOV version 2.1