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