LCOV - code coverage report
Current view: top level - src/rfc/detail - rules.cpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 95.8 % 166 159 7
Test Date: 2026-06-13 19:44:58 Functions: 100.0 % 10 10

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2021 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
       8                 : //
       9                 : 
      10                 : #include "src/rfc/detail/rules.hpp"
      11                 : 
      12                 : #include <boost/http/error.hpp>
      13                 : #include <boost/http/detail/config.hpp>
      14                 : #include <boost/http/rfc/token_rule.hpp>
      15                 : 
      16                 : #include <boost/core/detail/string_view.hpp>
      17                 : #include <boost/url/grammar/delim_rule.hpp>
      18                 : #include <boost/url/grammar/digit_chars.hpp>
      19                 : #include <boost/url/grammar/error.hpp>
      20                 : #include <boost/url/grammar/hexdig_chars.hpp>
      21                 : #include <boost/url/grammar/lut_chars.hpp>
      22                 : #include <boost/url/grammar/parse.hpp>
      23                 : #include <boost/url/grammar/tuple_rule.hpp>
      24                 : 
      25                 : #include "src/rfc/detail/rules.hpp"
      26                 : 
      27                 : namespace boost {
      28                 : namespace http {
      29                 : namespace detail {
      30                 : 
      31                 : auto
      32 HIT       28320 : crlf_rule_t::
      33                 : parse(
      34                 :     char const*& it,
      35                 :     char const* end) const noexcept ->
      36                 :         system::result<value_type>
      37                 : {
      38           28320 :     if(it == end)
      39            6145 :         return grammar::error::need_more;
      40           22175 :     if(*it != '\r')
      41              29 :         return grammar::error::mismatch;
      42           22146 :     ++it;
      43           22146 :     if(it == end)
      44             887 :         return grammar::error::need_more;
      45           21259 :     if(*it != '\n')
      46              51 :         return grammar::error::mismatch;
      47           21208 :     ++it;
      48           21208 :     return {};
      49                 : }
      50                 : 
      51                 : //------------------------------------------------
      52                 : 
      53                 : auto
      54           26900 : version_rule_t::
      55                 : parse(
      56                 :     char const*& it,
      57                 :     char const* end) const noexcept ->
      58                 :         system::result<value_type>
      59                 : {
      60           26900 :     value_type v = 0;
      61           26900 :     if(it == end)
      62                 :     {
      63                 :         // expected "HTTP/"
      64            1511 :         BOOST_HTTP_RETURN_EC(
      65                 :             grammar::error::need_more);
      66                 :     }
      67           25389 :     if(end - it >= 5)
      68                 :     {
      69           21083 :         if(std::memcmp(
      70                 :             it, "HTTP/", 5) != 0)
      71                 :         {
      72 MIS           0 :             BOOST_HTTP_RETURN_EC(
      73                 :                 grammar::error::mismatch);
      74                 :         }
      75 HIT       21083 :         it += 5;
      76                 :     }
      77           25389 :     if(it == end)
      78                 :     {
      79                 :         // expected DIGIT
      80             991 :         BOOST_HTTP_RETURN_EC(
      81                 :             grammar::error::need_more);
      82                 :     }
      83           24398 :     if(! grammar::digit_chars(*it))
      84                 :     {
      85                 :         // expected DIGIT
      86            4306 :         BOOST_HTTP_RETURN_EC(
      87                 :             grammar::error::need_more);
      88                 :     }
      89           20092 :     v = 10 * (*it++ - '0');
      90           20092 :     if(it == end)
      91                 :     {
      92                 :         // expected "."
      93            1119 :         BOOST_HTTP_RETURN_EC(
      94                 :             grammar::error::need_more);
      95                 :     }
      96           18973 :     if(*it != '.')
      97                 :     {
      98                 :         // expected "."
      99 MIS           0 :         BOOST_HTTP_RETURN_EC(
     100                 :             grammar::error::need_more);
     101                 :     }
     102 HIT       18973 :     ++it;
     103           18973 :     if(it == end)
     104                 :     {
     105                 :         // expected DIGIT
     106             959 :         BOOST_HTTP_RETURN_EC(
     107                 :             grammar::error::need_more);
     108                 :     }
     109           18014 :     if(! grammar::digit_chars(*it))
     110                 :     {
     111                 :         // expected DIGIT
     112 MIS           0 :         BOOST_HTTP_RETURN_EC(
     113                 :             grammar::error::need_more);
     114                 :     }
     115 HIT       18014 :     v += *it++ - '0';
     116           18014 :     return v;
     117                 : }
     118                 : 
     119                 : //------------------------------------------------
     120                 : 
     121                 : auto
     122            7464 : status_code_rule_t::
     123                 : parse(
     124                 :     char const*& it,
     125                 :     char const* end) const noexcept ->
     126                 :         system::result<value_type>
     127                 : {
     128                 :     auto const dig =
     129           17380 :         [](char c) -> int
     130                 :         {
     131           17380 :             unsigned char uc(c - '0');
     132           17380 :             if(uc > 9)
     133 MIS           0 :                 return -1;
     134 HIT       17380 :             return uc;
     135                 :         };
     136                 : 
     137            7464 :     if(it == end)
     138                 :     {
     139                 :         // end
     140             846 :         BOOST_HTTP_RETURN_EC(
     141                 :             grammar::error::need_more);
     142                 :     }
     143            6618 :     auto it0 = it;
     144            6618 :     int v = dig(*it);
     145            6618 :     if(v == -1)
     146                 :     {
     147                 :         // expected DIGIT
     148 MIS           0 :         BOOST_HTTP_RETURN_EC(
     149                 :             grammar::error::mismatch);
     150                 :     }
     151 HIT        6618 :     value_type t;
     152            6618 :     t.v = 100 * v;
     153            6618 :     ++it;
     154            6618 :     if(it == end)
     155                 :     {
     156                 :         // end
     157             830 :         BOOST_HTTP_RETURN_EC(
     158                 :             grammar::error::need_more);
     159                 :     }
     160            5788 :     v = dig(*it);
     161            5788 :     if(v == -1)
     162                 :     {
     163                 :         // expected DIGIT
     164 MIS           0 :         BOOST_HTTP_RETURN_EC(
     165                 :             grammar::error::mismatch);
     166                 :     }
     167 HIT        5788 :     t.v = t.v + (10 * v);
     168            5788 :     ++it;
     169            5788 :     if(it == end)
     170                 :     {
     171                 :         // end
     172             814 :         BOOST_HTTP_RETURN_EC(
     173                 :             grammar::error::need_more);
     174                 :     }
     175            4974 :     v = dig(*it);
     176            4974 :     if(v == -1)
     177                 :     {
     178                 :         // expected DIGIT
     179 MIS           0 :         BOOST_HTTP_RETURN_EC(
     180                 :             grammar::error::need_more);
     181                 :     }
     182 HIT        4974 :     t.v = t.v + v;
     183            4974 :     ++it;
     184                 : 
     185            4974 :     t.s = core::string_view(it0, it - it0);
     186            4974 :     t.st = int_to_status(t.v);
     187            4974 :     return t;
     188                 : }
     189                 : 
     190                 : //------------------------------------------------
     191                 : 
     192                 : auto
     193            4176 : reason_phrase_rule_t::
     194                 : parse(
     195                 :     char const*& it,
     196                 :     char const* end) const noexcept ->
     197                 :         system::result<value_type>
     198                 : {
     199            4176 :     auto begin = it;
     200            4176 :     it = grammar::find_if_not(it, end, ws_vchars);
     201            4176 :     return core::string_view(begin, it);
     202                 : }
     203                 : 
     204                 : //------------------------------------------------
     205                 : 
     206                 : auto
     207           25313 : field_name_rule_t::
     208                 : parse(
     209                 :     char const*& it,
     210                 :     char const* end) const noexcept ->
     211                 :         system::result<value_type>
     212                 : {
     213           25313 :     if( it == end )
     214               1 :         BOOST_HTTP_RETURN_EC(
     215                 :             grammar::error::need_more);
     216                 : 
     217           25312 :     value_type v;
     218                 : 
     219           25312 :     auto begin = it;
     220           25312 :     auto rv = grammar::parse(
     221                 :         it, end, token_rule);
     222           25312 :     if( rv.has_error() || (it != end) )
     223                 :     {
     224           15687 :         if( it != begin )
     225                 :         {
     226           15621 :             v = core::string_view(begin, it - begin);
     227           15621 :             return v;
     228                 :         }
     229              66 :         return error::bad_field_name;
     230                 :     }
     231                 : 
     232            9625 :     v = core::string_view(begin, end - begin);
     233            9625 :     return v;
     234                 : }
     235                 : 
     236                 : auto
     237           15890 : field_value_rule_t::
     238                 : parse(
     239                 :     char const*& it,
     240                 :     char const* end) const noexcept ->
     241                 :         system::result<value_type>
     242                 : {
     243           15890 :     value_type v;
     244           15890 :     if( it == end )
     245                 :     {
     246             651 :         v.value = core::string_view(it, 0);
     247             651 :         return v;
     248                 :     }
     249                 : 
     250                 :     // field-line     = field-name ":" OWS field-value OWS
     251                 :     // field-value    = *field-content
     252                 :     // field-content  = field-vchar
     253                 :     //                  [ 1*( SP / HTAB / field-vchar ) field-vchar ]
     254                 :     // field-vchar    = VCHAR / obs-text
     255                 :     // obs-text       = %x80-FF
     256                 :     // VCHAR          = %x21-7E
     257                 :     //                       ; visible (printing) characters
     258                 : 
     259           66277 :     auto is_field_vchar = [](unsigned char ch)
     260                 :     {
     261           66277 :       return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
     262                 :     };
     263                 : 
     264           15239 :     char const* s0 = nullptr;
     265           15239 :     char const* s1 = nullptr;
     266                 : 
     267           15239 :     bool has_crlf = false;
     268           15239 :     bool has_obs_fold = false;
     269                 : 
     270           99363 :     while( it < end )
     271                 :     {
     272           95981 :         auto ch = *it;
     273           95981 :         if( ws(ch) )
     274                 :         {
     275           17151 :             ++it;
     276           17151 :             continue;
     277                 :         }
     278                 : 
     279           78830 :         if( ch == '\r' )
     280                 :         {
     281                 :             // too short to know if we have a potential obs-fold
     282                 :             // occurrence
     283           12553 :             if( end - it < 2 )
     284             558 :                 BOOST_HTTP_RETURN_EC(
     285                 :                     grammar::error::need_more);
     286                 : 
     287           11995 :             if( it[1] != '\n' )
     288              53 :                 goto done;
     289                 : 
     290           11942 :             if( end - it < 3 )
     291             514 :                 BOOST_HTTP_RETURN_EC(
     292                 :                     grammar::error::need_more);
     293                 : 
     294           11428 :             if(! ws(it[2]) )
     295                 :             {
     296           10698 :                 has_crlf = true;
     297           10698 :                 goto done;
     298                 :             }
     299                 : 
     300             730 :             has_obs_fold = true;
     301             730 :             it = it + 3;
     302             730 :             continue;
     303             730 :         }
     304                 : 
     305           66277 :         if(! is_field_vchar(ch) )
     306                 :         {
     307              34 :             goto done;
     308                 :         }
     309                 : 
     310           66243 :         if(! s0 )
     311           14176 :             s0 = it;
     312                 : 
     313           66243 :         ++it;
     314           66243 :         s1 = it;
     315                 :     }
     316                 : 
     317            3382 : done:
     318                 :     // later routines wind up doing pointer
     319                 :     // subtraction using the .data() member
     320                 :     // of the value so we need a valid 0-len range
     321           14167 :     if(! s0 )
     322                 :     {
     323             899 :         s0 = it;
     324             899 :         s1 = s0;
     325                 :     }
     326                 : 
     327           14167 :     v.value = core::string_view(s0, s1 - s0);
     328           14167 :     v.has_crlf = has_crlf;
     329           14167 :     v.has_obs_fold = has_obs_fold;
     330           14167 :     return v;
     331                 : }
     332                 : 
     333                 : auto
     334           36560 : field_rule_t::
     335                 : parse(
     336                 :     char const*& it,
     337                 :     char const* end) const noexcept ->
     338                 :         system::result<value_type>
     339                 : {
     340           36560 :     if(it == end)
     341                 :     {
     342             907 :         BOOST_HTTP_RETURN_EC(
     343                 :             grammar::error::need_more);
     344                 :     }
     345                 :     // check for leading CRLF
     346           35653 :     if(it[0] == '\r')
     347                 :     {
     348           10581 :         ++it;
     349           10581 :         if(it == end)
     350                 :         {
     351             459 :             BOOST_HTTP_RETURN_EC(
     352                 :                 grammar::error::need_more);
     353                 :         }
     354           10122 :         if(*it != '\n')
     355                 :         {
     356              21 :             BOOST_HTTP_RETURN_EC(
     357                 :                 grammar::error::mismatch);
     358                 :         }
     359                 :         // end of fields
     360           10101 :         ++it;
     361           10101 :         BOOST_HTTP_RETURN_EC(
     362                 :             grammar::error::end_of_range);
     363                 :     }
     364                 : 
     365           25072 :     value_type v;
     366                 :     auto rv = grammar::parse(
     367           25072 :         it, end, grammar::tuple_rule(
     368                 :             field_name_rule,
     369           25072 :             grammar::delim_rule(':'),
     370                 :             field_value_rule,
     371           25072 :             crlf_rule));
     372                 : 
     373           25072 :     if( rv.has_error() )
     374           14390 :         return rv.error();
     375                 : 
     376           10682 :     auto val = rv.value();
     377           10682 :     v.name = std::get<0>(val);
     378           10682 :     v.value = std::get<2>(val).value;
     379           10682 :     v.has_obs_fold = std::get<2>(val).has_obs_fold;
     380                 : 
     381           10682 :     return v;
     382                 : }
     383                 : 
     384                 : //------------------------------------------------
     385                 : 
     386                 : void
     387             244 : remove_obs_fold(
     388                 :     char* it,
     389                 :     char const* const end) noexcept
     390                 : {
     391            2262 :     while(it != end)
     392                 :     {
     393            2236 :         if(*it != '\r')
     394                 :         {
     395            1637 :             ++it;
     396            1637 :             continue;
     397                 :         }
     398             599 :         if(end - it < 3)
     399             218 :             break;
     400             381 :         BOOST_ASSERT(it[1] == '\n');
     401             762 :         if( it[1] == '\n' &&
     402             381 :             ws(it[2]))
     403                 :         {
     404             378 :             it[0] = ' ';
     405             378 :             it[1] = ' ';
     406             378 :             it += 3;
     407                 :         }
     408                 :         else
     409                 :         {
     410               3 :             ++it;
     411                 :         }
     412                 :     }
     413             244 : }
     414                 : 
     415                 : } // detail
     416                 : } // http
     417                 : } // boost
        

Generated by: LCOV version 2.3