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 4910 : crlf_rule_t:: 22 : parse( 23 : char const*& it, 24 : char const* end) const noexcept -> 25 : system::result<value_type> 26 : { 27 4910 : if(it == end) 28 529 : return grammar::error::need_more; 29 4381 : if(*it != '\r') 30 0 : return grammar::error::mismatch; 31 4381 : ++it; 32 4381 : if(it == end) 33 219 : return grammar::error::need_more; 34 4162 : if(*it != '\n') 35 0 : return grammar::error::mismatch; 36 4162 : ++it; 37 4162 : return {}; 38 : } 39 : 40 : //------------------------------------------------ 41 : 42 : auto 43 2902 : version_rule_t:: 44 : parse( 45 : char const*& it, 46 : char const* end) const noexcept -> 47 : system::result<value_type> 48 : { 49 2902 : value_type v = 0; 50 2902 : if(it == end) 51 : { 52 : // expected "HTTP/" 53 135 : BOOST_HTTP_PROTO_RETURN_EC( 54 : grammar::error::need_more); 55 : } 56 2767 : if(end - it >= 5) 57 : { 58 2344 : if(std::memcmp( 59 : it, "HTTP/", 5) != 0) 60 : { 61 0 : BOOST_HTTP_PROTO_RETURN_EC( 62 : grammar::error::mismatch); 63 : } 64 2344 : it += 5; 65 : } 66 2767 : if(it == end) 67 : { 68 : // expected DIGIT 69 72 : BOOST_HTTP_PROTO_RETURN_EC( 70 : grammar::error::need_more); 71 : } 72 2695 : if(! grammar::digit_chars(*it)) 73 : { 74 : // expected DIGIT 75 423 : BOOST_HTTP_PROTO_RETURN_EC( 76 : grammar::error::need_more); 77 : } 78 2272 : v = 10 * (*it++ - '0'); 79 2272 : if(it == end) 80 : { 81 : // expected "." 82 180 : BOOST_HTTP_PROTO_RETURN_EC( 83 : grammar::error::need_more); 84 : } 85 2092 : if(*it != '.') 86 : { 87 : // expected "." 88 0 : BOOST_HTTP_PROTO_RETURN_EC( 89 : grammar::error::need_more); 90 : } 91 2092 : ++it; 92 2092 : if(it == end) 93 : { 94 : // expected DIGIT 95 71 : BOOST_HTTP_PROTO_RETURN_EC( 96 : grammar::error::need_more); 97 : } 98 2021 : if(! grammar::digit_chars(*it)) 99 : { 100 : // expected DIGIT 101 0 : BOOST_HTTP_PROTO_RETURN_EC( 102 : grammar::error::need_more); 103 : } 104 2021 : v += *it++ - '0'; 105 2021 : return v; 106 : } 107 : 108 : //------------------------------------------------ 109 : 110 : auto 111 499 : 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 1446 : [](char c) -> int 119 : { 120 1446 : unsigned char uc(c - '0'); 121 1446 : if(uc > 9) 122 0 : return -1; 123 1446 : return uc; 124 : }; 125 : 126 499 : if(it == end) 127 : { 128 : // end 129 9 : BOOST_HTTP_PROTO_RETURN_EC( 130 : grammar::error::need_more); 131 : } 132 490 : auto it0 = it; 133 490 : int v = dig(*it); 134 490 : if(v == -1) 135 : { 136 : // expected DIGIT 137 0 : BOOST_HTTP_PROTO_RETURN_EC( 138 : grammar::error::mismatch); 139 : } 140 490 : value_type t; 141 490 : t.v = 100 * v; 142 490 : ++it; 143 490 : if(it == end) 144 : { 145 : // end 146 8 : BOOST_HTTP_PROTO_RETURN_EC( 147 : grammar::error::need_more); 148 : } 149 482 : v = dig(*it); 150 482 : if(v == -1) 151 : { 152 : // expected DIGIT 153 0 : BOOST_HTTP_PROTO_RETURN_EC( 154 : grammar::error::mismatch); 155 : } 156 482 : t.v = t.v + (10 * v); 157 482 : ++it; 158 482 : if(it == end) 159 : { 160 : // end 161 8 : BOOST_HTTP_PROTO_RETURN_EC( 162 : grammar::error::need_more); 163 : } 164 474 : v = dig(*it); 165 474 : if(v == -1) 166 : { 167 : // expected DIGIT 168 0 : BOOST_HTTP_PROTO_RETURN_EC( 169 : grammar::error::need_more); 170 : } 171 474 : t.v = t.v + v; 172 474 : ++it; 173 : 174 474 : t.s = core::string_view(it0, it - it0); 175 474 : t.st = int_to_status(t.v); 176 474 : return t; 177 : } 178 : 179 : //------------------------------------------------ 180 : 181 : auto 182 5825 : field_rule_t:: 183 : parse( 184 : char const*& it, 185 : char const* end) const noexcept -> 186 : system::result<value_type> 187 : { 188 5825 : if(it == end) 189 : { 190 152 : BOOST_HTTP_PROTO_RETURN_EC( 191 : grammar::error::need_more); 192 : } 193 : // check for leading CRLF 194 5673 : if(it[0] == '\r') 195 : { 196 1892 : ++it; 197 1892 : if(it == end) 198 : { 199 112 : BOOST_HTTP_PROTO_RETURN_EC( 200 : grammar::error::need_more); 201 : } 202 1780 : if(*it != '\n') 203 : { 204 0 : BOOST_HTTP_PROTO_RETURN_EC( 205 : grammar::error::mismatch); 206 : } 207 : // end of fields 208 1780 : ++it; 209 1780 : BOOST_HTTP_PROTO_RETURN_EC( 210 : grammar::error::end_of_range); 211 : } 212 : 213 3781 : value_type v; 214 : 215 : // field name 216 : { 217 : auto rv = grammar::parse( 218 3781 : it, end, grammar::tuple_rule( 219 : token_rule, 220 3781 : grammar::squelch( 221 3781 : grammar::delim_rule(':')))); 222 3781 : if(! rv) 223 397 : return rv.error(); 224 3384 : v.name = rv.value(); 225 : } 226 : 227 : // consume all obs-fold until 228 : // field char or end of field 229 : for(;;) 230 : { 231 3678 : skip_ows(it, end); 232 3678 : if(it == end) 233 : { 234 227 : BOOST_HTTP_PROTO_RETURN_EC( 235 : grammar::error::need_more); 236 : } 237 3451 : if(*it != '\r') 238 : { 239 : // start of value 240 2897 : 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 2897 : char const* s0 = it; // start of value 276 : for(;;) 277 : { 278 : auto rv = grammar::parse( 279 2939 : it, end, grammar::tuple_rule( 280 2939 : grammar::token_rule( 281 2939 : ws_vchars), 282 2939 : crlf_rule)); 283 2939 : if(! rv) 284 488 : return rv.error(); 285 2451 : if(it == end) 286 : { 287 71 : BOOST_HTTP_PROTO_RETURN_EC( 288 : grammar::error::need_more); 289 : } 290 2380 : if( *it != ' ' && 291 2338 : *it != '\t') 292 : { 293 : // end of field 294 2338 : break; 295 : } 296 : // *it will match field_value_rule 297 42 : v.has_obs_fold = true; 298 42 : } 299 : 300 2338 : v.value = core::string_view(s0, (it - s0) - 2); 301 2338 : BOOST_ASSERT(! v.value.empty()); 302 : //BOOST_ASSERT(! ws(t.v.value.front())); 303 : 304 : // remove trailing SP,HTAB,CR,LF 305 2338 : auto p = &v.value.back(); 306 : for(;;) 307 : { 308 2543 : switch(*p) 309 : { 310 205 : case ' ': case '\t': 311 : case '\r': case '\n': 312 205 : --p; 313 205 : continue; 314 2338 : default: 315 2338 : ++p; 316 2338 : goto done; 317 : } 318 : } 319 2338 : done: 320 2338 : v.value = core::string_view( 321 : v.value.data(), 322 2338 : p - v.value.data()); 323 2338 : 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