LCOV - code coverage report
Current view: top level - http_proto/rfc/detail/impl - rules.ipp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 137 150 91.3 %
Date: 2023-12-11 14:11:20 Functions: 6 6 100.0 %

          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_proto
       8             : //
       9             : 
      10             : #ifndef BOOST_HTTP_PROTO_RFC_DETAIL_IMPL_RULES_IPP
      11             : #define BOOST_HTTP_PROTO_RFC_DETAIL_IMPL_RULES_IPP
      12             : 
      13             : #include <boost/http_proto/rfc/detail/rules.hpp>
      14             : #include <boost/url/grammar/digit_chars.hpp>
      15             : 
      16             : namespace boost {
      17             : namespace http_proto {
      18             : namespace detail {
      19             : 
      20             : auto
      21        4910 : crlf_rule_t::
      22             : parse(
      23             :     char const*& it,
      24             :     char const* end) const noexcept ->
      25             :         system::result<value_type>
      26             : {
      27        4910 :     if(it == end)
      28         529 :         return grammar::error::need_more;
      29        4381 :     if(*it != '\r')
      30           0 :         return grammar::error::mismatch;
      31        4381 :     ++it;
      32        4381 :     if(it == end)
      33         219 :         return grammar::error::need_more;
      34        4162 :     if(*it != '\n')
      35           0 :         return grammar::error::mismatch;
      36        4162 :     ++it;
      37        4162 :     return {};
      38             : }
      39             : 
      40             : //------------------------------------------------
      41             : 
      42             : auto
      43        2902 : version_rule_t::
      44             : parse(
      45             :     char const*& it,
      46             :     char const* end) const noexcept ->
      47             :         system::result<value_type>
      48             : {
      49        2902 :     value_type v = 0;
      50        2902 :     if(it == end)
      51             :     {
      52             :         // expected "HTTP/"
      53         135 :         BOOST_HTTP_PROTO_RETURN_EC(
      54             :             grammar::error::need_more);
      55             :     }
      56        2767 :     if(end - it >= 5)
      57             :     {
      58        2344 :         if(std::memcmp(
      59             :             it, "HTTP/", 5) != 0)
      60             :         {
      61           0 :             BOOST_HTTP_PROTO_RETURN_EC(
      62             :                 grammar::error::mismatch);
      63             :         }
      64        2344 :         it += 5;
      65             :     }
      66        2767 :     if(it == end)
      67             :     {
      68             :         // expected DIGIT
      69          72 :         BOOST_HTTP_PROTO_RETURN_EC(
      70             :             grammar::error::need_more);
      71             :     }
      72        2695 :     if(! grammar::digit_chars(*it))
      73             :     {
      74             :         // expected DIGIT
      75         423 :         BOOST_HTTP_PROTO_RETURN_EC(
      76             :             grammar::error::need_more);
      77             :     }
      78        2272 :     v = 10 * (*it++ - '0');
      79        2272 :     if(it == end)
      80             :     {
      81             :         // expected "."
      82         180 :         BOOST_HTTP_PROTO_RETURN_EC(
      83             :             grammar::error::need_more);
      84             :     }
      85        2092 :     if(*it != '.')
      86             :     {
      87             :         // expected "."
      88           0 :         BOOST_HTTP_PROTO_RETURN_EC(
      89             :             grammar::error::need_more);
      90             :     }
      91        2092 :     ++it;
      92        2092 :     if(it == end)
      93             :     {
      94             :         // expected DIGIT
      95          71 :         BOOST_HTTP_PROTO_RETURN_EC(
      96             :             grammar::error::need_more);
      97             :     }
      98        2021 :     if(! grammar::digit_chars(*it))
      99             :     {
     100             :         // expected DIGIT
     101           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     102             :             grammar::error::need_more);
     103             :     }
     104        2021 :     v += *it++ - '0';
     105        2021 :     return v;
     106             : }
     107             : 
     108             : //------------------------------------------------
     109             : 
     110             : auto
     111         499 : status_code_rule_t::
     112             : parse(
     113             :     char const*& it,
     114             :     char const* end) const noexcept ->
     115             :         system::result<value_type>
     116             : {
     117             :     auto const dig =
     118        1446 :         [](char c) -> int
     119             :         {
     120        1446 :             unsigned char uc(c - '0');
     121        1446 :             if(uc > 9)
     122           0 :                 return -1;
     123        1446 :             return uc;
     124             :         };
     125             :         
     126         499 :     if(it == end)
     127             :     {
     128             :         // end
     129           9 :         BOOST_HTTP_PROTO_RETURN_EC(
     130             :             grammar::error::need_more);
     131             :     }
     132         490 :     auto it0 = it;
     133         490 :     int v = dig(*it);
     134         490 :     if(v == -1)
     135             :     {
     136             :         // expected DIGIT
     137           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     138             :             grammar::error::mismatch);
     139             :     }
     140         490 :     value_type t;
     141         490 :     t.v = 100 * v;
     142         490 :     ++it;
     143         490 :     if(it == end)
     144             :     {
     145             :         // end
     146           8 :         BOOST_HTTP_PROTO_RETURN_EC(
     147             :             grammar::error::need_more);
     148             :     }
     149         482 :     v = dig(*it);
     150         482 :     if(v == -1)
     151             :     {
     152             :         // expected DIGIT
     153           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     154             :             grammar::error::mismatch);
     155             :     }
     156         482 :     t.v = t.v + (10 * v);
     157         482 :     ++it;
     158         482 :     if(it == end)
     159             :     {
     160             :         // end
     161           8 :         BOOST_HTTP_PROTO_RETURN_EC(
     162             :             grammar::error::need_more);
     163             :     }
     164         474 :     v = dig(*it);
     165         474 :     if(v == -1)
     166             :     {
     167             :         // expected DIGIT
     168           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     169             :             grammar::error::need_more);
     170             :     }
     171         474 :     t.v = t.v + v;
     172         474 :     ++it;
     173             : 
     174         474 :     t.s = core::string_view(it0, it - it0);
     175         474 :     t.st = int_to_status(t.v);
     176         474 :     return t;
     177             : }
     178             : 
     179             : //------------------------------------------------
     180             : 
     181             : auto
     182        5825 : field_rule_t::
     183             : parse(
     184             :     char const*& it,
     185             :     char const* end) const noexcept ->
     186             :         system::result<value_type>
     187             : {
     188        5825 :     if(it == end)
     189             :     {
     190         152 :         BOOST_HTTP_PROTO_RETURN_EC(
     191             :             grammar::error::need_more);
     192             :     }
     193             :     // check for leading CRLF
     194        5673 :     if(it[0] == '\r')
     195             :     {
     196        1892 :         ++it;
     197        1892 :         if(it == end)
     198             :         {
     199         112 :             BOOST_HTTP_PROTO_RETURN_EC(
     200             :                 grammar::error::need_more);
     201             :         }
     202        1780 :         if(*it != '\n')
     203             :         {
     204           0 :             BOOST_HTTP_PROTO_RETURN_EC(
     205             :                 grammar::error::mismatch);
     206             :         }
     207             :         // end of fields
     208        1780 :         ++it;
     209        1780 :         BOOST_HTTP_PROTO_RETURN_EC(
     210             :             grammar::error::end_of_range);
     211             :     }
     212             : 
     213        3781 :     value_type v;
     214             : 
     215             :     // field name
     216             :     {
     217             :         auto rv = grammar::parse(
     218        3781 :             it, end, grammar::tuple_rule(
     219             :                 token_rule,
     220        3781 :                 grammar::squelch(
     221        3781 :                     grammar::delim_rule(':'))));
     222        3781 :         if(! rv)
     223         397 :             return rv.error();
     224        3384 :         v.name = rv.value();
     225             :     }
     226             : 
     227             :     // consume all obs-fold until
     228             :     // field char or end of field
     229             :     for(;;)
     230             :     {
     231        3678 :         skip_ows(it, end);
     232        3678 :         if(it == end)
     233             :         {
     234         227 :             BOOST_HTTP_PROTO_RETURN_EC(
     235             :                 grammar::error::need_more);
     236             :         }
     237        3451 :         if(*it != '\r')
     238             :         {
     239             :             // start of value
     240        2897 :             break;
     241             :         }
     242         554 :         ++it;
     243         554 :         if(it == end)
     244             :         {
     245          60 :             BOOST_HTTP_PROTO_RETURN_EC(
     246             :                 grammar::error::need_more);
     247             :         }
     248         494 :         if(*it != '\n')
     249             :         {
     250           0 :             BOOST_HTTP_PROTO_RETURN_EC(
     251             :                 grammar::error::mismatch);
     252             :         }
     253         494 :         ++it;
     254         494 :         if(it == end)
     255             :         {
     256          56 :             BOOST_HTTP_PROTO_RETURN_EC(
     257             :                 grammar::error::need_more);
     258             :         }
     259         438 :         if(*it == '\r')
     260             :         {
     261             :             // empty value
     262         144 :             return v;
     263             :         }
     264         294 :         if( *it != ' ' &&
     265           0 :             *it != '\t')
     266             :         {
     267             :             // start of value
     268           0 :             break;
     269             :         }
     270             :         // eat obs-fold
     271         294 :         ++it;
     272         294 :         v.has_obs_fold = true;
     273         294 :     }
     274             : 
     275        2897 :     char const* s0 = it; // start of value
     276             :     for(;;)
     277             :     {
     278             :         auto rv = grammar::parse(
     279        2939 :             it, end, grammar::tuple_rule(
     280        2939 :                 grammar::token_rule(
     281        2939 :                     ws_vchars),
     282        2939 :                 crlf_rule));
     283        2939 :         if(! rv)
     284         488 :             return rv.error();
     285        2451 :         if(it == end)
     286             :         {
     287          71 :             BOOST_HTTP_PROTO_RETURN_EC(
     288             :                 grammar::error::need_more);
     289             :         }
     290        2380 :         if( *it != ' ' &&
     291        2338 :             *it != '\t')
     292             :         {
     293             :             // end of field
     294        2338 :             break;
     295             :         }
     296             :         // *it will match field_value_rule
     297          42 :         v.has_obs_fold = true;
     298          42 :     }
     299             : 
     300        2338 :     v.value = core::string_view(s0, (it - s0) - 2);
     301        2338 :     BOOST_ASSERT(! v.value.empty());
     302             :     //BOOST_ASSERT(! ws(t.v.value.front()));
     303             : 
     304             :     // remove trailing SP,HTAB,CR,LF
     305        2338 :     auto p = &v.value.back();
     306             :     for(;;)
     307             :     {
     308        2543 :         switch(*p)
     309             :         {
     310         205 :         case ' ':  case '\t':
     311             :         case '\r': case '\n':
     312         205 :             --p;
     313         205 :             continue;
     314        2338 :         default:
     315        2338 :             ++p;
     316        2338 :             goto done;
     317             :         }
     318             :     }
     319        2338 : done:
     320        2338 :     v.value = core::string_view(
     321             :         v.value.data(),
     322        2338 :         p - v.value.data());
     323        2338 :     return v;
     324             : }
     325             : 
     326             : //------------------------------------------------
     327             : 
     328             : void
     329         946 : remove_obs_fold(
     330             :     char* it,
     331             :     char const* const end) noexcept
     332             : {
     333         946 :     while(it != end)
     334             :     {
     335         941 :         if(*it != '\r')
     336             :         {
     337         593 :             ++it;
     338         593 :             continue;
     339             :         }
     340         348 :         if(end - it < 3)
     341         145 :             break;
     342         203 :         BOOST_ASSERT(it[1] == '\n');
     343         406 :         if( it[1] == '\n' &&
     344         203 :             ws(it[2]))
     345             :         {
     346         200 :             it[0] = ' ';
     347         200 :             it[1] = ' ';
     348         200 :             it += 3;
     349             :         }
     350             :         else
     351             :         {
     352           3 :             ++it;
     353             :         }
     354             :     }
     355         150 : }
     356             : 
     357             : } // detail
     358             : } // http_proto
     359             : } // boost
     360             : 
     361             : #endif

Generated by: LCOV version 1.15