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

Generated by: LCOV version 1.15