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: 154 161 95.7 %
Date: 2024-05-09 08:15:19 Functions: 9 9 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             : 
      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/lut_chars.hpp>
      21             : #include <boost/url/grammar/parse.hpp>
      22             : #include <boost/url/grammar/tuple_rule.hpp>
      23             : 
      24             : #include "rules.hpp"
      25             : 
      26             : namespace boost {
      27             : namespace http_proto {
      28             : namespace detail {
      29             : 
      30             : auto
      31        5952 : crlf_rule_t::
      32             : parse(
      33             :     char const*& it,
      34             :     char const* end) const noexcept ->
      35             :         system::result<value_type>
      36             : {
      37        5952 :     if(it == end)
      38        1002 :         return grammar::error::need_more;
      39        4950 :     if(*it != '\r')
      40          29 :         return grammar::error::mismatch;
      41        4921 :     ++it;
      42        4921 :     if(it == end)
      43         161 :         return grammar::error::need_more;
      44        4760 :     if(*it != '\n')
      45          51 :         return grammar::error::mismatch;
      46        4709 :     ++it;
      47        4709 :     return {};
      48             : }
      49             : 
      50             : //------------------------------------------------
      51             : 
      52             : auto
      53        3506 : version_rule_t::
      54             : parse(
      55             :     char const*& it,
      56             :     char const* end) const noexcept ->
      57             :         system::result<value_type>
      58             : {
      59        3506 :     value_type v = 0;
      60        3506 :     if(it == end)
      61             :     {
      62             :         // expected "HTTP/"
      63         171 :         BOOST_HTTP_PROTO_RETURN_EC(
      64             :             grammar::error::need_more);
      65             :     }
      66        3335 :     if(end - it >= 5)
      67             :     {
      68        2795 :         if(std::memcmp(
      69             :             it, "HTTP/", 5) != 0)
      70             :         {
      71           0 :             BOOST_HTTP_PROTO_RETURN_EC(
      72             :                 grammar::error::mismatch);
      73             :         }
      74        2795 :         it += 5;
      75             :     }
      76        3335 :     if(it == end)
      77             :     {
      78             :         // expected DIGIT
      79          90 :         BOOST_HTTP_PROTO_RETURN_EC(
      80             :             grammar::error::need_more);
      81             :     }
      82        3245 :     if(! grammar::digit_chars(*it))
      83             :     {
      84             :         // expected DIGIT
      85         540 :         BOOST_HTTP_PROTO_RETURN_EC(
      86             :             grammar::error::need_more);
      87             :     }
      88        2705 :     v = 10 * (*it++ - '0');
      89        2705 :     if(it == end)
      90             :     {
      91             :         // expected "."
      92         234 :         BOOST_HTTP_PROTO_RETURN_EC(
      93             :             grammar::error::need_more);
      94             :     }
      95        2471 :     if(*it != '.')
      96             :     {
      97             :         // expected "."
      98           0 :         BOOST_HTTP_PROTO_RETURN_EC(
      99             :             grammar::error::need_more);
     100             :     }
     101        2471 :     ++it;
     102        2471 :     if(it == end)
     103             :     {
     104             :         // expected DIGIT
     105          89 :         BOOST_HTTP_PROTO_RETURN_EC(
     106             :             grammar::error::need_more);
     107             :     }
     108        2382 :     if(! grammar::digit_chars(*it))
     109             :     {
     110             :         // expected DIGIT
     111           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     112             :             grammar::error::need_more);
     113             :     }
     114        2382 :     v += *it++ - '0';
     115        2382 :     return v;
     116             : }
     117             : 
     118             : //------------------------------------------------
     119             : 
     120             : auto
     121         520 : status_code_rule_t::
     122             : parse(
     123             :     char const*& it,
     124             :     char const* end) const noexcept ->
     125             :         system::result<value_type>
     126             : {
     127             :     auto const dig =
     128        1509 :         [](char c) -> int
     129             :         {
     130        1509 :             unsigned char uc(c - '0');
     131        1509 :             if(uc > 9)
     132           0 :                 return -1;
     133        1509 :             return uc;
     134             :         };
     135             : 
     136         520 :     if(it == end)
     137             :     {
     138             :         // end
     139           9 :         BOOST_HTTP_PROTO_RETURN_EC(
     140             :             grammar::error::need_more);
     141             :     }
     142         511 :     auto it0 = it;
     143         511 :     int v = dig(*it);
     144         511 :     if(v == -1)
     145             :     {
     146             :         // expected DIGIT
     147           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     148             :             grammar::error::mismatch);
     149             :     }
     150         511 :     value_type t;
     151         511 :     t.v = 100 * v;
     152         511 :     ++it;
     153         511 :     if(it == end)
     154             :     {
     155             :         // end
     156           8 :         BOOST_HTTP_PROTO_RETURN_EC(
     157             :             grammar::error::need_more);
     158             :     }
     159         503 :     v = dig(*it);
     160         503 :     if(v == -1)
     161             :     {
     162             :         // expected DIGIT
     163           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     164             :             grammar::error::mismatch);
     165             :     }
     166         503 :     t.v = t.v + (10 * v);
     167         503 :     ++it;
     168         503 :     if(it == end)
     169             :     {
     170             :         // end
     171           8 :         BOOST_HTTP_PROTO_RETURN_EC(
     172             :             grammar::error::need_more);
     173             :     }
     174         495 :     v = dig(*it);
     175         495 :     if(v == -1)
     176             :     {
     177             :         // expected DIGIT
     178           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     179             :             grammar::error::need_more);
     180             :     }
     181         495 :     t.v = t.v + v;
     182         495 :     ++it;
     183             : 
     184         495 :     t.s = core::string_view(it0, it - it0);
     185         495 :     t.st = int_to_status(t.v);
     186         495 :     return t;
     187             : }
     188             : 
     189             : //------------------------------------------------
     190             : 
     191             : auto
     192        4681 : field_name_rule_t::
     193             : parse(
     194             :     char const*& it,
     195             :     char const* end) const noexcept ->
     196             :         system::result<value_type>
     197             : {
     198        4681 :     if( it == end )
     199           1 :         BOOST_HTTP_PROTO_RETURN_EC(
     200             :             grammar::error::need_more);
     201             : 
     202        4680 :     value_type v;
     203             : 
     204        4680 :     auto begin = it;
     205             :     auto rv = grammar::parse(
     206        4680 :         it, end, token_rule);
     207        4680 :     if( rv.has_error() || (it != end) )
     208             :     {
     209        4149 :         if( it != begin )
     210             :         {
     211        4084 :             v = core::string_view(begin, it - begin);
     212        4084 :             return v;
     213             :         }
     214          65 :         return error::bad_field_name;
     215             :     }
     216             : 
     217         531 :     v = core::string_view(begin, end - begin);
     218         531 :     return v;
     219             : }
     220             : 
     221             : auto
     222        4259 : field_value_rule_t::
     223             : parse(
     224             :     char const*& it,
     225             :     char const* end) const noexcept ->
     226             :         system::result<value_type>
     227             : {
     228        4259 :     value_type v;
     229        4259 :     if( it == end )
     230             :     {
     231         199 :         v.value = core::string_view(it, 0);
     232         199 :         return v;
     233             :     }
     234             : 
     235             :     // field-line     = field-name ":" OWS field-value OWS
     236             :     // field-value    = *field-content
     237             :     // field-content  = field-vchar
     238             :     //                  [ 1*( SP / HTAB / field-vchar ) field-vchar ]
     239             :     // field-vchar    = VCHAR / obs-text
     240             :     // obs-text       = %x80-FF
     241             :     // VCHAR          = %x21-7E
     242             :     //                       ; visible (printing) characters
     243             : 
     244       14829 :     auto is_field_vchar = [](unsigned char ch)
     245             :     {
     246       14829 :       return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
     247             :     };
     248             : 
     249        4060 :     char const* s0 = nullptr;
     250        4060 :     char const* s1 = nullptr;
     251             : 
     252        4060 :     bool has_crlf = false;
     253        4060 :     bool has_obs_fold = false;
     254             : 
     255       25614 :     while( it < end )
     256             :     {
     257       24728 :         auto ch = *it;
     258       24728 :         if( ws(ch) )
     259             :         {
     260        6043 :             ++it;
     261        6043 :             continue;
     262             :         }
     263             : 
     264       18685 :         if( ch == '\r' )
     265             :         {
     266             :             // too short to know if we have a potential obs-fold
     267             :             // occurrence
     268        3856 :             if( end - it < 2 )
     269         200 :                 BOOST_HTTP_PROTO_RETURN_EC(
     270             :                     grammar::error::need_more);
     271             : 
     272        3656 :             if( it[1] != '\n' )
     273          53 :                 goto done;
     274             : 
     275        3603 :             if( end - it < 3 )
     276         171 :                 BOOST_HTTP_PROTO_RETURN_EC(
     277             :                     grammar::error::need_more);
     278             : 
     279        3432 :             if(! ws(it[2]) )
     280             :             {
     281        2716 :                 has_crlf = true;
     282        2716 :                 goto done;
     283             :             }
     284             : 
     285         716 :             has_obs_fold = true;
     286         716 :             it = it + 3;
     287         716 :             continue;
     288             :         }
     289             : 
     290       14829 :         if(! is_field_vchar(ch) )
     291             :         {
     292          34 :             goto done;
     293             :         }
     294             : 
     295       14795 :         if(! s0 )
     296        3435 :             s0 = it;
     297             : 
     298       14795 :         ++it;
     299       14795 :         s1 = it;
     300             :     }
     301             : 
     302         886 : done:
     303             :     // later routines wind up doing pointer
     304             :     // subtraction using the .data() member
     305             :     // of the value so we need a valid 0-len range
     306        3689 :     if(! s0 )
     307             :     {
     308         462 :         s0 = it;
     309         462 :         s1 = s0;
     310             :     }
     311             : 
     312        3689 :     v.value = core::string_view(s0, s1 - s0);
     313        3689 :     v.has_crlf = has_crlf;
     314        3689 :     v.has_obs_fold = has_obs_fold;
     315        3689 :     return v;
     316             : }
     317             : 
     318             : auto
     319        6781 : field_rule_t::
     320             : parse(
     321             :     char const*& it,
     322             :     char const* end) const noexcept ->
     323             :         system::result<value_type>
     324             : {
     325        6781 :     if(it == end)
     326             :     {
     327         197 :         BOOST_HTTP_PROTO_RETURN_EC(
     328             :             grammar::error::need_more);
     329             :     }
     330             :     // check for leading CRLF
     331        6584 :     if(it[0] == '\r')
     332             :     {
     333        2136 :         ++it;
     334        2136 :         if(it == end)
     335             :         {
     336         134 :             BOOST_HTTP_PROTO_RETURN_EC(
     337             :                 grammar::error::need_more);
     338             :         }
     339        2002 :         if(*it != '\n')
     340             :         {
     341          21 :             BOOST_HTTP_PROTO_RETURN_EC(
     342             :                 grammar::error::mismatch);
     343             :         }
     344             :         // end of fields
     345        1981 :         ++it;
     346        1981 :         BOOST_HTTP_PROTO_RETURN_EC(
     347             :             grammar::error::end_of_range);
     348             :     }
     349             : 
     350        4448 :     value_type v;
     351             :     auto rv = grammar::parse(
     352        4448 :         it, end, grammar::tuple_rule(
     353             :             field_name_rule,
     354        4448 :             grammar::delim_rule(':'),
     355             :             field_value_rule,
     356        4448 :             crlf_rule));
     357             : 
     358        4448 :     if( rv.has_error() )
     359        1739 :         return rv.error();
     360             : 
     361        2709 :     auto val = rv.value();
     362        2709 :     v.name = std::get<0>(val);
     363        2709 :     v.value = std::get<2>(val).value;
     364        2709 :     v.has_obs_fold = std::get<2>(val).has_obs_fold;
     365             : 
     366        2709 :     return v;
     367             : }
     368             : 
     369             : //------------------------------------------------
     370             : 
     371             : void
     372        2247 : remove_obs_fold(
     373             :     char* it,
     374             :     char const* const end) noexcept
     375             : {
     376        2247 :     while(it != end)
     377             :     {
     378        2224 :         if(*it != '\r')
     379             :         {
     380        1628 :             ++it;
     381        1628 :             continue;
     382             :         }
     383         596 :         if(end - it < 3)
     384         218 :             break;
     385         378 :         BOOST_ASSERT(it[1] == '\n');
     386         756 :         if( it[1] == '\n' &&
     387         378 :             ws(it[2]))
     388             :         {
     389         375 :             it[0] = ' ';
     390         375 :             it[1] = ' ';
     391         375 :             it += 3;
     392             :         }
     393             :         else
     394             :         {
     395           3 :             ++it;
     396             :         }
     397             :     }
     398         241 : }
     399             : 
     400             : } // detail
     401             : } // http_proto
     402             : } // boost

Generated by: LCOV version 1.15