src/head_parser.cpp
99.6% Lines (235/236)
100.0% List of functions (17/17)
94.6% Branches (106/112)
Functions (17)
Function
Calls
Lines
Branches
Blocks
boost::burl::(anonymous namespace)::parse_method(char const*&, char const*, std::basic_string_view<char, std::char_traits<char> >&, boost::system::error_code&)
:58
79024x
100.0%
100.0%
100.0%
boost::burl::(anonymous namespace)::parse_target(char const*&, char const*, std::basic_string_view<char, std::char_traits<char> >&, boost::system::error_code&)
:91
36776x
100.0%
100.0%
100.0%
boost::burl::(anonymous namespace)::parse_version(char const*&, char const*, boost::http::version&, boost::system::error_code&)
:124
36023x
100.0%
100.0%
100.0%
boost::burl::(anonymous namespace)::parse_status(char const*&, char const*, unsigned short&, boost::system::error_code&)
:151
837x
100.0%
100.0%
100.0%
boost::burl::(anonymous namespace)::parse_reason(char const*&, char const*, std::basic_string_view<char, std::char_traits<char> >&, boost::system::error_code&)
:192
579x
100.0%
100.0%
100.0%
boost::burl::head_parser::head_parser(bool, char*, unsigned long, boost::burl::header_limits const&)
:215
40840x
93.8%
83.3%
93.0%
boost::burl::head_parser::head_parser(boost::burl::head_parser&&)
:240
336x
100.0%
100.0%
100.0%
boost::burl::head_parser::operator=(boost::burl::head_parser&&)
:255
302x
100.0%
100.0%
100.0%
boost::burl::head_parser::ceiling() const
:273
195851x
100.0%
100.0%
100.0%
boost::burl::head_parser::reset(char*)
:284
377x
100.0%
75.0%
92.0%
boost::burl::head_parser::rebase(char*)
:300
207x
100.0%
50.0%
80.0%
boost::burl::head_parser::parse(unsigned long, boost::system::error_code&)
:309
92291x
100.0%
62.5%
94.0%
auto boost::burl::head_parser::parse(unsigned long, boost::system::error_code&)::{lambda(auto:1&, auto:2, auto:3&)#1}::operator()<char const*, char const*, boost::system::error_code>(char const*&, char const*, boost::system::error_code&) const
:326
80679x
100.0%
100.0%
100.0%
auto boost::burl::head_parser::parse(unsigned long, boost::system::error_code&)::{lambda(auto:1&, auto:2, auto:3&)#2}::operator()<char const*, char const*, boost::system::error_code>(char const*&, char const*, boost::system::error_code&) const
:343
38353x
100.0%
100.0%
100.0%
boost::burl::head_parser::parse_start_line_(char const*&, char const*, boost::system::error_code&)
:368
80679x
100.0%
100.0%
100.0%
boost::burl::head_parser::parse_fields_(char const*&, char const*, boost::system::error_code&)
:453
38353x
100.0%
100.0%
100.0%
auto boost::burl::head_parser::parse_fields_(char const*&, char const*, boost::system::error_code&)::{lambda(auto:1&, auto:2, auto:3&)#1}::operator()<char const*, char const*, boost::system::error_code>(char const*&, char const*, boost::system::error_code&) const
:490
36370x
100.0%
100.0%
100.0%
| Line | Branch | TLA | Hits | Source Code |
|---|---|---|---|---|
| 1 | // | |||
| 2 | // Copyright (c) 2021 Vinnie Falco ([email protected]) | |||
| 3 | // Copyright (c) 2026 Mohammad Nejati | |||
| 4 | // | |||
| 5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |||
| 6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |||
| 7 | // | |||
| 8 | // Official repository: https://github.com/cppalliance/burl | |||
| 9 | // | |||
| 10 | ||||
| 11 | #include <boost/burl/head_parser.hpp> | |||
| 12 | ||||
| 13 | #include "detail/grammar.hpp" | |||
| 14 | #include "detail/util.hpp" | |||
| 15 | ||||
| 16 | #include <boost/assert.hpp> | |||
| 17 | ||||
| 18 | #include <cstring> | |||
| 19 | #include <new> | |||
| 20 | ||||
| 21 | namespace boost | |||
| 22 | { | |||
| 23 | namespace burl | |||
| 24 | { | |||
| 25 | ||||
| 26 | // assert relying facts | |||
| 27 | static_assert( | |||
| 28 | std::is_same_v< | |||
| 29 | decltype(header_limits::max_size), std::uint32_t>); | |||
| 30 | ||||
| 31 | static_assert( | |||
| 32 | std::is_same_v< | |||
| 33 | decltype(header_limits::max_fields), std::uint16_t>); | |||
| 34 | ||||
| 35 | static_assert( | |||
| 36 | std::is_same_v< | |||
| 37 | decltype(header_limits::max_field), std::uint16_t>); | |||
| 38 | ||||
| 39 | static_assert( | |||
| 40 | std::is_same_v< | |||
| 41 | decltype(header_limits::max_start_line), std::uint16_t>); | |||
| 42 | ||||
| 43 | using error = http::error; | |||
| 44 | using version = http::version; | |||
| 45 | ||||
| 46 | using detail::distance; | |||
| 47 | using detail::is_digit; | |||
| 48 | using detail::is_target_char; | |||
| 49 | using detail::is_token_char; | |||
| 50 | using detail::parse_field; | |||
| 51 | using detail::parse_limited; | |||
| 52 | using detail::parse_token_to_eol; | |||
| 53 | ||||
| 54 | namespace | |||
| 55 | { | |||
| 56 | ||||
| 57 | void | |||
| 58 | 79024x | parse_method( | ||
| 59 | char const*& it, | |||
| 60 | char const* end, | |||
| 61 | std::string_view& result, | |||
| 62 | system::error_code& ec) | |||
| 63 | { | |||
| 64 | // parse token SP | |||
| 65 | 79024x | auto const first = it; | ||
| 66 | 114584x | for(;; ++it) | ||
| 67 | { | |||
| 68 |
2/2✓ Branch 1 taken 42244 times.
✓ Branch 2 taken 151364 times.
|
193608x | if(distance(it, end) < 1) | |
| 69 | { | |||
| 70 | 42244x | ec = error::need_data; | ||
| 71 | 42244x | return; | ||
| 72 | } | |||
| 73 |
2/2✓ Branch 1 taken 36780 times.
✓ Branch 2 taken 114584 times.
|
151364x | if(! is_token_char(*it)) | |
| 74 | 36780x | break; | ||
| 75 | } | |||
| 76 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 36778 times.
|
36780x | if(*it != ' ') | |
| 77 | { | |||
| 78 | 2x | ec = error::bad_method; | ||
| 79 | 2x | return; | ||
| 80 | } | |||
| 81 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 36776 times.
|
36778x | if(it == first) | |
| 82 | { | |||
| 83 | // cannot be empty | |||
| 84 | 2x | ec = error::bad_method; | ||
| 85 | 2x | return; | ||
| 86 | } | |||
| 87 | 36776x | result = { first, it++ }; | ||
| 88 | } | |||
| 89 | ||||
| 90 | void | |||
| 91 | 36776x | parse_target( | ||
| 92 | char const*& it, | |||
| 93 | char const* end, | |||
| 94 | std::string_view& result, | |||
| 95 | system::error_code& ec) | |||
| 96 | { | |||
| 97 | // parse target SP | |||
| 98 | 36776x | auto const first = it; | ||
| 99 | 83506x | for(;; ++it) | ||
| 100 | { | |||
| 101 |
2/2✓ Branch 1 taken 2402 times.
✓ Branch 2 taken 117880 times.
|
120282x | if(distance(it, end) < 1) | |
| 102 | { | |||
| 103 | 2402x | ec = error::need_data; | ||
| 104 | 2402x | return; | ||
| 105 | } | |||
| 106 |
2/2✓ Branch 1 taken 34374 times.
✓ Branch 2 taken 83506 times.
|
117880x | if(! is_target_char(*it)) | |
| 107 | 34374x | break; | ||
| 108 | } | |||
| 109 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 34370 times.
|
34374x | if(*it != ' ') | |
| 110 | { | |||
| 111 | 4x | ec = error::bad_request_target; | ||
| 112 | 4x | return; | ||
| 113 | } | |||
| 114 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 34368 times.
|
34370x | if(it == first) | |
| 115 | { | |||
| 116 | // cannot be empty | |||
| 117 | 2x | ec = error::bad_request_target; | ||
| 118 | 2x | return; | ||
| 119 | } | |||
| 120 | 34368x | result = { first, it++ }; | ||
| 121 | } | |||
| 122 | ||||
| 123 | void | |||
| 124 | 36023x | parse_version( | ||
| 125 | char const*& it, | |||
| 126 | char const* end, | |||
| 127 | version& result, | |||
| 128 | system::error_code& ec) | |||
| 129 | { | |||
| 130 |
2/2✓ Branch 1 taken 7267 times.
✓ Branch 2 taken 28756 times.
|
36023x | if(distance(it, end) < 8) | |
| 131 | { | |||
| 132 | 7267x | ec = error::need_data; | ||
| 133 | 7267x | return; | ||
| 134 | } | |||
| 135 |
2/2✓ Branch 0 taken 28739 times.
✓ Branch 1 taken 17 times.
|
28756x | if(std::memcmp(it, "HTTP/1.1", 8) == 0) | |
| 136 | { | |||
| 137 | 28739x | it += 8; | ||
| 138 | 28739x | result = version::http_1_1; | ||
| 139 | 28739x | return; | ||
| 140 | } | |||
| 141 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 9 times.
|
17x | if(std::memcmp(it, "HTTP/1.0", 8) == 0) | |
| 142 | { | |||
| 143 | 8x | it += 8; | ||
| 144 | 8x | result = version::http_1_0; | ||
| 145 | 8x | return; | ||
| 146 | } | |||
| 147 | 9x | ec = error::bad_version; | ||
| 148 | } | |||
| 149 | ||||
| 150 | void | |||
| 151 | 837x | parse_status( | ||
| 152 | char const*& it, | |||
| 153 | char const* end, | |||
| 154 | std::uint16_t& result, | |||
| 155 | system::error_code& ec) | |||
| 156 | { | |||
| 157 | // parse 3(digit) SP | |||
| 158 |
2/2✓ Branch 1 taken 250 times.
✓ Branch 2 taken 587 times.
|
837x | if(distance(it, end) < 4) | |
| 159 | { | |||
| 160 | 250x | ec = error::need_data; | ||
| 161 | 250x | return; | ||
| 162 | } | |||
| 163 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 585 times.
|
587x | if(! is_digit(*it)) | |
| 164 | { | |||
| 165 | 2x | ec = error::bad_status_code; | ||
| 166 | 2x | return; | ||
| 167 | } | |||
| 168 | 585x | result = 100 * (*it++ - '0'); | ||
| 169 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 583 times.
|
585x | if(! is_digit(*it)) | |
| 170 | { | |||
| 171 | 2x | ec = error::bad_status_code; | ||
| 172 | 2x | return; | ||
| 173 | } | |||
| 174 | 583x | result += 10 * (*it++ - '0'); | ||
| 175 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 581 times.
|
583x | if(! is_digit(*it)) | |
| 176 | { | |||
| 177 | 2x | ec = error::bad_status_code; | ||
| 178 | 2x | return; | ||
| 179 | } | |||
| 180 | 581x | result += *it++ - '0'; | ||
| 181 |
2/2✓ Branch 0 taken 577 times.
✓ Branch 1 taken 4 times.
|
581x | if(*it == ' ') | |
| 182 | { | |||
| 183 | 577x | ++it; | ||
| 184 | } | |||
| 185 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4x | else if(*it != '\r') | |
| 186 | { | |||
| 187 | 2x | ec = error::bad_status_code; | ||
| 188 | } | |||
| 189 | } | |||
| 190 | ||||
| 191 | void | |||
| 192 | 579x | parse_reason( | ||
| 193 | char const*& it, | |||
| 194 | char const* end, | |||
| 195 | std::string_view& result, | |||
| 196 | system::error_code& ec) | |||
| 197 | { | |||
| 198 | 579x | auto const first = it; | ||
| 199 | 579x | char const* token_end = nullptr; | ||
| 200 | 579x | auto p = parse_token_to_eol( | ||
| 201 | it, end, token_end, ec); | |||
| 202 |
2/2✓ Branch 1 taken 252 times.
✓ Branch 2 taken 327 times.
|
579x | if(ec) | |
| 203 | 254x | return; | ||
| 204 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 325 times.
|
327x | if(! p) | |
| 205 | { | |||
| 206 | 2x | ec = error::bad_reason; | ||
| 207 | 2x | return; | ||
| 208 | } | |||
| 209 | 325x | result = { first, token_end }; | ||
| 210 | 325x | it = p; | ||
| 211 | } | |||
| 212 | ||||
| 213 | } // namespace | |||
| 214 | ||||
| 215 | 40840x | head_parser:: | ||
| 216 | head_parser( | |||
| 217 | bool is_request, | |||
| 218 | char* buf, | |||
| 219 | std::size_t n, | |||
| 220 | 40840x | header_limits const& limits) noexcept | ||
| 221 | 40840x | : limits_(limits) | ||
| 222 | 40840x | , is_req_(is_request) | ||
| 223 | { | |||
| 224 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40840 times.
|
40840x | if(limits_.max_size > fields_base::max_buffer_size) | |
| 225 | ✗ | limits_.max_size = fields_base::max_buffer_size; | ||
| 226 | ||||
| 227 | 40840x | auto const a = reinterpret_cast<std::uintptr_t>(buf); | ||
| 228 | 40840x | auto const e = (a + n) - | ||
| 229 | 40840x | (a + n) % alignof(message_head_base::entry); | ||
| 230 |
2/2✓ Branch 0 taken 40535 times.
✓ Branch 1 taken 305 times.
|
40840x | auto const cap = (e > a) ? e - a : 0; | |
| 231 | ||||
| 232 |
2/2✓ Branch 0 taken 40522 times.
✓ Branch 1 taken 318 times.
|
40840x | if(is_req_) | |
| 233 | 40522x | ::new(static_cast<void*>(&s_.req)) | ||
| 234 | 40522x | class request_head_base(buf, cap); | ||
| 235 | else | |||
| 236 | 318x | ::new(static_cast<void*>(&s_.res)) | ||
| 237 | 318x | class response_head_base(buf, cap); | ||
| 238 | 40840x | } | ||
| 239 | ||||
| 240 | 336x | head_parser:: | ||
| 241 | 336x | head_parser(head_parser&& other) noexcept | ||
| 242 | 336x | : limits_(other.limits_) | ||
| 243 | 336x | , is_req_(other.is_req_) | ||
| 244 | 336x | , st_(other.st_) | ||
| 245 | { | |||
| 246 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 325 times.
|
336x | if(is_req_) | |
| 247 | 11x | ::new(static_cast<void*>(&s_.req)) | ||
| 248 | 11x | class request_head_base(other.s_.req); | ||
| 249 | else | |||
| 250 | 325x | ::new(static_cast<void*>(&s_.res)) | ||
| 251 | 325x | class response_head_base(other.s_.res); | ||
| 252 | 336x | } | ||
| 253 | ||||
| 254 | head_parser& | |||
| 255 | 302x | head_parser:: | ||
| 256 | operator=(head_parser&& other) noexcept | |||
| 257 | { | |||
| 258 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 301 times.
|
302x | if(this == &other) | |
| 259 | 1x | return *this; | ||
| 260 | 301x | limits_ = other.limits_; | ||
| 261 | 301x | is_req_ = other.is_req_; | ||
| 262 | 301x | st_ = other.st_; | ||
| 263 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 298 times.
|
301x | if(is_req_) | |
| 264 | 3x | ::new(static_cast<void*>(&s_.req)) | ||
| 265 | 3x | class request_head_base(other.s_.req); | ||
| 266 | else | |||
| 267 | 298x | ::new(static_cast<void*>(&s_.res)) | ||
| 268 | 298x | class response_head_base(other.s_.res); | ||
| 269 | 301x | return *this; | ||
| 270 | } | |||
| 271 | ||||
| 272 | char* | |||
| 273 | 195851x | head_parser:: | ||
| 274 | ceiling() const noexcept | |||
| 275 | { | |||
| 276 | 195851x | auto const& h = h_(); | ||
| 277 | auto const reserve = | |||
| 278 | 195851x | message_head_base::table_space_(limits_.max_fields); | ||
| 279 | 195851x | auto const cap = h.capacity_in_bytes(); | ||
| 280 |
2/2✓ Branch 1 taken 195804 times.
✓ Branch 2 taken 47 times.
|
195851x | return h.base_() + (cap > reserve ? cap - reserve : 0); | |
| 281 | } | |||
| 282 | ||||
| 283 | void | |||
| 284 | 377x | head_parser:: | ||
| 285 | reset(char* base) noexcept | |||
| 286 | { | |||
| 287 | 377x | auto& h = h_(); | ||
| 288 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 377 times.
|
377x | BOOST_ASSERT(base <= ceiling()); | |
| 289 | 377x | auto const cap = static_cast<std::size_t>(h.end_ - base); | ||
| 290 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 366 times.
|
377x | if(is_req_) | |
| 291 | 11x | ::new(static_cast<void*>(&s_.req)) | ||
| 292 | 11x | class request_head_base(base, cap); | ||
| 293 | else | |||
| 294 | 366x | ::new(static_cast<void*>(&s_.res)) | ||
| 295 | 366x | class response_head_base(base, cap); | ||
| 296 | 377x | st_ = state::start_line; | ||
| 297 | 377x | } | ||
| 298 | ||||
| 299 | void | |||
| 300 | 207x | head_parser:: | ||
| 301 | rebase(char* base) noexcept | |||
| 302 | { | |||
| 303 | 207x | auto& h = h_(); | ||
| 304 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 207 times.
|
207x | BOOST_ASSERT(base <= h.base_()); | |
| 305 | 207x | h.buf_ = base + h.prefix_; | ||
| 306 | 207x | } | ||
| 307 | ||||
| 308 | void | |||
| 309 | 92291x | head_parser:: | ||
| 310 | parse( | |||
| 311 | std::size_t n, | |||
| 312 | system::error_code& ec) noexcept | |||
| 313 | { | |||
| 314 | 92291x | ec.clear(); | ||
| 315 | 92291x | auto const& h = h_(); | ||
| 316 | 92291x | char const* it = h.buf_ + h.size_; | ||
| 317 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 92291 times.
|
92291x | BOOST_ASSERT(n >= std::size_t(h.prefix_) + h.size_); | |
| 318 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 92291 times.
|
92291x | BOOST_ASSERT(h.base_() + n <= ceiling()); | |
| 319 | 92291x | auto* const end = h.base_() + n; | ||
| 320 | ||||
| 321 |
3/4✓ Branch 0 taken 80679 times.
✓ Branch 1 taken 11609 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
92291x | switch(st_) | |
| 322 | { | |||
| 323 | 80679x | case state::start_line: | ||
| 324 | { | |||
| 325 | 161358x | parse_limited( | ||
| 326 | 80679x | [this](auto& it, auto end, auto& ec) | ||
| 327 | { | |||
| 328 | 80679x | parse_start_line_(it, end, ec); | ||
| 329 | 80679x | }, | ||
| 330 | it, | |||
| 331 | end, | |||
| 332 | 80679x | detail::clamp(limits_.max_start_line, limits_.max_size), | ||
| 333 | error::start_line_limit, | |||
| 334 | ec); | |||
| 335 |
2/2✓ Branch 1 taken 53935 times.
✓ Branch 2 taken 26744 times.
|
80679x | if(ec) | |
| 336 | 53935x | break; | ||
| 337 | 26744x | st_ = state::fields; | ||
| 338 | BOOST_FALLTHROUGH; | |||
| 339 | } | |||
| 340 | 38353x | case state::fields: | ||
| 341 | { | |||
| 342 | 38353x | parse_limited( | ||
| 343 | 115059x | [this](auto& it, auto end, auto& ec) | ||
| 344 | { | |||
| 345 | 38353x | parse_fields_(it, end, ec); | ||
| 346 | 38353x | }, | ||
| 347 | it, | |||
| 348 | end, | |||
| 349 | 38353x | limits_.max_size - h.prefix_ - h.size_, | ||
| 350 | error::headers_limit, | |||
| 351 | ec); | |||
| 352 |
2/2✓ Branch 1 taken 29277 times.
✓ Branch 2 taken 9076 times.
|
38353x | if(ec) | |
| 353 | 29277x | break; | ||
| 354 | 9076x | st_ = state::done; | ||
| 355 | BOOST_FALLTHROUGH; | |||
| 356 | } | |||
| 357 | 9079x | case state::done: | ||
| 358 | { | |||
| 359 | 9079x | ec = h.validate_framing_(); | ||
| 360 | } | |||
| 361 | } | |||
| 362 | ||||
| 363 |
6/6✓ Branch 1 taken 51891 times.
✓ Branch 2 taken 40400 times.
✓ Branch 4 taken 214 times.
✓ Branch 5 taken 51677 times.
✓ Branch 6 taken 214 times.
✓ Branch 7 taken 92077 times.
|
92291x | if(ec == error::need_data && end >= ceiling()) | |
| 364 | 214x | ec = error::in_place_overflow; | ||
| 365 | 92291x | } | ||
| 366 | ||||
| 367 | void | |||
| 368 | 80679x | head_parser:: | ||
| 369 | parse_start_line_( | |||
| 370 | char const*& it, | |||
| 371 | char const* end, | |||
| 372 | system::error_code& ec) noexcept | |||
| 373 | { | |||
| 374 | 80679x | auto& h = h_(); | ||
| 375 | 80679x | auto const first = it; | ||
| 376 |
2/2✓ Branch 0 taken 79024 times.
✓ Branch 1 taken 1655 times.
|
80679x | if(is_req_) | |
| 377 | { | |||
| 378 | /* | |||
| 379 | request-line = method SP request-target SP HTTP-version CRLF | |||
| 380 | method = token | |||
| 381 | */ | |||
| 382 | ||||
| 383 | 79024x | std::string_view m; | ||
| 384 | 79024x | parse_method(it, end, m, ec); | ||
| 385 |
2/2✓ Branch 1 taken 42248 times.
✓ Branch 2 taken 36776 times.
|
79024x | if(ec) | |
| 386 | 52605x | return; | ||
| 387 | ||||
| 388 | 36776x | std::string_view t; | ||
| 389 | 36776x | parse_target(it, end, t, ec); | ||
| 390 |
2/2✓ Branch 1 taken 2408 times.
✓ Branch 2 taken 34368 times.
|
36776x | if(ec) | |
| 391 | 2408x | return; | ||
| 392 | ||||
| 393 | version v; | |||
| 394 | 34368x | parse_version(it, end, v, ec); | ||
| 395 |
2/2✓ Branch 1 taken 6524 times.
✓ Branch 2 taken 27844 times.
|
34368x | if(ec) | |
| 396 | 6524x | return; | ||
| 397 | ||||
| 398 |
2/2✓ Branch 1 taken 1419 times.
✓ Branch 2 taken 26425 times.
|
27844x | if(distance(it, end) < 2) | |
| 399 | { | |||
| 400 | 1419x | ec = error::need_data; | ||
| 401 | 1419x | return; | ||
| 402 | } | |||
| 403 |
4/4✓ Branch 0 taken 26421 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 26419 times.
|
26425x | if(it[0] != '\r' || it[1] != '\n') | |
| 404 | { | |||
| 405 | 6x | ec = error::bad_line_ending; | ||
| 406 | 6x | return; | ||
| 407 | } | |||
| 408 | 26419x | it += 2; | ||
| 409 | 26419x | h.push_start_line_( | ||
| 410 | 26419x | m, t, v, distance<std::uint16_t>(first, it)); | ||
| 411 | } | |||
| 412 | else | |||
| 413 | { | |||
| 414 | /* | |||
| 415 | status-line = HTTP-version SP status-code SP reason-phrase CRLF | |||
| 416 | status-code = 3*DIGIT | |||
| 417 | reason-phrase = *( HTAB / SP / VCHAR / obs-text ) | |||
| 418 | */ | |||
| 419 | ||||
| 420 | version v; | |||
| 421 | 1655x | parse_version(it, end, v, ec); | ||
| 422 |
2/2✓ Branch 1 taken 752 times.
✓ Branch 2 taken 903 times.
|
1655x | if(ec) | |
| 423 | 1330x | return; | ||
| 424 | ||||
| 425 | // SP | |||
| 426 |
2/2✓ Branch 1 taken 64 times.
✓ Branch 2 taken 839 times.
|
903x | if(distance(it, end) < 1) | |
| 427 | { | |||
| 428 | 64x | ec = error::need_data; | ||
| 429 | 64x | return; | ||
| 430 | } | |||
| 431 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 837 times.
|
839x | if(*it++ != ' ') | |
| 432 | { | |||
| 433 | 2x | ec = error::bad_version; | ||
| 434 | 2x | return; | ||
| 435 | } | |||
| 436 | ||||
| 437 | std::uint16_t s; | |||
| 438 | 837x | parse_status(it, end, s, ec); | ||
| 439 |
2/2✓ Branch 1 taken 258 times.
✓ Branch 2 taken 579 times.
|
837x | if(ec) | |
| 440 | 258x | return; | ||
| 441 | ||||
| 442 | // parse reason CRLF | |||
| 443 | 579x | std::string_view r; | ||
| 444 | 579x | parse_reason(it, end, r, ec); | ||
| 445 |
2/2✓ Branch 1 taken 254 times.
✓ Branch 2 taken 325 times.
|
579x | if(ec) | |
| 446 | 254x | return; | ||
| 447 | 325x | h.push_start_line_( | ||
| 448 | 325x | v, s, r, distance<std::uint16_t>(first, it)); | ||
| 449 | } | |||
| 450 | } | |||
| 451 | ||||
| 452 | void | |||
| 453 | 38353x | head_parser:: | ||
| 454 | parse_fields_( | |||
| 455 | char const*& it, | |||
| 456 | char const* end, | |||
| 457 | system::error_code& ec) noexcept | |||
| 458 | { | |||
| 459 | 38353x | auto& h = h_(); | ||
| 460 | 38353x | std::string_view name; | ||
| 461 | 38353x | std::string_view value; | ||
| 462 | for(;;) | |||
| 463 | { | |||
| 464 |
2/2✓ Branch 1 taken 2589 times.
✓ Branch 2 taken 53324 times.
|
55913x | if(distance(it, end) < 2) | |
| 465 | { | |||
| 466 | 2589x | ec = error::need_data; | ||
| 467 | 2589x | return; | ||
| 468 | } | |||
| 469 |
2/2✓ Branch 0 taken 9078 times.
✓ Branch 1 taken 44246 times.
|
53324x | if(it[0] == '\r') | |
| 470 | { | |||
| 471 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9076 times.
|
9078x | if(it[1] != '\n') | |
| 472 | { | |||
| 473 | 2x | ec = error::bad_line_ending; | ||
| 474 | 2x | return; | ||
| 475 | } | |||
| 476 | // terminating CRLF | |||
| 477 | 9076x | it += 2; | ||
| 478 | 9076x | h.size_ += 2; | ||
| 479 | 9076x | return; | ||
| 480 | } | |||
| 481 | ||||
| 482 |
2/2✓ Branch 1 taken 7876 times.
✓ Branch 2 taken 36370 times.
|
44246x | if(h.size() >= limits_.max_fields) | |
| 483 | { | |||
| 484 | 7876x | ec = error::fields_limit; | ||
| 485 | 7876x | return; | ||
| 486 | } | |||
| 487 | ||||
| 488 | 36370x | auto const first = it; | ||
| 489 | 36370x | parse_limited( | ||
| 490 | 109110x | [&name, &value](auto& it, auto end, auto& ec) | ||
| 491 | { | |||
| 492 | 36370x | parse_field(it, end, name, value, ec); | ||
| 493 | 36370x | }, | ||
| 494 | it, | |||
| 495 | end, | |||
| 496 | 36370x | limits_.max_field + 1u, // 1u for obs lookahead | ||
| 497 | error::field_size_limit, | |||
| 498 | ec); | |||
| 499 |
2/2✓ Branch 1 taken 18776 times.
✓ Branch 2 taken 17594 times.
|
36370x | if(ec) | |
| 500 | 18776x | return; | ||
| 501 | ec = h.push_field_( | |||
| 502 | 17594x | name, value, distance<std::uint16_t>(first, it)); | ||
| 503 |
2/2✓ Branch 1 taken 34 times.
✓ Branch 2 taken 17560 times.
|
17594x | if(ec) | |
| 504 | 34x | return; | ||
| 505 | 17560x | } | ||
| 506 | } | |||
| 507 | ||||
| 508 | } // namespace burl | |||
| 509 | } // namespace boost | |||
| 510 |