LCOV - code coverage report
Current view: top level - libs/http_proto/src/rfc/detail/rules.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 95.7 % 162 155
Test Date: 2024-09-20 16:11:51 Functions: 100.0 % 9 9

            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              : 
      12              : #include <boost/http_proto/error.hpp>
      13              : #include <boost/http_proto/detail/config.hpp>
      14              : #include <boost/http_proto/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 "rules.hpp"
      26              : 
      27              : namespace boost {
      28              : namespace http_proto {
      29              : namespace detail {
      30              : 
      31              : auto
      32        22212 : crlf_rule_t::
      33              : parse(
      34              :     char const*& it,
      35              :     char const* end) const noexcept ->
      36              :         system::result<value_type>
      37              : {
      38        22212 :     if(it == end)
      39         1002 :         return grammar::error::need_more;
      40        21210 :     if(*it != '\r')
      41           29 :         return grammar::error::mismatch;
      42        21181 :     ++it;
      43        21181 :     if(it == end)
      44          161 :         return grammar::error::need_more;
      45        21020 :     if(*it != '\n')
      46           51 :         return grammar::error::mismatch;
      47        20969 :     ++it;
      48        20969 :     return {};
      49              : }
      50              : 
      51              : //------------------------------------------------
      52              : 
      53              : auto
      54        11636 : version_rule_t::
      55              : parse(
      56              :     char const*& it,
      57              :     char const* end) const noexcept ->
      58              :         system::result<value_type>
      59              : {
      60        11636 :     value_type v = 0;
      61        11636 :     if(it == end)
      62              :     {
      63              :         // expected "HTTP/"
      64          171 :         BOOST_HTTP_PROTO_RETURN_EC(
      65              :             grammar::error::need_more);
      66              :     }
      67        11465 :     if(end - it >= 5)
      68              :     {
      69        10925 :         if(std::memcmp(
      70              :             it, "HTTP/", 5) != 0)
      71              :         {
      72            0 :             BOOST_HTTP_PROTO_RETURN_EC(
      73              :                 grammar::error::mismatch);
      74              :         }
      75        10925 :         it += 5;
      76              :     }
      77        11465 :     if(it == end)
      78              :     {
      79              :         // expected DIGIT
      80           90 :         BOOST_HTTP_PROTO_RETURN_EC(
      81              :             grammar::error::need_more);
      82              :     }
      83        11375 :     if(! grammar::digit_chars(*it))
      84              :     {
      85              :         // expected DIGIT
      86          540 :         BOOST_HTTP_PROTO_RETURN_EC(
      87              :             grammar::error::need_more);
      88              :     }
      89        10835 :     v = 10 * (*it++ - '0');
      90        10835 :     if(it == end)
      91              :     {
      92              :         // expected "."
      93          234 :         BOOST_HTTP_PROTO_RETURN_EC(
      94              :             grammar::error::need_more);
      95              :     }
      96        10601 :     if(*it != '.')
      97              :     {
      98              :         // expected "."
      99            0 :         BOOST_HTTP_PROTO_RETURN_EC(
     100              :             grammar::error::need_more);
     101              :     }
     102        10601 :     ++it;
     103        10601 :     if(it == end)
     104              :     {
     105              :         // expected DIGIT
     106           89 :         BOOST_HTTP_PROTO_RETURN_EC(
     107              :             grammar::error::need_more);
     108              :     }
     109        10512 :     if(! grammar::digit_chars(*it))
     110              :     {
     111              :         // expected DIGIT
     112            0 :         BOOST_HTTP_PROTO_RETURN_EC(
     113              :             grammar::error::need_more);
     114              :     }
     115        10512 :     v += *it++ - '0';
     116        10512 :     return v;
     117              : }
     118              : 
     119              : //------------------------------------------------
     120              : 
     121              : auto
     122          650 : status_code_rule_t::
     123              : parse(
     124              :     char const*& it,
     125              :     char const* end) const noexcept ->
     126              :         system::result<value_type>
     127              : {
     128              :     auto const dig =
     129         1899 :         [](char c) -> int
     130              :         {
     131         1899 :             unsigned char uc(c - '0');
     132         1899 :             if(uc > 9)
     133            0 :                 return -1;
     134         1899 :             return uc;
     135              :         };
     136              : 
     137          650 :     if(it == end)
     138              :     {
     139              :         // end
     140            9 :         BOOST_HTTP_PROTO_RETURN_EC(
     141              :             grammar::error::need_more);
     142              :     }
     143          641 :     auto it0 = it;
     144          641 :     int v = dig(*it);
     145          641 :     if(v == -1)
     146              :     {
     147              :         // expected DIGIT
     148            0 :         BOOST_HTTP_PROTO_RETURN_EC(
     149              :             grammar::error::mismatch);
     150              :     }
     151          641 :     value_type t;
     152          641 :     t.v = 100 * v;
     153          641 :     ++it;
     154          641 :     if(it == end)
     155              :     {
     156              :         // end
     157            8 :         BOOST_HTTP_PROTO_RETURN_EC(
     158              :             grammar::error::need_more);
     159              :     }
     160          633 :     v = dig(*it);
     161          633 :     if(v == -1)
     162              :     {
     163              :         // expected DIGIT
     164            0 :         BOOST_HTTP_PROTO_RETURN_EC(
     165              :             grammar::error::mismatch);
     166              :     }
     167          633 :     t.v = t.v + (10 * v);
     168          633 :     ++it;
     169          633 :     if(it == end)
     170              :     {
     171              :         // end
     172            8 :         BOOST_HTTP_PROTO_RETURN_EC(
     173              :             grammar::error::need_more);
     174              :     }
     175          625 :     v = dig(*it);
     176          625 :     if(v == -1)
     177              :     {
     178              :         // expected DIGIT
     179            0 :         BOOST_HTTP_PROTO_RETURN_EC(
     180              :             grammar::error::need_more);
     181              :     }
     182          625 :     t.v = t.v + v;
     183          625 :     ++it;
     184              : 
     185          625 :     t.s = core::string_view(it0, it - it0);
     186          625 :     t.st = int_to_status(t.v);
     187          625 :     return t;
     188              : }
     189              : 
     190              : //------------------------------------------------
     191              : 
     192              : auto
     193        12883 : field_name_rule_t::
     194              : parse(
     195              :     char const*& it,
     196              :     char const* end) const noexcept ->
     197              :         system::result<value_type>
     198              : {
     199        12883 :     if( it == end )
     200            1 :         BOOST_HTTP_PROTO_RETURN_EC(
     201              :             grammar::error::need_more);
     202              : 
     203        12882 :     value_type v;
     204              : 
     205        12882 :     auto begin = it;
     206        12882 :     auto rv = grammar::parse(
     207              :         it, end, token_rule);
     208        12882 :     if( rv.has_error() || (it != end) )
     209              :     {
     210        12279 :         if( it != begin )
     211              :         {
     212        12214 :             v = core::string_view(begin, it - begin);
     213        12214 :             return v;
     214              :         }
     215           65 :         return error::bad_field_name;
     216              :     }
     217              : 
     218          603 :     v = core::string_view(begin, end - begin);
     219          603 :     return v;
     220              : }
     221              : 
     222              : auto
     223        12461 : field_value_rule_t::
     224              : parse(
     225              :     char const*& it,
     226              :     char const* end) const noexcept ->
     227              :         system::result<value_type>
     228              : {
     229        12461 :     value_type v;
     230        12461 :     if( it == end )
     231              :     {
     232          199 :         v.value = core::string_view(it, 0);
     233          199 :         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        54861 :     auto is_field_vchar = [](unsigned char ch)
     246              :     {
     247        54861 :       return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
     248              :     };
     249              : 
     250        12262 :     char const* s0 = nullptr;
     251        12262 :     char const* s1 = nullptr;
     252              : 
     253        12262 :     bool has_crlf = false;
     254        12262 :     bool has_obs_fold = false;
     255              : 
     256        81978 :     while( it < end )
     257              :     {
     258        81020 :         auto ch = *it;
     259        81020 :         if( ws(ch) )
     260              :         {
     261        14173 :             ++it;
     262        14173 :             continue;
     263              :         }
     264              : 
     265        66847 :         if( ch == '\r' )
     266              :         {
     267              :             // too short to know if we have a potential obs-fold
     268              :             // occurrence
     269        11986 :             if( end - it < 2 )
     270          200 :                 BOOST_HTTP_PROTO_RETURN_EC(
     271              :                     grammar::error::need_more);
     272              : 
     273        11786 :             if( it[1] != '\n' )
     274           53 :                 goto done;
     275              : 
     276        11733 :             if( end - it < 3 )
     277          171 :                 BOOST_HTTP_PROTO_RETURN_EC(
     278              :                     grammar::error::need_more);
     279              : 
     280        11562 :             if(! ws(it[2]) )
     281              :             {
     282        10846 :                 has_crlf = true;
     283        10846 :                 goto done;
     284              :             }
     285              : 
     286          716 :             has_obs_fold = true;
     287          716 :             it = it + 3;
     288          716 :             continue;
     289          716 :         }
     290              : 
     291        54861 :         if(! is_field_vchar(ch) )
     292              :         {
     293           34 :             goto done;
     294              :         }
     295              : 
     296        54827 :         if(! s0 )
     297        11637 :             s0 = it;
     298              : 
     299        54827 :         ++it;
     300        54827 :         s1 = it;
     301              :     }
     302              : 
     303          958 : done:
     304              :     // later routines wind up doing pointer
     305              :     // subtraction using the .data() member
     306              :     // of the value so we need a valid 0-len range
     307        11891 :     if(! s0 )
     308              :     {
     309          462 :         s0 = it;
     310          462 :         s1 = s0;
     311              :     }
     312              : 
     313        11891 :     v.value = core::string_view(s0, s1 - s0);
     314        11891 :     v.has_crlf = has_crlf;
     315        11891 :     v.has_obs_fold = has_obs_fold;
     316        11891 :     return v;
     317              : }
     318              : 
     319              : auto
     320        23041 : field_rule_t::
     321              : parse(
     322              :     char const*& it,
     323              :     char const* end) const noexcept ->
     324              :         system::result<value_type>
     325              : {
     326        23041 :     if(it == end)
     327              :     {
     328          197 :         BOOST_HTTP_PROTO_RETURN_EC(
     329              :             grammar::error::need_more);
     330              :     }
     331              :     // check for leading CRLF
     332        22844 :     if(it[0] == '\r')
     333              :     {
     334        10266 :         ++it;
     335        10266 :         if(it == end)
     336              :         {
     337          134 :             BOOST_HTTP_PROTO_RETURN_EC(
     338              :                 grammar::error::need_more);
     339              :         }
     340        10132 :         if(*it != '\n')
     341              :         {
     342           21 :             BOOST_HTTP_PROTO_RETURN_EC(
     343              :                 grammar::error::mismatch);
     344              :         }
     345              :         // end of fields
     346        10111 :         ++it;
     347        10111 :         BOOST_HTTP_PROTO_RETURN_EC(
     348              :             grammar::error::end_of_range);
     349              :     }
     350              : 
     351        12578 :     value_type v;
     352              :     auto rv = grammar::parse(
     353        12578 :         it, end, grammar::tuple_rule(
     354              :             field_name_rule,
     355        12578 :             grammar::delim_rule(':'),
     356              :             field_value_rule,
     357        12578 :             crlf_rule));
     358              : 
     359        12578 :     if( rv.has_error() )
     360         1739 :         return rv.error();
     361              : 
     362        10839 :     auto val = rv.value();
     363        10839 :     v.name = std::get<0>(val);
     364        10839 :     v.value = std::get<2>(val).value;
     365        10839 :     v.has_obs_fold = std::get<2>(val).has_obs_fold;
     366              : 
     367        10839 :     return v;
     368              : }
     369              : 
     370              : //------------------------------------------------
     371              : 
     372              : void
     373          241 : remove_obs_fold(
     374              :     char* it,
     375              :     char const* const end) noexcept
     376              : {
     377         2247 :     while(it != end)
     378              :     {
     379         2224 :         if(*it != '\r')
     380              :         {
     381         1628 :             ++it;
     382         1628 :             continue;
     383              :         }
     384          596 :         if(end - it < 3)
     385          218 :             break;
     386          378 :         BOOST_ASSERT(it[1] == '\n');
     387          756 :         if( it[1] == '\n' &&
     388          378 :             ws(it[2]))
     389              :         {
     390          375 :             it[0] = ' ';
     391          375 :             it[1] = ' ';
     392          375 :             it += 3;
     393              :         }
     394              :         else
     395              :         {
     396            3 :             ++it;
     397              :         }
     398              :     }
     399          241 : }
     400              : 
     401              : } // detail
     402              : } // http_proto
     403              : } // boost
        

Generated by: LCOV version 2.1