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-08-26 15:14:03 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       28890 : crlf_rule_t::
      33                 : parse(
      34                 :     char const*& it,
      35                 :     char const* end) const noexcept ->
      36                 :         system::result<value_type>
      37                 : {
      38           28890 :     if(it == end)
      39            6535 :         return grammar::error::need_more;
      40           22355 :     if(*it != '\r')
      41              29 :         return grammar::error::mismatch;
      42           22326 :     ++it;
      43           22326 :     if(it == end)
      44             961 :         return grammar::error::need_more;
      45           21365 :     if(*it != '\n')
      46              51 :         return grammar::error::mismatch;
      47           21314 :     ++it;
      48           21314 :     return {};
      49                 : }
      50                 : 
      51                 : //------------------------------------------------
      52                 : 
      53                 : auto
      54           28506 : version_rule_t::
      55                 : parse(
      56                 :     char const*& it,
      57                 :     char const* end) const noexcept ->
      58                 :         system::result<value_type>
      59                 : {
      60           28506 :     value_type v = 0;
      61           28506 :     if(it == end)
      62                 :     {
      63                 :         // expected "HTTP/"
      64            1619 :         return grammar::error::need_more;
      65                 :     }
      66           26887 :     if(end - it >= 5)
      67                 :     {
      68           22177 :         if(std::memcmp(
      69                 :             it, "HTTP/", 5) != 0)
      70                 :         {
      71 MIS           0 :             return grammar::error::mismatch;
      72                 :         }
      73 HIT       22177 :         it += 5;
      74                 :     }
      75           26887 :     if(it == end)
      76                 :     {
      77                 :         // expected DIGIT
      78            1087 :         return grammar::error::need_more;
      79                 :     }
      80           25800 :     if(! grammar::digit_chars(*it))
      81                 :     {
      82                 :         // expected DIGIT
      83            4710 :         return grammar::error::need_more;
      84                 :     }
      85           21090 :     v = 10 * (*it++ - '0');
      86           21090 :     if(it == end)
      87                 :     {
      88                 :         // expected "."
      89            1213 :         return grammar::error::need_more;
      90                 :     }
      91           19877 :     if(*it != '.')
      92                 :     {
      93                 :         // expected "."
      94 MIS           0 :         return grammar::error::need_more;
      95                 :     }
      96 HIT       19877 :     ++it;
      97           19877 :     if(it == end)
      98                 :     {
      99                 :         // expected DIGIT
     100            1051 :         return grammar::error::need_more;
     101                 :     }
     102           18826 :     if(! grammar::digit_chars(*it))
     103                 :     {
     104                 :         // expected DIGIT
     105 MIS           0 :         return grammar::error::need_more;
     106                 :     }
     107 HIT       18826 :     v += *it++ - '0';
     108           18826 :     return v;
     109                 : }
     110                 : 
     111                 : //------------------------------------------------
     112                 : 
     113                 : auto
     114            8184 : status_code_rule_t::
     115                 : parse(
     116                 :     char const*& it,
     117                 :     char const* end) const noexcept ->
     118                 :         system::result<value_type>
     119                 : {
     120                 :     auto const dig =
     121           19020 :         [](char c) -> int
     122                 :         {
     123           19020 :             unsigned char uc(c - '0');
     124           19020 :             if(uc > 9)
     125 MIS           0 :                 return -1;
     126 HIT       19020 :             return uc;
     127                 :         };
     128                 : 
     129            8184 :     if(it == end)
     130                 :     {
     131                 :         // end
     132             934 :         return grammar::error::need_more;
     133                 :     }
     134            7250 :     auto it0 = it;
     135            7250 :     int v = dig(*it);
     136            7250 :     if(v == -1)
     137                 :     {
     138                 :         // expected DIGIT
     139 MIS           0 :         return grammar::error::mismatch;
     140                 :     }
     141 HIT        7250 :     value_type t;
     142            7250 :     t.v = 100 * v;
     143            7250 :     ++it;
     144            7250 :     if(it == end)
     145                 :     {
     146                 :         // end
     147             916 :         return grammar::error::need_more;
     148                 :     }
     149            6334 :     v = dig(*it);
     150            6334 :     if(v == -1)
     151                 :     {
     152                 :         // expected DIGIT
     153 MIS           0 :         return grammar::error::mismatch;
     154                 :     }
     155 HIT        6334 :     t.v = t.v + (10 * v);
     156            6334 :     ++it;
     157            6334 :     if(it == end)
     158                 :     {
     159                 :         // end
     160             898 :         return grammar::error::need_more;
     161                 :     }
     162            5436 :     v = dig(*it);
     163            5436 :     if(v == -1)
     164                 :     {
     165                 :         // expected DIGIT
     166 MIS           0 :         return grammar::error::need_more;
     167                 :     }
     168 HIT        5436 :     t.v = t.v + v;
     169            5436 :     ++it;
     170                 : 
     171            5436 :     t.s = core::string_view(it0, it - it0);
     172            5436 :     t.st = int_to_status(t.v);
     173            5436 :     return t;
     174                 : }
     175                 : 
     176                 : //------------------------------------------------
     177                 : 
     178                 : auto
     179            4556 : reason_phrase_rule_t::
     180                 : parse(
     181                 :     char const*& it,
     182                 :     char const* end) const noexcept ->
     183                 :         system::result<value_type>
     184                 : {
     185            4556 :     auto begin = it;
     186            4556 :     it = grammar::find_if_not(it, end, ws_vchars);
     187            4556 :     return core::string_view(begin, it);
     188                 : }
     189                 : 
     190                 : //------------------------------------------------
     191                 : 
     192                 : auto
     193           26365 : field_name_rule_t::
     194                 : parse(
     195                 :     char const*& it,
     196                 :     char const* end) const noexcept ->
     197                 :         system::result<value_type>
     198                 : {
     199           26365 :     if( it == end )
     200               1 :         return grammar::error::need_more;
     201                 : 
     202           26364 :     value_type v;
     203                 : 
     204           26364 :     auto begin = it;
     205           26364 :     auto rv = grammar::parse(
     206                 :         it, end, token_rule);
     207           26364 :     if( rv.has_error() || (it != end) )
     208                 :     {
     209           15941 :         if( it != begin )
     210                 :         {
     211           15875 :             v = core::string_view(begin, it - begin);
     212           15875 :             return v;
     213                 :         }
     214             132 :         return make_error_code(
     215              66 :             error::bad_field_name);
     216                 :     }
     217                 : 
     218           10423 :     v = core::string_view(begin, end - begin);
     219           10423 :     return v;
     220                 : }
     221                 : 
     222                 : auto
     223           16144 : field_value_rule_t::
     224                 : parse(
     225                 :     char const*& it,
     226                 :     char const* end) const noexcept ->
     227                 :         system::result<value_type>
     228                 : {
     229           16144 :     value_type v;
     230           16144 :     if( it == end )
     231                 :     {
     232             693 :         v.value = core::string_view(it, 0);
     233             693 :         return v;
     234                 :     }
     235                 : 
     236                 :     // field-line     = field-name ":" OWS field-value OWS
     237                 :     // field-value    = *field-content
     238                 :     // field-content  = field-vchar
     239                 :     //                  [ 1*( SP / HTAB / field-vchar ) field-vchar ]
     240                 :     // field-vchar    = VCHAR / obs-text
     241                 :     // obs-text       = %x80-FF
     242                 :     // VCHAR          = %x21-7E
     243                 :     //                       ; visible (printing) characters
     244                 : 
     245           66585 :     auto is_field_vchar = [](unsigned char ch)
     246                 :     {
     247           66585 :       return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
     248                 :     };
     249                 : 
     250           15451 :     char const* s0 = nullptr;
     251           15451 :     char const* s1 = nullptr;
     252                 : 
     253           15451 :     bool has_crlf = false;
     254           15451 :     bool has_obs_fold = false;
     255                 : 
     256          100095 :     while( it < end )
     257                 :     {
     258           96599 :         auto ch = *it;
     259           96599 :         if( ws(ch) )
     260                 :         {
     261           17363 :             ++it;
     262           17363 :             continue;
     263                 :         }
     264                 : 
     265           79236 :         if( ch == '\r' )
     266                 :         {
     267                 :             // too short to know if we have a potential obs-fold
     268                 :             // occurrence
     269           12651 :             if( end - it < 2 )
     270             592 :                 return grammar::error::need_more;
     271                 : 
     272           12059 :             if( it[1] != '\n' )
     273              53 :                 goto done;
     274                 : 
     275           12006 :             if( end - it < 3 )
     276             546 :                 return grammar::error::need_more;
     277                 : 
     278           11460 :             if(! ws(it[2]) )
     279                 :             {
     280           10730 :                 has_crlf = true;
     281           10730 :                 goto done;
     282                 :             }
     283                 : 
     284             730 :             has_obs_fold = true;
     285             730 :             it = it + 3;
     286             730 :             continue;
     287                 :         }
     288                 : 
     289           66585 :         if(! is_field_vchar(ch) )
     290                 :         {
     291              34 :             goto done;
     292                 :         }
     293                 : 
     294           66551 :         if(! s0 )
     295           14348 :             s0 = it;
     296                 : 
     297           66551 :         ++it;
     298           66551 :         s1 = it;
     299                 :     }
     300                 : 
     301            3496 : done:
     302                 :     // later routines wind up doing pointer
     303                 :     // subtraction using the .data() member
     304                 :     // of the value so we need a valid 0-len range
     305           14313 :     if(! s0 )
     306                 :     {
     307             939 :         s0 = it;
     308             939 :         s1 = s0;
     309                 :     }
     310                 : 
     311           14313 :     v.value = core::string_view(s0, s1 - s0);
     312           14313 :     v.has_crlf = has_crlf;
     313           14313 :     v.has_obs_fold = has_obs_fold;
     314           14313 :     return v;
     315                 : }
     316                 : 
     317                 : auto
     318           37744 : field_rule_t::
     319                 : parse(
     320                 :     char const*& it,
     321                 :     char const* end) const noexcept ->
     322                 :         system::result<value_type>
     323                 : {
     324           37744 :     if(it == end)
     325                 :     {
     326             979 :         return grammar::error::need_more;
     327                 :     }
     328                 :     // check for leading CRLF
     329           36765 :     if(it[0] == '\r')
     330                 :     {
     331           10641 :         ++it;
     332           10641 :         if(it == end)
     333                 :         {
     334             489 :             return grammar::error::need_more;
     335                 :         }
     336           10152 :         if(*it != '\n')
     337                 :         {
     338              21 :             return grammar::error::mismatch;
     339                 :         }
     340                 :         // end of fields
     341           10131 :         ++it;
     342           10131 :         return grammar::error::end_of_range;
     343                 :     }
     344                 : 
     345           26124 :     value_type v;
     346                 :     auto rv = grammar::parse(
     347           26124 :         it, end, grammar::tuple_rule(
     348                 :             field_name_rule,
     349           26124 :             grammar::delim_rule(':'),
     350                 :             field_value_rule,
     351           26124 :             crlf_rule));
     352                 : 
     353           26124 :     if( rv.has_error() )
     354           15410 :         return rv.error();
     355                 : 
     356           10714 :     auto val = rv.value();
     357           10714 :     v.name = std::get<0>(val);
     358           10714 :     v.value = std::get<2>(val).value;
     359           10714 :     v.has_obs_fold = std::get<2>(val).has_obs_fold;
     360                 : 
     361           10714 :     return v;
     362                 : }
     363                 : 
     364                 : //------------------------------------------------
     365                 : 
     366                 : void
     367             244 : remove_obs_fold(
     368                 :     char* it,
     369                 :     char const* const end) noexcept
     370                 : {
     371            2262 :     while(it != end)
     372                 :     {
     373            2236 :         if(*it != '\r')
     374                 :         {
     375            1637 :             ++it;
     376            1637 :             continue;
     377                 :         }
     378             599 :         if(end - it < 3)
     379             218 :             break;
     380             381 :         BOOST_ASSERT(it[1] == '\n');
     381             762 :         if( it[1] == '\n' &&
     382             381 :             ws(it[2]))
     383                 :         {
     384             378 :             it[0] = ' ';
     385             378 :             it[1] = ' ';
     386             378 :             it += 3;
     387                 :         }
     388                 :         else
     389                 :         {
     390               3 :             ++it;
     391                 :         }
     392                 :     }
     393             244 : }
     394                 : 
     395                 : } // detail
     396                 : } // http
     397                 : } // boost
        

Generated by: LCOV version 2.3