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-03-01 04:29:22 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       43158 : crlf_rule_t::
      22             : parse(
      23             :     char const*& it,
      24             :     char const* end) const noexcept ->
      25             :         system::result<value_type>
      26             : {
      27       43158 :     if(it == end)
      28        3861 :         return grammar::error::need_more;
      29       39297 :     if(*it != '\r')
      30           0 :         return grammar::error::mismatch;
      31       39297 :     ++it;
      32       39297 :     if(it == end)
      33        1553 :         return grammar::error::need_more;
      34       37744 :     if(*it != '\n')
      35           0 :         return grammar::error::mismatch;
      36       37744 :     ++it;
      37       37744 :     return {};
      38             : }
      39             : 
      40             : //------------------------------------------------
      41             : 
      42             : auto
      43       23617 : version_rule_t::
      44             : parse(
      45             :     char const*& it,
      46             :     char const* end) const noexcept ->
      47             :         system::result<value_type>
      48             : {
      49       23617 :     value_type v = 0;
      50       23617 :     if(it == end)
      51             :     {
      52             :         // expected "HTTP/"
      53         671 :         BOOST_HTTP_PROTO_RETURN_EC(
      54             :             grammar::error::need_more);
      55             :     }
      56       22946 :     if(end - it >= 5)
      57             :     {
      58       20343 :         if(std::memcmp(
      59             :             it, "HTTP/", 5) != 0)
      60             :         {
      61           0 :             BOOST_HTTP_PROTO_RETURN_EC(
      62             :                 grammar::error::mismatch);
      63             :         }
      64       20343 :         it += 5;
      65             :     }
      66       22946 :     if(it == end)
      67             :     {
      68             :         // expected DIGIT
      69         617 :         BOOST_HTTP_PROTO_RETURN_EC(
      70             :             grammar::error::need_more);
      71             :     }
      72       22329 :     if(! grammar::digit_chars(*it))
      73             :     {
      74             :         // expected DIGIT
      75        2603 :         BOOST_HTTP_PROTO_RETURN_EC(
      76             :             grammar::error::need_more);
      77             :     }
      78       19726 :     v = 10 * (*it++ - '0');
      79       19726 :     if(it == end)
      80             :     {
      81             :         // expected "."
      82         725 :         BOOST_HTTP_PROTO_RETURN_EC(
      83             :             grammar::error::need_more);
      84             :     }
      85       19001 :     if(*it != '.')
      86             :     {
      87             :         // expected "."
      88           0 :         BOOST_HTTP_PROTO_RETURN_EC(
      89             :             grammar::error::need_more);
      90             :     }
      91       19001 :     ++it;
      92       19001 :     if(it == end)
      93             :     {
      94             :         // expected DIGIT
      95         617 :         BOOST_HTTP_PROTO_RETURN_EC(
      96             :             grammar::error::need_more);
      97             :     }
      98       18384 :     if(! grammar::digit_chars(*it))
      99             :     {
     100             :         // expected DIGIT
     101           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     102             :             grammar::error::need_more);
     103             :     }
     104       18384 :     v += *it++ - '0';
     105       18384 :     return v;
     106             : }
     107             : 
     108             : //------------------------------------------------
     109             : 
     110             : auto
     111       11100 : 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       31152 :         [](char c) -> int
     119             :         {
     120       31152 :             unsigned char uc(c - '0');
     121       31152 :             if(uc > 9)
     122           0 :                 return -1;
     123       31152 :             return uc;
     124             :         };
     125             :         
     126       11100 :     if(it == end)
     127             :     {
     128             :         // end
     129         358 :         BOOST_HTTP_PROTO_RETURN_EC(
     130             :             grammar::error::need_more);
     131             :     }
     132       10742 :     auto it0 = it;
     133       10742 :     int v = dig(*it);
     134       10742 :     if(v == -1)
     135             :     {
     136             :         // expected DIGIT
     137           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     138             :             grammar::error::mismatch);
     139             :     }
     140       10742 :     value_type t;
     141       10742 :     t.v = 100 * v;
     142       10742 :     ++it;
     143       10742 :     if(it == end)
     144             :     {
     145             :         // end
     146         358 :         BOOST_HTTP_PROTO_RETURN_EC(
     147             :             grammar::error::need_more);
     148             :     }
     149       10384 :     v = dig(*it);
     150       10384 :     if(v == -1)
     151             :     {
     152             :         // expected DIGIT
     153           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     154             :             grammar::error::mismatch);
     155             :     }
     156       10384 :     t.v = t.v + (10 * v);
     157       10384 :     ++it;
     158       10384 :     if(it == end)
     159             :     {
     160             :         // end
     161         358 :         BOOST_HTTP_PROTO_RETURN_EC(
     162             :             grammar::error::need_more);
     163             :     }
     164       10026 :     v = dig(*it);
     165       10026 :     if(v == -1)
     166             :     {
     167             :         // expected DIGIT
     168           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     169             :             grammar::error::need_more);
     170             :     }
     171       10026 :     t.v = t.v + v;
     172       10026 :     ++it;
     173             : 
     174       10026 :     t.s = core::string_view(it0, it - it0);
     175       10026 :     t.st = int_to_status(t.v);
     176       10026 :     return t;
     177             : }
     178             : 
     179             : //------------------------------------------------
     180             : 
     181             : auto
     182       52722 : field_rule_t::
     183             : parse(
     184             :     char const*& it,
     185             :     char const* end) const noexcept ->
     186             :         system::result<value_type>
     187             : {
     188       52722 :     if(it == end)
     189             :     {
     190         698 :         BOOST_HTTP_PROTO_RETURN_EC(
     191             :             grammar::error::need_more);
     192             :     }
     193             :     // check for leading CRLF
     194       52024 :     if(it[0] == '\r')
     195             :     {
     196       15262 :         ++it;
     197       15262 :         if(it == end)
     198             :         {
     199         657 :             BOOST_HTTP_PROTO_RETURN_EC(
     200             :                 grammar::error::need_more);
     201             :         }
     202       14605 :         if(*it != '\n')
     203             :         {
     204           0 :             BOOST_HTTP_PROTO_RETURN_EC(
     205             :                 grammar::error::mismatch);
     206             :         }
     207             :         // end of fields
     208       14605 :         ++it;
     209       14605 :         BOOST_HTTP_PROTO_RETURN_EC(
     210             :             grammar::error::end_of_range);
     211             :     }
     212             : 
     213       36762 :     value_type v;
     214             : 
     215             :     // field name
     216             :     {
     217             :         auto rv = grammar::parse(
     218       36762 :             it, end, grammar::tuple_rule(
     219             :                 token_rule,
     220       36762 :                 grammar::squelch(
     221       36762 :                     grammar::delim_rule(':'))));
     222       36762 :         if(! rv)
     223        7820 :             return rv.error();
     224       28942 :         v.name = rv.value();
     225             :     }
     226             : 
     227             :     // consume all obs-fold until
     228             :     // field char or end of field
     229             :     for(;;)
     230             :     {
     231       29236 :         skip_ows(it, end);
     232       29236 :         if(it == end)
     233             :         {
     234        1802 :             BOOST_HTTP_PROTO_RETURN_EC(
     235             :                 grammar::error::need_more);
     236             :         }
     237       27434 :         if(*it != '\r')
     238             :         {
     239             :             // start of value
     240       26880 :             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       26880 :     char const* s0 = it; // start of value
     276             :     for(;;)
     277             :     {
     278             :         auto rv = grammar::parse(
     279       26922 :             it, end, grammar::tuple_rule(
     280       26922 :                 grammar::token_rule(
     281       26922 :                     ws_vchars),
     282       26922 :                 crlf_rule));
     283       26922 :         if(! rv)
     284        3714 :             return rv.error();
     285       23208 :         if(it == end)
     286             :         {
     287         858 :             BOOST_HTTP_PROTO_RETURN_EC(
     288             :                 grammar::error::need_more);
     289             :         }
     290       22350 :         if( *it != ' ' &&
     291       22308 :             *it != '\t')
     292             :         {
     293             :             // end of field
     294       22308 :             break;
     295             :         }
     296             :         // *it will match field_value_rule
     297          42 :         v.has_obs_fold = true;
     298          42 :     }
     299             : 
     300       22308 :     v.value = core::string_view(s0, (it - s0) - 2);
     301       22308 :     BOOST_ASSERT(! v.value.empty());
     302             :     //BOOST_ASSERT(! ws(t.v.value.front()));
     303             : 
     304             :     // remove trailing SP,HTAB,CR,LF
     305       22308 :     auto p = &v.value.back();
     306             :     for(;;)
     307             :     {
     308       22513 :         switch(*p)
     309             :         {
     310         205 :         case ' ':  case '\t':
     311             :         case '\r': case '\n':
     312         205 :             --p;
     313         205 :             continue;
     314       22308 :         default:
     315       22308 :             ++p;
     316       22308 :             goto done;
     317             :         }
     318             :     }
     319       22308 : done:
     320       22308 :     v.value = core::string_view(
     321             :         v.value.data(),
     322       22308 :         p - v.value.data());
     323       22308 :     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