src/head_parser.cpp
99.6% Lines (238/239)
100.0% List of functions (17/17)
94.7% Branches (108/114)
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> >&, std::error_code&)
:58
79027x
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> >&, std::error_code&)
:91
36779x
100.0%
100.0%
100.0%
boost::burl::(anonymous namespace)::parse_version(char const*&, char const*, boost::http::version&, std::error_code&)
:124
36038x
100.0%
100.0%
100.0%
boost::burl::(anonymous namespace)::parse_status(char const*&, char const*, unsigned short&, std::error_code&)
:151
843x
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> >&, std::error_code&)
:192
585x
100.0%
100.0%
100.0%
boost::burl::head_parser::head_parser(bool, char*, unsigned long, boost::burl::header_limits const&)
:215
40858x
93.8%
83.3%
93.0%
boost::burl::head_parser::head_parser(boost::burl::head_parser&&)
:240
343x
100.0%
100.0%
100.0%
boost::burl::head_parser::operator=(boost::burl::head_parser&&)
:255
311x
100.0%
100.0%
100.0%
boost::burl::head_parser::ceiling() const
:273
195891x
100.0%
100.0%
100.0%
boost::burl::head_parser::reset(char*)
:284
387x
100.0%
75.0%
92.0%
boost::burl::head_parser::rebase(char*)
:300
209x
100.0%
50.0%
80.0%
boost::burl::head_parser::parse(unsigned long)
:309
92306x
100.0%
62.5%
95.0%
auto boost::burl::head_parser::parse(unsigned long)::{lambda(auto:1&, auto:2, auto:3&)#1}::operator()<char const*, char const*, std::error_code>(char const*&, char const*, std::error_code&) const
:324
80694x
100.0%
100.0%
100.0%
auto boost::burl::head_parser::parse(unsigned long)::{lambda(auto:1&, auto:2, auto:3&)#2}::operator()<char const*, char const*, std::error_code>(char const*&, char const*, std::error_code&) const
:341
38362x
100.0%
100.0%
100.0%
boost::burl::head_parser::parse_start_line_(char const*&, char const*, std::error_code&)
:370
80694x
100.0%
100.0%
100.0%
boost::burl::head_parser::parse_fields_(char const*&, char const*, std::error_code&)
:455
38362x
100.0%
100.0%
100.0%
auto boost::burl::head_parser::parse_fields_(char const*&, char const*, std::error_code&)::{lambda(auto:1&, auto:2, auto:3&)#1}::operator()<char const*, char const*, std::error_code>(char const*&, char const*, std::error_code&) const
:492
36386x
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 | 79027x | parse_method( | ||
| 59 | char const*& it, | |||
| 60 | char const* end, | |||
| 61 | std::string_view& result, | |||
| 62 | std::error_code& ec) | |||
| 63 | { | |||
| 64 | // parse token SP | |||
| 65 | 79027x | auto const first = it; | ||
| 66 | 114593x | for(;; ++it) | ||
| 67 | { | |||
| 68 |
2/2✓ Branch 1 taken 42244 times.
✓ Branch 2 taken 151376 times.
|
193620x | if(distance(it, end) < 1) | |
| 69 | { | |||
| 70 | 42244x | ec = error::need_data; | ||
| 71 | 42244x | return; | ||
| 72 | } | |||
| 73 |
2/2✓ Branch 1 taken 36783 times.
✓ Branch 2 taken 114593 times.
|
151376x | if(! is_token_char(*it)) | |
| 74 | 36783x | break; | ||
| 75 | } | |||
| 76 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 36781 times.
|
36783x | if(*it != ' ') | |
| 77 | { | |||
| 78 | 2x | ec = error::bad_method; | ||
| 79 | 2x | return; | ||
| 80 | } | |||
| 81 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 36779 times.
|
36781x | if(it == first) | |
| 82 | { | |||
| 83 | // cannot be empty | |||
| 84 | 2x | ec = error::bad_method; | ||
| 85 | 2x | return; | ||
| 86 | } | |||
| 87 | 36779x | result = { first, it++ }; | ||
| 88 | } | |||
| 89 | ||||
| 90 | void | |||
| 91 | 36779x | parse_target( | ||
| 92 | char const*& it, | |||
| 93 | char const* end, | |||
| 94 | std::string_view& result, | |||
| 95 | std::error_code& ec) | |||
| 96 | { | |||
| 97 | // parse target SP | |||
| 98 | 36779x | auto const first = it; | ||
| 99 | 83509x | for(;; ++it) | ||
| 100 | { | |||
| 101 |
2/2✓ Branch 1 taken 2402 times.
✓ Branch 2 taken 117886 times.
|
120288x | if(distance(it, end) < 1) | |
| 102 | { | |||
| 103 | 2402x | ec = error::need_data; | ||
| 104 | 2402x | return; | ||
| 105 | } | |||
| 106 |
2/2✓ Branch 1 taken 34377 times.
✓ Branch 2 taken 83509 times.
|
117886x | if(! is_target_char(*it)) | |
| 107 | 34377x | break; | ||
| 108 | } | |||
| 109 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 34373 times.
|
34377x | 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 34371 times.
|
34373x | if(it == first) | |
| 115 | { | |||
| 116 | // cannot be empty | |||
| 117 | 2x | ec = error::bad_request_target; | ||
| 118 | 2x | return; | ||
| 119 | } | |||
| 120 | 34371x | result = { first, it++ }; | ||
| 121 | } | |||
| 122 | ||||
| 123 | void | |||
| 124 | 36038x | parse_version( | ||
| 125 | char const*& it, | |||
| 126 | char const* end, | |||
| 127 | version& result, | |||
| 128 | std::error_code& ec) | |||
| 129 | { | |||
| 130 |
2/2✓ Branch 1 taken 7273 times.
✓ Branch 2 taken 28765 times.
|
36038x | if(distance(it, end) < 8) | |
| 131 | { | |||
| 132 | 7273x | ec = error::need_data; | ||
| 133 | 7273x | return; | ||
| 134 | } | |||
| 135 |
2/2✓ Branch 0 taken 28748 times.
✓ Branch 1 taken 17 times.
|
28765x | if(std::memcmp(it, "HTTP/1.1", 8) == 0) | |
| 136 | { | |||
| 137 | 28748x | it += 8; | ||
| 138 | 28748x | result = version::http_1_1; | ||
| 139 | 28748x | 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 | 843x | parse_status( | ||
| 152 | char const*& it, | |||
| 153 | char const* end, | |||
| 154 | std::uint16_t& result, | |||
| 155 | std::error_code& ec) | |||
| 156 | { | |||
| 157 | // parse 3(digit) SP | |||
| 158 |
2/2✓ Branch 1 taken 250 times.
✓ Branch 2 taken 593 times.
|
843x | 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 591 times.
|
593x | if(! is_digit(*it)) | |
| 164 | { | |||
| 165 | 2x | ec = error::bad_status_code; | ||
| 166 | 2x | return; | ||
| 167 | } | |||
| 168 | 591x | result = 100 * (*it++ - '0'); | ||
| 169 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 589 times.
|
591x | if(! is_digit(*it)) | |
| 170 | { | |||
| 171 | 2x | ec = error::bad_status_code; | ||
| 172 | 2x | return; | ||
| 173 | } | |||
| 174 | 589x | result += 10 * (*it++ - '0'); | ||
| 175 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 587 times.
|
589x | if(! is_digit(*it)) | |
| 176 | { | |||
| 177 | 2x | ec = error::bad_status_code; | ||
| 178 | 2x | return; | ||
| 179 | } | |||
| 180 | 587x | result += *it++ - '0'; | ||
| 181 |
2/2✓ Branch 0 taken 583 times.
✓ Branch 1 taken 4 times.
|
587x | if(*it == ' ') | |
| 182 | { | |||
| 183 | 583x | ++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 | 585x | parse_reason( | ||
| 193 | char const*& it, | |||
| 194 | char const* end, | |||
| 195 | std::string_view& result, | |||
| 196 | std::error_code& ec) | |||
| 197 | { | |||
| 198 | 585x | auto const first = it; | ||
| 199 | 585x | char const* token_end = nullptr; | ||
| 200 | 585x | auto p = parse_token_to_eol( | ||
| 201 | it, end, token_end, ec); | |||
| 202 |
2/2✓ Branch 1 taken 252 times.
✓ Branch 2 taken 333 times.
|
585x | if(ec) | |
| 203 | 254x | return; | ||
| 204 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 331 times.
|
333x | if(! p) | |
| 205 | { | |||
| 206 | 2x | ec = error::bad_reason; | ||
| 207 | 2x | return; | ||
| 208 | } | |||
| 209 | 331x | result = { first, token_end }; | ||
| 210 | 331x | it = p; | ||
| 211 | } | |||
| 212 | ||||
| 213 | } // namespace | |||
| 214 | ||||
| 215 | 40858x | head_parser:: | ||
| 216 | head_parser( | |||
| 217 | bool is_request, | |||
| 218 | char* buf, | |||
| 219 | std::size_t n, | |||
| 220 | 40858x | header_limits const& limits) noexcept | ||
| 221 | 40858x | : limits_(limits) | ||
| 222 | 40858x | , is_req_(is_request) | ||
| 223 | { | |||
| 224 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40858 times.
|
40858x | if(limits_.max_size > fields_base::max_buffer_size) | |
| 225 | ✗ | limits_.max_size = fields_base::max_buffer_size; | ||
| 226 | ||||
| 227 | 40858x | auto const a = reinterpret_cast<std::uintptr_t>(buf); | ||
| 228 | 40858x | auto const e = (a + n) - | ||
| 229 | 40858x | (a + n) % alignof(message_head_base::entry); | ||
| 230 |
2/2✓ Branch 0 taken 40544 times.
✓ Branch 1 taken 314 times.
|
40858x | auto const cap = (e > a) ? e - a : 0; | |
| 231 | ||||
| 232 |
2/2✓ Branch 0 taken 40534 times.
✓ Branch 1 taken 324 times.
|
40858x | if(is_req_) | |
| 233 | 40534x | ::new(static_cast<void*>(&s_.req)) | ||
| 234 | 40534x | class request_head_base(buf, cap); | ||
| 235 | else | |||
| 236 | 324x | ::new(static_cast<void*>(&s_.res)) | ||
| 237 | 324x | class response_head_base(buf, cap); | ||
| 238 | 40858x | } | ||
| 239 | ||||
| 240 | 343x | head_parser:: | ||
| 241 | 343x | head_parser(head_parser&& other) noexcept | ||
| 242 | 343x | : limits_(other.limits_) | ||
| 243 | 343x | , is_req_(other.is_req_) | ||
| 244 | 343x | , st_(other.st_) | ||
| 245 | { | |||
| 246 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 332 times.
|
343x | if(is_req_) | |
| 247 | 11x | ::new(static_cast<void*>(&s_.req)) | ||
| 248 | 11x | class request_head_base(other.s_.req); | ||
| 249 | else | |||
| 250 | 332x | ::new(static_cast<void*>(&s_.res)) | ||
| 251 | 332x | class response_head_base(other.s_.res); | ||
| 252 | 343x | } | ||
| 253 | ||||
| 254 | head_parser& | |||
| 255 | 311x | head_parser:: | ||
| 256 | operator=(head_parser&& other) noexcept | |||
| 257 | { | |||
| 258 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 310 times.
|
311x | if(this == &other) | |
| 259 | 1x | return *this; | ||
| 260 | 310x | limits_ = other.limits_; | ||
| 261 | 310x | is_req_ = other.is_req_; | ||
| 262 | 310x | st_ = other.st_; | ||
| 263 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 304 times.
|
310x | if(is_req_) | |
| 264 | 6x | ::new(static_cast<void*>(&s_.req)) | ||
| 265 | 6x | class request_head_base(other.s_.req); | ||
| 266 | else | |||
| 267 | 304x | ::new(static_cast<void*>(&s_.res)) | ||
| 268 | 304x | class response_head_base(other.s_.res); | ||
| 269 | 310x | return *this; | ||
| 270 | } | |||
| 271 | ||||
| 272 | char* | |||
| 273 | 195891x | head_parser:: | ||
| 274 | ceiling() const noexcept | |||
| 275 | { | |||
| 276 | 195891x | auto const& h = h_(); | ||
| 277 | auto const reserve = | |||
| 278 | 195891x | message_head_base::table_space_(limits_.max_fields); | ||
| 279 | 195891x | auto const cap = h.capacity_in_bytes(); | ||
| 280 |
2/2✓ Branch 1 taken 195844 times.
✓ Branch 2 taken 47 times.
|
195891x | return h.base_() + (cap > reserve ? cap - reserve : 0); | |
| 281 | } | |||
| 282 | ||||
| 283 | void | |||
| 284 | 387x | head_parser:: | ||
| 285 | reset(char* base) noexcept | |||
| 286 | { | |||
| 287 | 387x | auto& h = h_(); | ||
| 288 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 387 times.
|
387x | BOOST_ASSERT(base <= ceiling()); | |
| 289 | 387x | auto const cap = static_cast<std::size_t>(h.end_ - base); | ||
| 290 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 373 times.
|
387x | if(is_req_) | |
| 291 | 14x | ::new(static_cast<void*>(&s_.req)) | ||
| 292 | 14x | class request_head_base(base, cap); | ||
| 293 | else | |||
| 294 | 373x | ::new(static_cast<void*>(&s_.res)) | ||
| 295 | 373x | class response_head_base(base, cap); | ||
| 296 | 387x | st_ = state::start_line; | ||
| 297 | 387x | } | ||
| 298 | ||||
| 299 | void | |||
| 300 | 209x | head_parser:: | ||
| 301 | rebase(char* base) noexcept | |||
| 302 | { | |||
| 303 | 209x | auto& h = h_(); | ||
| 304 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 209 times.
|
209x | BOOST_ASSERT(base <= h.base_()); | |
| 305 | 209x | h.buf_ = base + h.prefix_; | ||
| 306 | 209x | } | ||
| 307 | ||||
| 308 | system::result<void, std::error_code> | |||
| 309 | 92306x | head_parser:: | ||
| 310 | parse(std::size_t n) noexcept | |||
| 311 | { | |||
| 312 | 92306x | std::error_code ec; | ||
| 313 | 92306x | auto const& h = h_(); | ||
| 314 | 92306x | char const* it = h.buf_ + h.size_; | ||
| 315 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 92306 times.
|
92306x | BOOST_ASSERT(n >= std::size_t(h.prefix_) + h.size_); | |
| 316 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 92306 times.
|
92306x | BOOST_ASSERT(h.base_() + n <= ceiling()); | |
| 317 | 92306x | auto* const end = h.base_() + n; | ||
| 318 | ||||
| 319 |
3/4✓ Branch 0 taken 80694 times.
✓ Branch 1 taken 11609 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
92306x | switch(st_) | |
| 320 | { | |||
| 321 | 80694x | case state::start_line: | ||
| 322 | { | |||
| 323 | 161388x | parse_limited( | ||
| 324 | 80694x | [this](auto& it, auto end, auto& ec) | ||
| 325 | { | |||
| 326 | 80694x | parse_start_line_(it, end, ec); | ||
| 327 | 80694x | }, | ||
| 328 | it, | |||
| 329 | end, | |||
| 330 | 80694x | detail::clamp(limits_.max_start_line, limits_.max_size), | ||
| 331 | error::start_line_limit, | |||
| 332 | ec); | |||
| 333 |
2/2✓ Branch 1 taken 53941 times.
✓ Branch 2 taken 26753 times.
|
80694x | if(ec) | |
| 334 | 53941x | break; | ||
| 335 | 26753x | st_ = state::fields; | ||
| 336 | BOOST_FALLTHROUGH; | |||
| 337 | } | |||
| 338 | 38362x | case state::fields: | ||
| 339 | { | |||
| 340 | 38362x | parse_limited( | ||
| 341 | 115086x | [this](auto& it, auto end, auto& ec) | ||
| 342 | { | |||
| 343 | 38362x | parse_fields_(it, end, ec); | ||
| 344 | 38362x | }, | ||
| 345 | it, | |||
| 346 | end, | |||
| 347 | 38362x | limits_.max_size - h.prefix_ - h.size_, | ||
| 348 | error::headers_limit, | |||
| 349 | ec); | |||
| 350 |
2/2✓ Branch 1 taken 29277 times.
✓ Branch 2 taken 9085 times.
|
38362x | if(ec) | |
| 351 | 29277x | break; | ||
| 352 | 9085x | st_ = state::done; | ||
| 353 | BOOST_FALLTHROUGH; | |||
| 354 | } | |||
| 355 | 9088x | case state::done: | ||
| 356 | { | |||
| 357 | 9088x | ec = h.validate_framing_(); | ||
| 358 | } | |||
| 359 | } | |||
| 360 | ||||
| 361 |
6/6✓ Branch 2 taken 51897 times.
✓ Branch 3 taken 40409 times.
✓ Branch 5 taken 214 times.
✓ Branch 6 taken 51683 times.
✓ Branch 7 taken 214 times.
✓ Branch 8 taken 92092 times.
|
92306x | if(ec == error::need_data && end >= ceiling()) | |
| 362 | 214x | ec = error::in_place_overflow; | ||
| 363 | ||||
| 364 |
2/2✓ Branch 1 taken 83224 times.
✓ Branch 2 taken 9082 times.
|
92306x | if(ec) | |
| 365 | 83224x | return ec; | ||
| 366 | 9082x | return {}; | ||
| 367 | } | |||
| 368 | ||||
| 369 | void | |||
| 370 | 80694x | head_parser:: | ||
| 371 | parse_start_line_( | |||
| 372 | char const*& it, | |||
| 373 | char const* end, | |||
| 374 | std::error_code& ec) noexcept | |||
| 375 | { | |||
| 376 | 80694x | auto& h = h_(); | ||
| 377 | 80694x | auto const first = it; | ||
| 378 |
2/2✓ Branch 0 taken 79027 times.
✓ Branch 1 taken 1667 times.
|
80694x | if(is_req_) | |
| 379 | { | |||
| 380 | /* | |||
| 381 | request-line = method SP request-target SP HTTP-version CRLF | |||
| 382 | method = token | |||
| 383 | */ | |||
| 384 | ||||
| 385 | 79027x | std::string_view m; | ||
| 386 | 79027x | parse_method(it, end, m, ec); | ||
| 387 |
2/2✓ Branch 1 taken 42248 times.
✓ Branch 2 taken 36779 times.
|
79027x | if(ec) | |
| 388 | 52605x | return; | ||
| 389 | ||||
| 390 | 36779x | std::string_view t; | ||
| 391 | 36779x | parse_target(it, end, t, ec); | ||
| 392 |
2/2✓ Branch 1 taken 2408 times.
✓ Branch 2 taken 34371 times.
|
36779x | if(ec) | |
| 393 | 2408x | return; | ||
| 394 | ||||
| 395 | version v; | |||
| 396 | 34371x | parse_version(it, end, v, ec); | ||
| 397 |
2/2✓ Branch 1 taken 6524 times.
✓ Branch 2 taken 27847 times.
|
34371x | if(ec) | |
| 398 | 6524x | return; | ||
| 399 | ||||
| 400 |
2/2✓ Branch 1 taken 1419 times.
✓ Branch 2 taken 26428 times.
|
27847x | if(distance(it, end) < 2) | |
| 401 | { | |||
| 402 | 1419x | ec = error::need_data; | ||
| 403 | 1419x | return; | ||
| 404 | } | |||
| 405 |
4/4✓ Branch 0 taken 26424 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 26422 times.
|
26428x | if(it[0] != '\r' || it[1] != '\n') | |
| 406 | { | |||
| 407 | 6x | ec = error::bad_line_ending; | ||
| 408 | 6x | return; | ||
| 409 | } | |||
| 410 | 26422x | it += 2; | ||
| 411 | 26422x | h.push_start_line_( | ||
| 412 | 26422x | m, t, v, distance<std::uint16_t>(first, it)); | ||
| 413 | } | |||
| 414 | else | |||
| 415 | { | |||
| 416 | /* | |||
| 417 | status-line = HTTP-version SP status-code SP reason-phrase CRLF | |||
| 418 | status-code = 3*DIGIT | |||
| 419 | reason-phrase = *( HTAB / SP / VCHAR / obs-text ) | |||
| 420 | */ | |||
| 421 | ||||
| 422 | version v; | |||
| 423 | 1667x | parse_version(it, end, v, ec); | ||
| 424 |
2/2✓ Branch 1 taken 758 times.
✓ Branch 2 taken 909 times.
|
1667x | if(ec) | |
| 425 | 1336x | return; | ||
| 426 | ||||
| 427 | // SP | |||
| 428 |
2/2✓ Branch 1 taken 64 times.
✓ Branch 2 taken 845 times.
|
909x | if(distance(it, end) < 1) | |
| 429 | { | |||
| 430 | 64x | ec = error::need_data; | ||
| 431 | 64x | return; | ||
| 432 | } | |||
| 433 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 843 times.
|
845x | if(*it++ != ' ') | |
| 434 | { | |||
| 435 | 2x | ec = error::bad_version; | ||
| 436 | 2x | return; | ||
| 437 | } | |||
| 438 | ||||
| 439 | std::uint16_t s; | |||
| 440 | 843x | parse_status(it, end, s, ec); | ||
| 441 |
2/2✓ Branch 1 taken 258 times.
✓ Branch 2 taken 585 times.
|
843x | if(ec) | |
| 442 | 258x | return; | ||
| 443 | ||||
| 444 | // parse reason CRLF | |||
| 445 | 585x | std::string_view r; | ||
| 446 | 585x | parse_reason(it, end, r, ec); | ||
| 447 |
2/2✓ Branch 1 taken 254 times.
✓ Branch 2 taken 331 times.
|
585x | if(ec) | |
| 448 | 254x | return; | ||
| 449 | 331x | h.push_start_line_( | ||
| 450 | 331x | v, s, r, distance<std::uint16_t>(first, it)); | ||
| 451 | } | |||
| 452 | } | |||
| 453 | ||||
| 454 | void | |||
| 455 | 38362x | head_parser:: | ||
| 456 | parse_fields_( | |||
| 457 | char const*& it, | |||
| 458 | char const* end, | |||
| 459 | std::error_code& ec) noexcept | |||
| 460 | { | |||
| 461 | 38362x | auto& h = h_(); | ||
| 462 | 38362x | std::string_view name; | ||
| 463 | 38362x | std::string_view value; | ||
| 464 | for(;;) | |||
| 465 | { | |||
| 466 |
2/2✓ Branch 1 taken 2589 times.
✓ Branch 2 taken 53349 times.
|
55938x | if(distance(it, end) < 2) | |
| 467 | { | |||
| 468 | 2589x | ec = error::need_data; | ||
| 469 | 2589x | return; | ||
| 470 | } | |||
| 471 |
2/2✓ Branch 0 taken 9087 times.
✓ Branch 1 taken 44262 times.
|
53349x | if(it[0] == '\r') | |
| 472 | { | |||
| 473 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9085 times.
|
9087x | if(it[1] != '\n') | |
| 474 | { | |||
| 475 | 2x | ec = error::bad_line_ending; | ||
| 476 | 2x | return; | ||
| 477 | } | |||
| 478 | // terminating CRLF | |||
| 479 | 9085x | it += 2; | ||
| 480 | 9085x | h.size_ += 2; | ||
| 481 | 9085x | return; | ||
| 482 | } | |||
| 483 | ||||
| 484 |
2/2✓ Branch 1 taken 7876 times.
✓ Branch 2 taken 36386 times.
|
44262x | if(h.size() >= limits_.max_fields) | |
| 485 | { | |||
| 486 | 7876x | ec = error::fields_limit; | ||
| 487 | 7876x | return; | ||
| 488 | } | |||
| 489 | ||||
| 490 | 36386x | auto const first = it; | ||
| 491 | 36386x | parse_limited( | ||
| 492 | 109158x | [&name, &value](auto& it, auto end, auto& ec) | ||
| 493 | { | |||
| 494 | 36386x | parse_field(it, end, name, value, ec); | ||
| 495 | 36386x | }, | ||
| 496 | it, | |||
| 497 | end, | |||
| 498 | 36386x | limits_.max_field + 1u, // 1u for obs lookahead | ||
| 499 | error::field_size_limit, | |||
| 500 | ec); | |||
| 501 |
2/2✓ Branch 1 taken 18776 times.
✓ Branch 2 taken 17610 times.
|
36386x | if(ec) | |
| 502 | 18776x | return; | ||
| 503 | 17610x | ec = h.push_field_( | ||
| 504 | 17610x | name, value, distance<std::uint16_t>(first, it)); | ||
| 505 |
2/2✓ Branch 1 taken 34 times.
✓ Branch 2 taken 17576 times.
|
17610x | if(ec) | |
| 506 | 34x | return; | ||
| 507 | 17576x | } | ||
| 508 | } | |||
| 509 | ||||
| 510 | } // namespace burl | |||
| 511 | } // namespace boost | |||
| 512 |