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