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 : #ifndef BOOST_HTTP_PROTO_RFC_DETAIL_IMPL_RULES_IPP 11 : #define BOOST_HTTP_PROTO_RFC_DETAIL_IMPL_RULES_IPP 12 : 13 : #include <boost/http_proto/rfc/detail/rules.hpp> 14 : #include <boost/url/grammar/digit_chars.hpp> 15 : 16 : namespace boost { 17 : namespace http_proto { 18 : namespace detail { 19 : 20 : auto 21 43158 : crlf_rule_t:: 22 : parse( 23 : char const*& it, 24 : char const* end) const noexcept -> 25 : system::result<value_type> 26 : { 27 43158 : if(it == end) 28 3861 : return grammar::error::need_more; 29 39297 : if(*it != '\r') 30 0 : return grammar::error::mismatch; 31 39297 : ++it; 32 39297 : if(it == end) 33 1553 : return grammar::error::need_more; 34 37744 : if(*it != '\n') 35 0 : return grammar::error::mismatch; 36 37744 : ++it; 37 37744 : return {}; 38 : } 39 : 40 : //------------------------------------------------ 41 : 42 : auto 43 23617 : version_rule_t:: 44 : parse( 45 : char const*& it, 46 : char const* end) const noexcept -> 47 : system::result<value_type> 48 : { 49 23617 : value_type v = 0; 50 23617 : if(it == end) 51 : { 52 : // expected "HTTP/" 53 671 : BOOST_HTTP_PROTO_RETURN_EC( 54 : grammar::error::need_more); 55 : } 56 22946 : if(end - it >= 5) 57 : { 58 20343 : if(std::memcmp( 59 : it, "HTTP/", 5) != 0) 60 : { 61 0 : BOOST_HTTP_PROTO_RETURN_EC( 62 : grammar::error::mismatch); 63 : } 64 20343 : it += 5; 65 : } 66 22946 : if(it == end) 67 : { 68 : // expected DIGIT 69 617 : BOOST_HTTP_PROTO_RETURN_EC( 70 : grammar::error::need_more); 71 : } 72 22329 : if(! grammar::digit_chars(*it)) 73 : { 74 : // expected DIGIT 75 2603 : BOOST_HTTP_PROTO_RETURN_EC( 76 : grammar::error::need_more); 77 : } 78 19726 : v = 10 * (*it++ - '0'); 79 19726 : if(it == end) 80 : { 81 : // expected "." 82 725 : BOOST_HTTP_PROTO_RETURN_EC( 83 : grammar::error::need_more); 84 : } 85 19001 : if(*it != '.') 86 : { 87 : // expected "." 88 0 : BOOST_HTTP_PROTO_RETURN_EC( 89 : grammar::error::need_more); 90 : } 91 19001 : ++it; 92 19001 : if(it == end) 93 : { 94 : // expected DIGIT 95 617 : BOOST_HTTP_PROTO_RETURN_EC( 96 : grammar::error::need_more); 97 : } 98 18384 : if(! grammar::digit_chars(*it)) 99 : { 100 : // expected DIGIT 101 0 : BOOST_HTTP_PROTO_RETURN_EC( 102 : grammar::error::need_more); 103 : } 104 18384 : v += *it++ - '0'; 105 18384 : return v; 106 : } 107 : 108 : //------------------------------------------------ 109 : 110 : auto 111 11100 : status_code_rule_t:: 112 : parse( 113 : char const*& it, 114 : char const* end) const noexcept -> 115 : system::result<value_type> 116 : { 117 : auto const dig = 118 31152 : [](char c) -> int 119 : { 120 31152 : unsigned char uc(c - '0'); 121 31152 : if(uc > 9) 122 0 : return -1; 123 31152 : return uc; 124 : }; 125 : 126 11100 : if(it == end) 127 : { 128 : // end 129 358 : BOOST_HTTP_PROTO_RETURN_EC( 130 : grammar::error::need_more); 131 : } 132 10742 : auto it0 = it; 133 10742 : int v = dig(*it); 134 10742 : if(v == -1) 135 : { 136 : // expected DIGIT 137 0 : BOOST_HTTP_PROTO_RETURN_EC( 138 : grammar::error::mismatch); 139 : } 140 10742 : value_type t; 141 10742 : t.v = 100 * v; 142 10742 : ++it; 143 10742 : if(it == end) 144 : { 145 : // end 146 358 : BOOST_HTTP_PROTO_RETURN_EC( 147 : grammar::error::need_more); 148 : } 149 10384 : v = dig(*it); 150 10384 : if(v == -1) 151 : { 152 : // expected DIGIT 153 0 : BOOST_HTTP_PROTO_RETURN_EC( 154 : grammar::error::mismatch); 155 : } 156 10384 : t.v = t.v + (10 * v); 157 10384 : ++it; 158 10384 : if(it == end) 159 : { 160 : // end 161 358 : BOOST_HTTP_PROTO_RETURN_EC( 162 : grammar::error::need_more); 163 : } 164 10026 : v = dig(*it); 165 10026 : if(v == -1) 166 : { 167 : // expected DIGIT 168 0 : BOOST_HTTP_PROTO_RETURN_EC( 169 : grammar::error::need_more); 170 : } 171 10026 : t.v = t.v + v; 172 10026 : ++it; 173 : 174 10026 : t.s = core::string_view(it0, it - it0); 175 10026 : t.st = int_to_status(t.v); 176 10026 : return t; 177 : } 178 : 179 : //------------------------------------------------ 180 : 181 : auto 182 52722 : field_rule_t:: 183 : parse( 184 : char const*& it, 185 : char const* end) const noexcept -> 186 : system::result<value_type> 187 : { 188 52722 : if(it == end) 189 : { 190 698 : BOOST_HTTP_PROTO_RETURN_EC( 191 : grammar::error::need_more); 192 : } 193 : // check for leading CRLF 194 52024 : if(it[0] == '\r') 195 : { 196 15262 : ++it; 197 15262 : if(it == end) 198 : { 199 657 : BOOST_HTTP_PROTO_RETURN_EC( 200 : grammar::error::need_more); 201 : } 202 14605 : if(*it != '\n') 203 : { 204 0 : BOOST_HTTP_PROTO_RETURN_EC( 205 : grammar::error::mismatch); 206 : } 207 : // end of fields 208 14605 : ++it; 209 14605 : BOOST_HTTP_PROTO_RETURN_EC( 210 : grammar::error::end_of_range); 211 : } 212 : 213 36762 : value_type v; 214 : 215 : // field name 216 : { 217 : auto rv = grammar::parse( 218 36762 : it, end, grammar::tuple_rule( 219 : token_rule, 220 36762 : grammar::squelch( 221 36762 : grammar::delim_rule(':')))); 222 36762 : if(! rv) 223 7820 : return rv.error(); 224 28942 : v.name = rv.value(); 225 : } 226 : 227 : // consume all obs-fold until 228 : // field char or end of field 229 : for(;;) 230 : { 231 29236 : skip_ows(it, end); 232 29236 : if(it == end) 233 : { 234 1802 : BOOST_HTTP_PROTO_RETURN_EC( 235 : grammar::error::need_more); 236 : } 237 27434 : if(*it != '\r') 238 : { 239 : // start of value 240 26880 : break; 241 : } 242 554 : ++it; 243 554 : if(it == end) 244 : { 245 60 : BOOST_HTTP_PROTO_RETURN_EC( 246 : grammar::error::need_more); 247 : } 248 494 : if(*it != '\n') 249 : { 250 0 : BOOST_HTTP_PROTO_RETURN_EC( 251 : grammar::error::mismatch); 252 : } 253 494 : ++it; 254 494 : if(it == end) 255 : { 256 56 : BOOST_HTTP_PROTO_RETURN_EC( 257 : grammar::error::need_more); 258 : } 259 438 : if(*it == '\r') 260 : { 261 : // empty value 262 144 : return v; 263 : } 264 294 : if( *it != ' ' && 265 0 : *it != '\t') 266 : { 267 : // start of value 268 0 : break; 269 : } 270 : // eat obs-fold 271 294 : ++it; 272 294 : v.has_obs_fold = true; 273 294 : } 274 : 275 26880 : char const* s0 = it; // start of value 276 : for(;;) 277 : { 278 : auto rv = grammar::parse( 279 26922 : it, end, grammar::tuple_rule( 280 26922 : grammar::token_rule( 281 26922 : ws_vchars), 282 26922 : crlf_rule)); 283 26922 : if(! rv) 284 3714 : return rv.error(); 285 23208 : if(it == end) 286 : { 287 858 : BOOST_HTTP_PROTO_RETURN_EC( 288 : grammar::error::need_more); 289 : } 290 22350 : if( *it != ' ' && 291 22308 : *it != '\t') 292 : { 293 : // end of field 294 22308 : break; 295 : } 296 : // *it will match field_value_rule 297 42 : v.has_obs_fold = true; 298 42 : } 299 : 300 22308 : v.value = core::string_view(s0, (it - s0) - 2); 301 22308 : BOOST_ASSERT(! v.value.empty()); 302 : //BOOST_ASSERT(! ws(t.v.value.front())); 303 : 304 : // remove trailing SP,HTAB,CR,LF 305 22308 : auto p = &v.value.back(); 306 : for(;;) 307 : { 308 22513 : switch(*p) 309 : { 310 205 : case ' ': case '\t': 311 : case '\r': case '\n': 312 205 : --p; 313 205 : continue; 314 22308 : default: 315 22308 : ++p; 316 22308 : goto done; 317 : } 318 : } 319 22308 : done: 320 22308 : v.value = core::string_view( 321 : v.value.data(), 322 22308 : p - v.value.data()); 323 22308 : return v; 324 : } 325 : 326 : //------------------------------------------------ 327 : 328 : void 329 946 : remove_obs_fold( 330 : char* it, 331 : char const* const end) noexcept 332 : { 333 946 : while(it != end) 334 : { 335 941 : if(*it != '\r') 336 : { 337 593 : ++it; 338 593 : continue; 339 : } 340 348 : if(end - it < 3) 341 145 : break; 342 203 : BOOST_ASSERT(it[1] == '\n'); 343 406 : if( it[1] == '\n' && 344 203 : ws(it[2])) 345 : { 346 200 : it[0] = ' '; 347 200 : it[1] = ' '; 348 200 : it += 3; 349 : } 350 : else 351 : { 352 3 : ++it; 353 : } 354 : } 355 150 : } 356 : 357 : } // detail 358 : } // http_proto 359 : } // boost 360 : 361 : #endif