Line data Source code
1 : // 2 : // Copyright (c) 2021 Vinnie Falco (vinnie dot falco at gmail dot 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 2122 : crlf_rule_t:: 22 : parse( 23 : char const*& it, 24 : char const* end) const noexcept -> 25 : result<value_type> 26 : { 27 2122 : if(it == end) 28 439 : return grammar::error::need_more; 29 1683 : if(*it != '\r') 30 0 : return grammar::error::mismatch; 31 1683 : ++it; 32 1683 : if(it == end) 33 182 : return grammar::error::need_more; 34 1501 : if(*it != '\n') 35 0 : return grammar::error::mismatch; 36 1501 : ++it; 37 1501 : return {}; 38 : } 39 : 40 : //------------------------------------------------ 41 : 42 : auto 43 1898 : version_rule_t:: 44 : parse( 45 : char const*& it, 46 : char const* end) const noexcept -> 47 : result<value_type> 48 : { 49 1898 : value_type v = 0; 50 1898 : if(it == end) 51 : { 52 : // expected "HTTP/" 53 108 : BOOST_HTTP_PROTO_RETURN_EC( 54 : grammar::error::need_more); 55 : } 56 1790 : if(end - it >= 5) 57 : { 58 1439 : if(std::memcmp( 59 : it, "HTTP/", 5) != 0) 60 : { 61 0 : BOOST_HTTP_PROTO_RETURN_EC( 62 : grammar::error::mismatch); 63 : } 64 1439 : it += 5; 65 : } 66 1790 : if(it == end) 67 : { 68 : // expected DIGIT 69 54 : BOOST_HTTP_PROTO_RETURN_EC( 70 : grammar::error::need_more); 71 : } 72 1736 : if(! grammar::digit_chars(*it)) 73 : { 74 : // expected DIGIT 75 351 : BOOST_HTTP_PROTO_RETURN_EC( 76 : grammar::error::need_more); 77 : } 78 1385 : v = 10 * (*it++ - '0'); 79 1385 : if(it == end) 80 : { 81 : // expected "." 82 162 : BOOST_HTTP_PROTO_RETURN_EC( 83 : grammar::error::need_more); 84 : } 85 1223 : if(*it != '.') 86 : { 87 : // expected "." 88 0 : BOOST_HTTP_PROTO_RETURN_EC( 89 : grammar::error::need_more); 90 : } 91 1223 : ++it; 92 1223 : if(it == end) 93 : { 94 : // expected DIGIT 95 54 : BOOST_HTTP_PROTO_RETURN_EC( 96 : grammar::error::need_more); 97 : } 98 1169 : if(! grammar::digit_chars(*it)) 99 : { 100 : // expected DIGIT 101 0 : BOOST_HTTP_PROTO_RETURN_EC( 102 : grammar::error::need_more); 103 : } 104 1169 : v += *it++ - '0'; 105 1169 : return v; 106 : } 107 : 108 : //------------------------------------------------ 109 : 110 : auto 111 66 : status_code_rule_t:: 112 : parse( 113 : char const*& it, 114 : char const* end) const noexcept -> 115 : result<value_type> 116 : { 117 : auto const dig = 118 198 : [](char c) -> int 119 : { 120 198 : unsigned char uc(c - '0'); 121 198 : if(uc > 9) 122 0 : return -1; 123 198 : return uc; 124 : }; 125 : 126 66 : if(it == end) 127 : { 128 : // end 129 0 : BOOST_HTTP_PROTO_RETURN_EC( 130 : grammar::error::need_more); 131 : } 132 66 : auto it0 = it; 133 66 : int v = dig(*it); 134 66 : if(v == -1) 135 : { 136 : // expected DIGIT 137 0 : BOOST_HTTP_PROTO_RETURN_EC( 138 : grammar::error::mismatch); 139 : } 140 66 : value_type t; 141 66 : t.v = 100 * v; 142 66 : ++it; 143 66 : if(it == end) 144 : { 145 : // end 146 0 : BOOST_HTTP_PROTO_RETURN_EC( 147 : grammar::error::need_more); 148 : } 149 66 : v = dig(*it); 150 66 : if(v == -1) 151 : { 152 : // expected DIGIT 153 0 : BOOST_HTTP_PROTO_RETURN_EC( 154 : grammar::error::mismatch); 155 : } 156 66 : t.v = t.v + (10 * v); 157 66 : ++it; 158 66 : if(it == end) 159 : { 160 : // end 161 0 : BOOST_HTTP_PROTO_RETURN_EC( 162 : grammar::error::need_more); 163 : } 164 66 : v = dig(*it); 165 66 : if(v == -1) 166 : { 167 : // expected DIGIT 168 0 : BOOST_HTTP_PROTO_RETURN_EC( 169 : grammar::error::need_more); 170 : } 171 66 : t.v = t.v + v; 172 66 : ++it; 173 : 174 66 : t.s = string_view(it0, it - it0); 175 66 : t.st = int_to_status(t.v); 176 66 : return t; 177 : } 178 : 179 : //------------------------------------------------ 180 : 181 : auto 182 2351 : field_rule_t:: 183 : parse( 184 : char const*& it, 185 : char const* end) const noexcept -> 186 : result<value_type> 187 : { 188 2351 : if(it == end) 189 : { 190 135 : BOOST_HTTP_PROTO_RETURN_EC( 191 : grammar::error::need_more); 192 : } 193 : // check for leading CRLF 194 2216 : if(it[0] == '\r') 195 : { 196 674 : ++it; 197 674 : if(it == end) 198 : { 199 95 : BOOST_HTTP_PROTO_RETURN_EC( 200 : grammar::error::need_more); 201 : } 202 579 : if(*it != '\n') 203 : { 204 0 : BOOST_HTTP_PROTO_RETURN_EC( 205 : grammar::error::mismatch); 206 : } 207 : // end of fields 208 579 : ++it; 209 579 : BOOST_HTTP_PROTO_RETURN_EC( 210 : grammar::error::end_of_range); 211 : } 212 : 213 1542 : value_type v; 214 : 215 : // field name 216 : { 217 : auto rv = grammar::parse( 218 1542 : it, end, grammar::tuple_rule( 219 : token_rule, 220 1542 : grammar::squelch( 221 1542 : grammar::delim_rule(':')))); 222 1542 : if(! rv) 223 188 : return rv.error(); 224 1354 : v.name = rv.value(); 225 : } 226 : 227 : // consume all obs-fold until 228 : // field char or end of field 229 : for(;;) 230 : { 231 1648 : skip_ows(it, end); 232 1648 : if(it == end) 233 : { 234 186 : BOOST_HTTP_PROTO_RETURN_EC( 235 : grammar::error::need_more); 236 : } 237 1462 : if(*it != '\r') 238 : { 239 : // start of value 240 911 : break; 241 : } 242 551 : ++it; 243 551 : if(it == end) 244 : { 245 60 : BOOST_HTTP_PROTO_RETURN_EC( 246 : grammar::error::need_more); 247 : } 248 491 : if(*it != '\n') 249 : { 250 0 : BOOST_HTTP_PROTO_RETURN_EC( 251 : grammar::error::mismatch); 252 : } 253 491 : ++it; 254 491 : if(it == end) 255 : { 256 56 : BOOST_HTTP_PROTO_RETURN_EC( 257 : grammar::error::need_more); 258 : } 259 435 : if(*it == '\r') 260 : { 261 : // empty value 262 141 : 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 911 : char const* s0 = it; // start of value 276 : for(;;) 277 : { 278 : auto rv = grammar::parse( 279 953 : it, end, grammar::tuple_rule( 280 953 : grammar::token_rule( 281 953 : ws_vchars), 282 953 : crlf_rule)); 283 953 : if(! rv) 284 405 : return rv.error(); 285 548 : if(it == end) 286 : { 287 50 : BOOST_HTTP_PROTO_RETURN_EC( 288 : grammar::error::need_more); 289 : } 290 498 : if( *it != ' ' && 291 456 : *it != '\t') 292 : { 293 : // end of field 294 456 : break; 295 : } 296 : // *it will match field_value_rule 297 42 : v.has_obs_fold = true; 298 42 : } 299 : 300 456 : v.value = string_view(s0, (it - s0) - 2); 301 456 : BOOST_ASSERT(! v.value.empty()); 302 : //BOOST_ASSERT(! ws(t.v.value.front())); 303 : 304 : // remove trailing SP,HTAB,CR,LF 305 456 : auto p = &v.value.back(); 306 : for(;;) 307 : { 308 661 : switch(*p) 309 : { 310 205 : case ' ': case '\t': 311 : case '\r': case '\n': 312 205 : --p; 313 205 : continue; 314 456 : default: 315 456 : ++p; 316 456 : goto done; 317 : } 318 : } 319 456 : done: 320 456 : v.value = string_view( 321 : v.value.data(), 322 456 : p - v.value.data()); 323 456 : 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