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: 134 150 89.3 %
Date: 2023-01-26 23:44:13 Functions: 6 6 100.0 %

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