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-02-09 15:32:01 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        5910 : crlf_rule_t::
      32             : parse(
      33             :     char const*& it,
      34             :     char const* end) const noexcept ->
      35             :         system::result<value_type>
      36             : {
      37        5910 :     if(it == end)
      38        1002 :         return grammar::error::need_more;
      39        4908 :     if(*it != '\r')
      40          29 :         return grammar::error::mismatch;
      41        4879 :     ++it;
      42        4879 :     if(it == end)
      43         161 :         return grammar::error::need_more;
      44        4718 :     if(*it != '\n')
      45          51 :         return grammar::error::mismatch;
      46        4667 :     ++it;
      47        4667 :     return {};
      48             : }
      49             : 
      50             : //------------------------------------------------
      51             : 
      52             : auto
      53        3488 : version_rule_t::
      54             : parse(
      55             :     char const*& it,
      56             :     char const* end) const noexcept ->
      57             :         system::result<value_type>
      58             : {
      59        3488 :     value_type v = 0;
      60        3488 :     if(it == end)
      61             :     {
      62             :         // expected "HTTP/"
      63         171 :         BOOST_HTTP_PROTO_RETURN_EC(
      64             :             grammar::error::need_more);
      65             :     }
      66        3317 :     if(end - it >= 5)
      67             :     {
      68        2777 :         if(std::memcmp(
      69             :             it, "HTTP/", 5) != 0)
      70             :         {
      71           0 :             BOOST_HTTP_PROTO_RETURN_EC(
      72             :                 grammar::error::mismatch);
      73             :         }
      74        2777 :         it += 5;
      75             :     }
      76        3317 :     if(it == end)
      77             :     {
      78             :         // expected DIGIT
      79          90 :         BOOST_HTTP_PROTO_RETURN_EC(
      80             :             grammar::error::need_more);
      81             :     }
      82        3227 :     if(! grammar::digit_chars(*it))
      83             :     {
      84             :         // expected DIGIT
      85         540 :         BOOST_HTTP_PROTO_RETURN_EC(
      86             :             grammar::error::need_more);
      87             :     }
      88        2687 :     v = 10 * (*it++ - '0');
      89        2687 :     if(it == end)
      90             :     {
      91             :         // expected "."
      92         234 :         BOOST_HTTP_PROTO_RETURN_EC(
      93             :             grammar::error::need_more);
      94             :     }
      95        2453 :     if(*it != '.')
      96             :     {
      97             :         // expected "."
      98           0 :         BOOST_HTTP_PROTO_RETURN_EC(
      99             :             grammar::error::need_more);
     100             :     }
     101        2453 :     ++it;
     102        2453 :     if(it == end)
     103             :     {
     104             :         // expected DIGIT
     105          89 :         BOOST_HTTP_PROTO_RETURN_EC(
     106             :             grammar::error::need_more);
     107             :     }
     108        2364 :     if(! grammar::digit_chars(*it))
     109             :     {
     110             :         // expected DIGIT
     111           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     112             :             grammar::error::need_more);
     113             :     }
     114        2364 :     v += *it++ - '0';
     115        2364 :     return v;
     116             : }
     117             : 
     118             : //------------------------------------------------
     119             : 
     120             : auto
     121         508 : 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        1473 :         [](char c) -> int
     129             :         {
     130        1473 :             unsigned char uc(c - '0');
     131        1473 :             if(uc > 9)
     132           0 :                 return -1;
     133        1473 :             return uc;
     134             :         };
     135             : 
     136         508 :     if(it == end)
     137             :     {
     138             :         // end
     139           9 :         BOOST_HTTP_PROTO_RETURN_EC(
     140             :             grammar::error::need_more);
     141             :     }
     142         499 :     auto it0 = it;
     143         499 :     int v = dig(*it);
     144         499 :     if(v == -1)
     145             :     {
     146             :         // expected DIGIT
     147           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     148             :             grammar::error::mismatch);
     149             :     }
     150         499 :     value_type t;
     151         499 :     t.v = 100 * v;
     152         499 :     ++it;
     153         499 :     if(it == end)
     154             :     {
     155             :         // end
     156           8 :         BOOST_HTTP_PROTO_RETURN_EC(
     157             :             grammar::error::need_more);
     158             :     }
     159         491 :     v = dig(*it);
     160         491 :     if(v == -1)
     161             :     {
     162             :         // expected DIGIT
     163           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     164             :             grammar::error::mismatch);
     165             :     }
     166         491 :     t.v = t.v + (10 * v);
     167         491 :     ++it;
     168         491 :     if(it == end)
     169             :     {
     170             :         // end
     171           8 :         BOOST_HTTP_PROTO_RETURN_EC(
     172             :             grammar::error::need_more);
     173             :     }
     174         483 :     v = dig(*it);
     175         483 :     if(v == -1)
     176             :     {
     177             :         // expected DIGIT
     178           0 :         BOOST_HTTP_PROTO_RETURN_EC(
     179             :             grammar::error::need_more);
     180             :     }
     181         483 :     t.v = t.v + v;
     182         483 :     ++it;
     183             : 
     184         483 :     t.s = core::string_view(it0, it - it0);
     185         483 :     t.st = int_to_status(t.v);
     186         483 :     return t;
     187             : }
     188             : 
     189             : //------------------------------------------------
     190             : 
     191             : auto
     192        4533 : field_name_rule_t::
     193             : parse(
     194             :     char const*& it,
     195             :     char const* end) const noexcept ->
     196             :         system::result<value_type>
     197             : {
     198        4533 :     if( it == end )
     199           1 :         BOOST_HTTP_PROTO_RETURN_EC(
     200             :             grammar::error::need_more);
     201             : 
     202        4532 :     value_type v;
     203             : 
     204        4532 :     auto begin = it;
     205             :     auto rv = grammar::parse(
     206        4532 :         it, end, token_rule);
     207        4532 :     if( rv.has_error() || (it != end) )
     208             :     {
     209        4125 :         if( it != begin )
     210             :         {
     211        4060 :             v = core::string_view(begin, it - begin);
     212        4060 :             return v;
     213             :         }
     214          65 :         return error::bad_field_name;
     215             :     }
     216             : 
     217         407 :     v = core::string_view(begin, end - begin);
     218         407 :     return v;
     219             : }
     220             : 
     221             : auto
     222        4107 : field_value_rule_t::
     223             : parse(
     224             :     char const*& it,
     225             :     char const* end) const noexcept ->
     226             :         system::result<value_type>
     227             : {
     228        4107 :     value_type v;
     229        4107 :     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       13657 :     auto is_field_vchar = [](unsigned char ch)
     245             :     {
     246       13657 :       return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
     247             :     };
     248             : 
     249        3908 :     char const* s0 = nullptr;
     250        3908 :     char const* s1 = nullptr;
     251             : 
     252        3908 :     bool has_crlf = false;
     253        3908 :     bool has_obs_fold = false;
     254             : 
     255       24266 :     while( it < end )
     256             :     {
     257       23508 :         auto ch = *it;
     258       23508 :         if( ws(ch) )
     259             :         {
     260        6019 :             ++it;
     261        6019 :             continue;
     262             :         }
     263             : 
     264       17489 :         if( ch == '\r' )
     265             :         {
     266             :             // too short to know if we have a potential obs-fold
     267             :             // occurrence
     268        3832 :             if( end - it < 2 )
     269         200 :                 BOOST_HTTP_PROTO_RETURN_EC(
     270             :                     grammar::error::need_more);
     271             : 
     272        3632 :             if( it[1] != '\n' )
     273          53 :                 goto done;
     274             : 
     275        3579 :             if( end - it < 3 )
     276         171 :                 BOOST_HTTP_PROTO_RETURN_EC(
     277             :                     grammar::error::need_more);
     278             : 
     279        3408 :             if(! ws(it[2]) )
     280             :             {
     281        2692 :                 has_crlf = true;
     282        2692 :                 goto done;
     283             :             }
     284             : 
     285         716 :             has_obs_fold = true;
     286         716 :             it = it + 3;
     287         716 :             continue;
     288             :         }
     289             : 
     290       13657 :         if(! is_field_vchar(ch) )
     291             :         {
     292          34 :             goto done;
     293             :         }
     294             : 
     295       13623 :         if(! s0 )
     296        3283 :             s0 = it;
     297             : 
     298       13623 :         ++it;
     299       13623 :         s1 = it;
     300             :     }
     301             : 
     302         758 : 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        3537 :     if(! s0 )
     307             :     {
     308         462 :         s0 = it;
     309         462 :         s1 = s0;
     310             :     }
     311             : 
     312        3537 :     v.value = core::string_view(s0, s1 - s0);
     313        3537 :     v.has_crlf = has_crlf;
     314        3537 :     v.has_obs_fold = has_obs_fold;
     315        3537 :     return v;
     316             : }
     317             : 
     318             : auto
     319        6738 : field_rule_t::
     320             : parse(
     321             :     char const*& it,
     322             :     char const* end) const noexcept ->
     323             :         system::result<value_type>
     324             : {
     325        6738 :     if(it == end)
     326             :     {
     327         197 :         BOOST_HTTP_PROTO_RETURN_EC(
     328             :             grammar::error::need_more);
     329             :     }
     330             :     // check for leading CRLF
     331        6541 :     if(it[0] == '\r')
     332             :     {
     333        2117 :         ++it;
     334        2117 :         if(it == end)
     335             :         {
     336         134 :             BOOST_HTTP_PROTO_RETURN_EC(
     337             :                 grammar::error::need_more);
     338             :         }
     339        1983 :         if(*it != '\n')
     340             :         {
     341          21 :             BOOST_HTTP_PROTO_RETURN_EC(
     342             :                 grammar::error::mismatch);
     343             :         }
     344             :         // end of fields
     345        1962 :         ++it;
     346        1962 :         BOOST_HTTP_PROTO_RETURN_EC(
     347             :             grammar::error::end_of_range);
     348             :     }
     349             : 
     350        4424 :     value_type v;
     351             :     auto rv = grammar::parse(
     352        4424 :         it, end, grammar::tuple_rule(
     353             :             field_name_rule,
     354        4424 :             grammar::delim_rule(':'),
     355             :             field_value_rule,
     356        4424 :             crlf_rule));
     357             : 
     358        4424 :     if( rv.has_error() )
     359        1739 :         return rv.error();
     360             : 
     361        2685 :     auto val = rv.value();
     362        2685 :     v.name = std::get<0>(val);
     363        2685 :     v.value = std::get<2>(val).value;
     364        2685 :     v.has_obs_fold = std::get<2>(val).has_obs_fold;
     365             : 
     366        2685 :     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