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