src/message_head_base.cpp
99.3% Lines (285/287)
100.0% List of functions (22/22)
96.1% Branches (197/205)
Functions (22)
Function
Calls
Lines
Branches
Blocks
boost::burl::(anonymous namespace)::parse_dec(std::basic_string_view<char, std::char_traits<char> >, unsigned long&)
:41
348x
100.0%
100.0%
100.0%
boost::burl::(anonymous namespace)::token_list_contains(std::basic_string_view<char, std::char_traits<char> >, boost::core::basic_string_view<char>)
:64
13x
100.0%
100.0%
100.0%
boost::burl::(anonymous namespace)::last_coding_is_chunked(std::basic_string_view<char, std::char_traits<char> >)
:79
87x
100.0%
100.0%
100.0%
boost::burl::(anonymous namespace)::is_ws(char)
:93
4x
100.0%
100.0%
100.0%
boost::burl::message_head_base::conn_flags_(std::basic_string_view<char, std::char_traits<char> >)
:101
42x
100.0%
100.0%
100.0%
boost::burl::message_head_base::message_head_base(bool, char*, unsigned long, unsigned int, unsigned short)
:121
41633x
100.0%
83.3%
88.0%
boost::burl::message_head_base::swap_(boost::burl::message_head_base&)
:144
37x
100.0%
100.0%
100.0%
boost::burl::message_head_base::set_version_(boost::http::version)
:157
26920x
100.0%
100.0%
100.0%
boost::burl::message_head_base::push_start_line_(std::basic_string_view<char, std::char_traits<char> >, std::basic_string_view<char, std::char_traits<char> >, boost::http::version, unsigned short)
:167
26419x
100.0%
50.0%
88.0%
boost::burl::message_head_base::push_start_line_(boost::http::version, unsigned short, std::basic_string_view<char, std::char_traits<char> >, unsigned short)
:184
325x
100.0%
50.0%
80.0%
boost::burl::message_head_base::push_field_(std::basic_string_view<char, std::char_traits<char> >, std::basic_string_view<char, std::char_traits<char> >, unsigned short)
:200
17594x
100.0%
100.0%
100.0%
boost::burl::message_head_base::validate_framing_() const
:273
9079x
100.0%
100.0%
100.0%
boost::burl::message_head_base::on_special_(boost::http::field)
:284
289x
95.5%
96.2%
98.0%
boost::burl::message_head_base::on_clear_()
:347
3x
100.0%
–
100.0%
boost::burl::message_head_base::payload() const
:363
941x
100.0%
91.7%
100.0%
boost::burl::message_head_base::content_length() const
:394
289x
100.0%
100.0%
100.0%
boost::burl::message_head_base::chunked() const
:403
361x
100.0%
–
100.0%
boost::burl::message_head_base::keep_alive() const
:410
154x
100.0%
83.3%
100.0%
boost::burl::message_head_base::set_content_length(unsigned long)
:428
122x
100.0%
100.0%
86.0%
boost::burl::message_head_base::set_chunked(bool)
:440
188x
100.0%
95.7%
96.0%
boost::burl::message_head_base::set_keep_alive(bool)
:471
11x
100.0%
100.0%
87.0%
boost::burl::operator<<(std::ostream&, boost::burl::message_head_base const&)
:517
3x
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/message_head_base.hpp> | |||
| 12 | ||||
| 13 | #include <boost/core/detail/string_view.hpp> | |||
| 14 | #include <boost/http/rfc/list_rule.hpp> | |||
| 15 | #include <boost/http/rfc/token_rule.hpp> | |||
| 16 | #include <boost/url/grammar/ci_string.hpp> | |||
| 17 | #include <boost/url/grammar/parse.hpp> | |||
| 18 | ||||
| 19 | #include <charconv> | |||
| 20 | #include <cstdint> | |||
| 21 | #include <limits> | |||
| 22 | #include <ostream> | |||
| 23 | #include <string> | |||
| 24 | ||||
| 25 | namespace boost | |||
| 26 | { | |||
| 27 | namespace burl | |||
| 28 | { | |||
| 29 | ||||
| 30 | using error = http::error; | |||
| 31 | using field = http::field; | |||
| 32 | using payload = http::payload; | |||
| 33 | ||||
| 34 | namespace grammar = urls::grammar; | |||
| 35 | using grammar::ci_is_equal; | |||
| 36 | ||||
| 37 | namespace | |||
| 38 | { | |||
| 39 | ||||
| 40 | bool | |||
| 41 | 348x | parse_dec( | ||
| 42 | std::string_view s, | |||
| 43 | std::uint64_t& n) noexcept | |||
| 44 | { | |||
| 45 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 345 times.
|
348x | if(s.empty()) | |
| 46 | 3x | return false; | ||
| 47 | 345x | n = 0; | ||
| 48 |
2/2✓ Branch 2 taken 556 times.
✓ Branch 3 taken 337 times.
|
893x | for(char const c : s) | |
| 49 | { | |||
| 50 |
4/4✓ Branch 0 taken 554 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 551 times.
|
556x | if(c < '0' || c > '9') | |
| 51 | 5x | return false; | ||
| 52 | 551x | auto const d = static_cast<std::uint64_t>(c - '0'); | ||
| 53 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 548 times.
|
551x | if(n > ((std::numeric_limits<std::uint64_t>::max)() - d) / 10) | |
| 54 | 3x | return false; | ||
| 55 | 548x | n = n * 10 + d; | ||
| 56 | } | |||
| 57 | 337x | return true; | ||
| 58 | } | |||
| 59 | ||||
| 60 | constexpr auto token_list_rule = | |||
| 61 | http::list_rule(http::token_rule); | |||
| 62 | ||||
| 63 | bool | |||
| 64 | 13x | token_list_contains( | ||
| 65 | std::string_view value, | |||
| 66 | core::string_view token) noexcept | |||
| 67 | { | |||
| 68 | 13x | auto const rv = grammar::parse(value, token_list_rule); | ||
| 69 |
2/2✓ Branch 1 taken 12 times.
✓ Branch 2 taken 1 time.
|
13x | if(rv) | |
| 70 | { | |||
| 71 |
2/2✓ Branch 6 taken 13 times.
✓ Branch 7 taken 2 times.
|
15x | for(auto t : *rv) | |
| 72 |
2/2✓ Branch 1 taken 10 times.
✓ Branch 2 taken 3 times.
|
13x | if(ci_is_equal(t, token)) | |
| 73 | 10x | return true; | ||
| 74 | } | |||
| 75 | 3x | return false; | ||
| 76 | 13x | } | ||
| 77 | ||||
| 78 | bool | |||
| 79 | 87x | last_coding_is_chunked( | ||
| 80 | std::string_view value) noexcept | |||
| 81 | { | |||
| 82 | 87x | auto const rv = grammar::parse(value, token_list_rule); | ||
| 83 | 87x | auto chunked = false; | ||
| 84 |
2/2✓ Branch 1 taken 86 times.
✓ Branch 2 taken 1 time.
|
87x | if(rv) | |
| 85 | { | |||
| 86 |
2/2✓ Branch 5 taken 91 times.
✓ Branch 6 taken 86 times.
|
177x | for(auto t : *rv) | |
| 87 | 91x | chunked = ci_is_equal(t, "chunked"); | ||
| 88 | } | |||
| 89 | 174x | return chunked; | ||
| 90 | 87x | } | ||
| 91 | ||||
| 92 | bool | |||
| 93 | 4x | is_ws(char c) noexcept | ||
| 94 | { | |||
| 95 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 2 times.
|
4x | return c == ' ' || c == '\t'; | |
| 96 | } | |||
| 97 | ||||
| 98 | } // namespace | |||
| 99 | ||||
| 100 | std::uint16_t | |||
| 101 | 42x | message_head_base:: | ||
| 102 | conn_flags_(std::string_view value) noexcept | |||
| 103 | { | |||
| 104 | 42x | std::uint16_t f = 0; | ||
| 105 | 42x | auto const rv = grammar::parse(value, token_list_rule); | ||
| 106 |
2/2✓ Branch 1 taken 41 times.
✓ Branch 2 taken 1 time.
|
42x | if(rv) | |
| 107 | { | |||
| 108 |
2/2✓ Branch 6 taken 48 times.
✓ Branch 7 taken 41 times.
|
89x | for(auto t : *rv) | |
| 109 | { | |||
| 110 |
2/2✓ Branch 2 taken 24 times.
✓ Branch 3 taken 24 times.
|
48x | if(ci_is_equal(t, "close")) | |
| 111 | 24x | f |= f_conn_close; | ||
| 112 |
2/2✓ Branch 2 taken 9 times.
✓ Branch 3 taken 15 times.
|
24x | else if(ci_is_equal(t, "keep-alive")) | |
| 113 | 9x | f |= f_conn_keep_alive; | ||
| 114 |
2/2✓ Branch 2 taken 7 times.
✓ Branch 3 taken 8 times.
|
15x | else if(ci_is_equal(t, "upgrade")) | |
| 115 | 7x | f |= f_conn_upgrade; | ||
| 116 | } | |||
| 117 | } | |||
| 118 | 84x | return f; | ||
| 119 | 42x | } | ||
| 120 | ||||
| 121 | 41633x | message_head_base:: | ||
| 122 | message_head_base( | |||
| 123 | bool is_request, | |||
| 124 | char* base, | |||
| 125 | std::size_t cap, | |||
| 126 | std::uint32_t size, | |||
| 127 | 41633x | std::uint16_t prefix) noexcept | ||
| 128 | 41633x | : fields_base(base, cap, size, 0, prefix) | ||
| 129 | { | |||
| 130 |
3/4✓ Branch 0 taken 40912 times.
✓ Branch 1 taken 721 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 40912 times.
|
41633x | BOOST_ASSERT( | |
| 131 | cap == 0 || | |||
| 132 | (reinterpret_cast<std::uintptr_t>(base) + cap) % | |||
| 133 | alignof(entry) == 0); | |||
| 134 |
2/2✓ Branch 0 taken 40773 times.
✓ Branch 1 taken 860 times.
|
41633x | if(is_request) | |
| 135 | { | |||
| 136 | 40773x | flags_ |= f_req; | ||
| 137 | 40773x | req_ = req_t{}; | ||
| 138 | } | |||
| 139 | else | |||
| 140 | 860x | res_ = res_t{}; | ||
| 141 | 41633x | } | ||
| 142 | ||||
| 143 | void | |||
| 144 | 37x | message_head_base:: | ||
| 145 | swap_(message_head_base& other) noexcept | |||
| 146 | { | |||
| 147 | 37x | fields_base::swap_(other); | ||
| 148 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 19 times.
|
37x | if(flags_ & f_req) | |
| 149 | 18x | std::swap(req_, other.req_); | ||
| 150 | else | |||
| 151 | 19x | std::swap(res_, other.res_); | ||
| 152 | 37x | std::swap(content_length_v_, other.content_length_v_); | ||
| 153 | 37x | std::swap(flags_, other.flags_); | ||
| 154 | 37x | } | ||
| 155 | ||||
| 156 | void | |||
| 157 | 26920x | message_head_base:: | ||
| 158 | set_version_(http::version v) noexcept | |||
| 159 | { | |||
| 160 |
2/2✓ Branch 0 taken 26904 times.
✓ Branch 1 taken 16 times.
|
26920x | if(v == http::version::http_1_1) | |
| 161 | 26904x | flags_ |= f_http_1_1; | ||
| 162 | else | |||
| 163 | 16x | flags_ &= ~f_http_1_1; | ||
| 164 | 26920x | } | ||
| 165 | ||||
| 166 | void | |||
| 167 | 26419x | message_head_base:: | ||
| 168 | push_start_line_( | |||
| 169 | std::string_view method, | |||
| 170 | std::string_view target, | |||
| 171 | http::version v, | |||
| 172 | std::uint16_t n) noexcept | |||
| 173 | { | |||
| 174 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26419 times.
|
26419x | BOOST_ASSERT(flags_ & f_req); | |
| 175 | 26419x | req_.method_len_ = static_cast<std::uint16_t>(method.size()); | ||
| 176 | 26419x | req_.target_len_ = static_cast<std::uint16_t>(target.size()); | ||
| 177 | 26419x | req_.method_ = http::string_to_method(method); | ||
| 178 | 26419x | set_version_(v); | ||
| 179 | 26419x | prefix_ = n; | ||
| 180 | 26419x | buf_ += n; | ||
| 181 | 26419x | } | ||
| 182 | ||||
| 183 | void | |||
| 184 | 325x | message_head_base:: | ||
| 185 | push_start_line_( | |||
| 186 | http::version v, | |||
| 187 | std::uint16_t status_int, | |||
| 188 | std::string_view, | |||
| 189 | std::uint16_t n) noexcept | |||
| 190 | { | |||
| 191 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
|
325x | BOOST_ASSERT(!(flags_ & f_req)); | |
| 192 | 325x | res_.status_int_ = status_int; | ||
| 193 | 325x | res_.status_ = http::int_to_status(status_int); | ||
| 194 | 325x | set_version_(v); | ||
| 195 | 325x | prefix_ = n; | ||
| 196 | 325x | buf_ += n; | ||
| 197 | 325x | } | ||
| 198 | ||||
| 199 | http::error | |||
| 200 | 17594x | message_head_base:: | ||
| 201 | push_field_( | |||
| 202 | std::string_view name, | |||
| 203 | std::string_view value, | |||
| 204 | std::uint16_t n) noexcept | |||
| 205 | { | |||
| 206 | 17594x | auto const id = resolve_(name); | ||
| 207 | ||||
| 208 |
6/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 209 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 143 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 17218 times.
|
17594x | switch(static_cast<field>(id)) | |
| 209 | { | |||
| 210 | 18x | case field::connection: | ||
| 211 | 18x | flags_ |= conn_flags_(value); | ||
| 212 | 18x | break; | ||
| 213 | 209x | case field::content_length: | ||
| 214 | { | |||
| 215 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 205 times.
|
209x | if(flags_ & f_content_length) | |
| 216 | 14x | return error::multiple_content_length; | ||
| 217 | 205x | std::uint64_t n = 0; | ||
| 218 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 197 times.
|
205x | if(!parse_dec(value, n)) | |
| 219 | 8x | return error::bad_content_length; | ||
| 220 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 195 times.
|
197x | if(flags_ & f_transfer_encoding) | |
| 221 | 2x | return error::bad_payload; | ||
| 222 | 195x | flags_ |= f_content_length; | ||
| 223 | 195x | content_length_v_ = n; | ||
| 224 | 195x | break; | ||
| 225 | } | |||
| 226 | 4x | case field::expect: | ||
| 227 |
2/2✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 time.
|
4x | if(token_list_contains(value, "100-continue")) | |
| 228 | 3x | flags_ |= f_exp_100; | ||
| 229 | 4x | break; | ||
| 230 | 143x | case field::transfer_encoding: | ||
| 231 | { | |||
| 232 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 139 times.
|
143x | if(flags_ & f_chunked) | |
| 233 | 20x | return error::bad_transfer_encoding; | ||
| 234 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 135 times.
|
139x | if(!(flags_ & f_http_1_1)) | |
| 235 | 4x | return error::bad_transfer_encoding; | ||
| 236 | 135x | auto const rv = grammar::parse(value, token_list_rule); | ||
| 237 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 133 times.
|
135x | if(!rv) | |
| 238 | 2x | return error::bad_transfer_encoding; | ||
| 239 | 133x | std::size_t n_chunked = 0; | ||
| 240 | 133x | auto is_last = false; | ||
| 241 |
2/2✓ Branch 6 taken 140 times.
✓ Branch 7 taken 133 times.
|
273x | for(auto t : *rv) | |
| 242 | { | |||
| 243 | 140x | is_last = ci_is_equal(t, "chunked"); | ||
| 244 |
2/2✓ Branch 0 taken 128 times.
✓ Branch 1 taken 12 times.
|
140x | if(is_last) | |
| 245 | 128x | ++n_chunked; | ||
| 246 | } | |||
| 247 |
4/4✓ Branch 0 taken 124 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 129 times.
|
133x | if(n_chunked > (is_last ? 1u : 0u)) | |
| 248 | 4x | return error::bad_transfer_encoding; | ||
| 249 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 123 times.
|
129x | if(flags_ & f_content_length) | |
| 250 | 6x | return error::bad_payload; | ||
| 251 | 123x | flags_ |= f_transfer_encoding; | ||
| 252 |
2/2✓ Branch 0 taken 116 times.
✓ Branch 1 taken 7 times.
|
123x | if(is_last) | |
| 253 | 116x | flags_ |= f_chunked; | ||
| 254 | 123x | break; | ||
| 255 | 135x | } | ||
| 256 | 2x | case field::upgrade: | ||
| 257 | 2x | flags_ |= f_upgrade; | ||
| 258 | 2x | break; | ||
| 259 | 17218x | default: | ||
| 260 | 17218x | break; | ||
| 261 | } | |||
| 262 | 17560x | auto& e = ent_(count_++); | ||
| 263 | 17560x | e.of = size_; | ||
| 264 | 17560x | e.id = id; | ||
| 265 | 17560x | e.nn = static_cast<std::uint16_t>(name.size()); | ||
| 266 | 17560x | e.ws = static_cast<std::uint16_t>(value.data() - name.data() - name.size()); | ||
| 267 | 17560x | e.vn = static_cast<std::uint16_t>(value.size()); | ||
| 268 | 17560x | size_ += n; // includes CRLF | ||
| 269 | 17560x | return error::success; | ||
| 270 | } | |||
| 271 | ||||
| 272 | http::error | |||
| 273 | 9079x | message_head_base:: | ||
| 274 | validate_framing_() const noexcept | |||
| 275 | { | |||
| 276 |
2/2✓ Branch 0 taken 8762 times.
✓ Branch 1 taken 317 times.
|
9079x | if( (flags_ & f_req) && | |
| 277 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 8750 times.
|
8762x | (flags_ & f_transfer_encoding) && | |
| 278 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12x | !(flags_ & f_chunked)) | |
| 279 | 6x | return error::bad_transfer_encoding; | ||
| 280 | 9073x | return error::success; | ||
| 281 | } | |||
| 282 | ||||
| 283 | void | |||
| 284 | 289x | message_head_base:: | ||
| 285 | on_special_(field id) noexcept | |||
| 286 | { | |||
| 287 |
5/6✓ Branch 0 taken 23 times.
✓ Branch 1 taken 150 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 101 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
289x | switch(id) | |
| 288 | { | |||
| 289 | 23x | case field::connection: | ||
| 290 | { | |||
| 291 | 23x | std::uint16_t f = 0; | ||
| 292 |
2/2✓ Branch 5 taken 24 times.
✓ Branch 6 taken 23 times.
|
47x | for(auto v : find_all(field::connection)) | |
| 293 | 24x | f |= conn_flags_(v); | ||
| 294 | 23x | flags_ &= ~(f_conn_close | | ||
| 295 | f_conn_keep_alive | f_conn_upgrade); | |||
| 296 | 23x | flags_ |= f; | ||
| 297 | 23x | break; | ||
| 298 | } | |||
| 299 | 150x | case field::content_length: | ||
| 300 | 150x | flags_ &= ~f_content_length; | ||
| 301 | 150x | content_length_v_ = 0; | ||
| 302 |
2/2✓ Branch 5 taken 148 times.
✓ Branch 6 taken 142 times.
|
290x | for(auto v : find_all(field::content_length)) | |
| 303 | { | |||
| 304 |
4/4✓ Branch 0 taken 143 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 140 times.
|
291x | if((flags_ & f_content_length) || | |
| 305 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 140 times.
|
143x | !parse_dec(v, content_length_v_)) | |
| 306 | { | |||
| 307 | 8x | flags_ &= ~f_content_length; | ||
| 308 | 8x | content_length_v_ = 0; | ||
| 309 | 8x | break; | ||
| 310 | } | |||
| 311 | 140x | flags_ |= f_content_length; | ||
| 312 | } | |||
| 313 | 150x | break; | ||
| 314 | 11x | case field::expect: | ||
| 315 | 11x | flags_ &= ~f_exp_100; | ||
| 316 |
2/2✓ Branch 6 taken 9 times.
✓ Branch 7 taken 4 times.
|
13x | for(auto v : find_all(field::expect)) | |
| 317 | { | |||
| 318 |
2/2✓ Branch 2 taken 7 times.
✓ Branch 3 taken 2 times.
|
9x | if(token_list_contains(v, "100-continue")) | |
| 319 | { | |||
| 320 | 7x | flags_ |= f_exp_100; | ||
| 321 | 7x | break; | ||
| 322 | } | |||
| 323 | } | |||
| 324 | 11x | break; | ||
| 325 | 101x | case field::transfer_encoding: | ||
| 326 | { | |||
| 327 | 101x | flags_ &= ~(f_transfer_encoding | f_chunked); | ||
| 328 | 101x | auto const it = find_last(end(), field::transfer_encoding); | ||
| 329 |
2/2✓ Branch 2 taken 20 times.
✓ Branch 3 taken 81 times.
|
101x | if(it == end()) | |
| 330 | 20x | break; | ||
| 331 | 81x | flags_ |= f_transfer_encoding; | ||
| 332 |
2/2✓ Branch 2 taken 70 times.
✓ Branch 3 taken 11 times.
|
81x | if(last_coding_is_chunked((*it).value)) | |
| 333 | 70x | flags_ |= f_chunked; | ||
| 334 | 81x | break; | ||
| 335 | } | |||
| 336 | 4x | case field::upgrade: | ||
| 337 | 4x | flags_ &= ~f_upgrade; | ||
| 338 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 time.
|
4x | if(contains(field::upgrade)) | |
| 339 | 3x | flags_ |= f_upgrade; | ||
| 340 | 4x | break; | ||
| 341 | ✗ | default: | ||
| 342 | ✗ | break; | ||
| 343 | } | |||
| 344 | 289x | } | ||
| 345 | ||||
| 346 | void | |||
| 347 | 3x | message_head_base:: | ||
| 348 | on_clear_() noexcept | |||
| 349 | { | |||
| 350 | // the start line, and the bits derived from | |||
| 351 | // it, are preserved | |||
| 352 | 3x | content_length_v_ = 0; | ||
| 353 | 3x | flags_ &= f_req | f_http_1_1; | ||
| 354 | 3x | } | ||
| 355 | ||||
| 356 | //------------------------------------------------ | |||
| 357 | // | |||
| 358 | // Observers | |||
| 359 | // | |||
| 360 | //------------------------------------------------ | |||
| 361 | ||||
| 362 | payload | |||
| 363 | 941x | message_head_base:: | ||
| 364 | payload() const noexcept | |||
| 365 | { | |||
| 366 |
2/2✓ Branch 0 taken 571 times.
✓ Branch 1 taken 370 times.
|
941x | if(!(flags_ & f_req)) | |
| 367 | { | |||
| 368 | 571x | auto const i = res_.status_int_; | ||
| 369 |
6/8✓ Branch 0 taken 571 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 570 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 566 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 566 times.
|
571x | if((i >= 100 && i <= 199) || i == 204 || i == 304) | |
| 370 | 5x | return payload::none; | ||
| 371 | } | |||
| 372 |
2/2✓ Branch 0 taken 270 times.
✓ Branch 1 taken 666 times.
|
936x | if(flags_ & f_transfer_encoding) | |
| 373 | { | |||
| 374 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 268 times.
|
270x | if(flags_ & f_content_length) | |
| 375 | 2x | return payload::error; | ||
| 376 |
2/2✓ Branch 0 taken 260 times.
✓ Branch 1 taken 8 times.
|
268x | if(flags_ & f_chunked) | |
| 377 | 260x | return payload::chunked; | ||
| 378 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 time.
|
8x | if(flags_ & f_req) | |
| 379 | 7x | return payload::error; | ||
| 380 | 1x | return payload::to_eof; | ||
| 381 | } | |||
| 382 |
2/2✓ Branch 0 taken 407 times.
✓ Branch 1 taken 259 times.
|
666x | if(flags_ & f_content_length) | |
| 383 | { | |||
| 384 |
2/2✓ Branch 0 taken 91 times.
✓ Branch 1 taken 316 times.
|
407x | if(content_length_v_ == 0) | |
| 385 | 91x | return payload::none; | ||
| 386 | 316x | return payload::size; | ||
| 387 | } | |||
| 388 |
2/2✓ Branch 0 taken 102 times.
✓ Branch 1 taken 157 times.
|
259x | if(flags_ & f_req) | |
| 389 | 102x | return payload::none; | ||
| 390 | 157x | return payload::to_eof; | ||
| 391 | } | |||
| 392 | ||||
| 393 | std::optional<std::uint64_t> | |||
| 394 | 289x | message_head_base:: | ||
| 395 | content_length() const noexcept | |||
| 396 | { | |||
| 397 |
2/2✓ Branch 0 taken 229 times.
✓ Branch 1 taken 60 times.
|
289x | if(flags_ & f_content_length) | |
| 398 | 229x | return content_length_v_; | ||
| 399 | 60x | return std::nullopt; | ||
| 400 | } | |||
| 401 | ||||
| 402 | bool | |||
| 403 | 361x | message_head_base:: | ||
| 404 | chunked() const noexcept | |||
| 405 | { | |||
| 406 | 361x | return payload() == payload::chunked; | ||
| 407 | } | |||
| 408 | ||||
| 409 | bool | |||
| 410 | 154x | message_head_base:: | ||
| 411 | keep_alive() const noexcept | |||
| 412 | { | |||
| 413 | 154x | auto const p = payload(); | ||
| 414 |
3/4✓ Branch 0 taken 154 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 152 times.
|
154x | if(p == payload::error || p == payload::to_eof) | |
| 415 | 2x | return false; | ||
| 416 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 140 times.
|
152x | if(!(flags_ & f_http_1_1)) | |
| 417 | 12x | return (flags_ & f_conn_keep_alive) != 0; | ||
| 418 | 140x | return !(flags_ & f_conn_close); | ||
| 419 | } | |||
| 420 | ||||
| 421 | //------------------------------------------------ | |||
| 422 | // | |||
| 423 | // Modifiers | |||
| 424 | // | |||
| 425 | //------------------------------------------------ | |||
| 426 | ||||
| 427 | void | |||
| 428 | 122x | message_head_base:: | ||
| 429 | set_content_length(std::uint64_t n) | |||
| 430 | { | |||
| 431 |
1/1✓ Branch 1 taken 122 times.
|
122x | set_chunked(false); | |
| 432 | char tmp[20]; | |||
| 433 |
1/1✓ Branch 1 taken 122 times.
|
122x | auto const r = std::to_chars(tmp, tmp + sizeof(tmp), n); | |
| 434 |
1/1✓ Branch 1 taken 122 times.
|
122x | set( | |
| 435 | field::content_length, | |||
| 436 | 122x | std::string_view{ tmp, std::size_t(r.ptr - tmp) }); | ||
| 437 | 122x | } | ||
| 438 | ||||
| 439 | void | |||
| 440 | 188x | message_head_base:: | ||
| 441 | set_chunked(bool value) | |||
| 442 | { | |||
| 443 |
2/2✓ Branch 0 taken 61 times.
✓ Branch 1 taken 127 times.
|
188x | if(value) | |
| 444 | { | |||
| 445 | 61x | erase(field::content_length); | ||
| 446 | 61x | auto const it = find_last(end(), field::transfer_encoding); | ||
| 447 |
6/6✓ Branch 2 taken 2 times.
✓ Branch 3 taken 59 times.
✓ Branch 6 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 60 times.
|
61x | if(it != end() && last_coding_is_chunked((*it).value)) | |
| 448 | 1x | return; | ||
| 449 |
1/1✓ Branch 2 taken 60 times.
|
60x | append(field::transfer_encoding, "chunked"); | |
| 450 | 60x | return; | ||
| 451 | } | |||
| 452 | 127x | auto const it = find_last(end(), field::transfer_encoding); | ||
| 453 |
2/2✓ Branch 2 taken 123 times.
✓ Branch 3 taken 4 times.
|
127x | if(it == end()) | |
| 454 | 123x | return; | ||
| 455 | 4x | auto const v = (*it).value; | ||
| 456 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 2 taken 3 times.
|
4x | if(!last_coding_is_chunked(v)) | |
| 457 | 1x | return; | ||
| 458 | 3x | auto const comma = v.rfind(','); | ||
| 459 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
|
3x | if(comma == std::string_view::npos) | |
| 460 | { | |||
| 461 | 1x | erase(it); | ||
| 462 | 1x | return; | ||
| 463 | } | |||
| 464 |
1/1✓ Branch 1 taken 2 times.
|
2x | std::string_view head = v.substr(0, comma); | |
| 465 |
5/6✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 2 times.
|
4x | while(!head.empty() && is_ws(head.back())) | |
| 466 | 2x | head.remove_suffix(1); | ||
| 467 |
1/1✓ Branch 1 taken 2 times.
|
2x | set(it, head); | |
| 468 | } | |||
| 469 | ||||
| 470 | void | |||
| 471 | 11x | message_head_base:: | ||
| 472 | set_keep_alive(bool value) | |||
| 473 | { | |||
| 474 | // TODO: Use static buffer | |||
| 475 | 11x | std::string list; | ||
| 476 |
2/2✓ Branch 6 taken 7 times.
✓ Branch 7 taken 11 times.
|
18x | for(auto v : find_all(field::connection)) | |
| 477 | { | |||
| 478 |
1/1✓ Branch 2 taken 7 times.
|
7x | auto const rv = grammar::parse(v, token_list_rule); | |
| 479 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 time.
|
7x | if(rv) | |
| 480 | { | |||
| 481 |
3/3✓ Branch 1 taken 6 times.
✓ Branch 8 taken 8 times.
✓ Branch 9 taken 6 times.
|
14x | for(auto t : *rv) | |
| 482 | { | |||
| 483 |
2/2✓ Branch 2 taken 2 times.
✓ Branch 3 taken 6 times.
|
8x | if(ci_is_equal(t, "close")) | |
| 484 | 2x | continue; | ||
| 485 |
2/2✓ Branch 2 taken 2 times.
✓ Branch 3 taken 4 times.
|
6x | if(ci_is_equal(t, "keep-alive")) | |
| 486 | 2x | continue; | ||
| 487 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 2 taken 3 times.
|
4x | if(!list.empty()) | |
| 488 |
1/1✓ Branch 1 taken 1 time.
|
1x | list += ", "; | |
| 489 |
1/1✓ Branch 1 taken 4 times.
|
4x | list += t; | |
| 490 | } | |||
| 491 | } | |||
| 492 | 7x | } | ||
| 493 | 11x | std::string_view add; | ||
| 494 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
|
11x | if(flags_ & f_http_1_1) | |
| 495 | { | |||
| 496 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
|
8x | if(!value) | |
| 497 | 6x | add = "close"; | ||
| 498 | } | |||
| 499 | else | |||
| 500 | { | |||
| 501 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
|
3x | if(value) | |
| 502 | 2x | add = "keep-alive"; | ||
| 503 | } | |||
| 504 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 3 times.
|
11x | if(!add.empty()) | |
| 505 | { | |||
| 506 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 6 times.
|
8x | if(!list.empty()) | |
| 507 |
1/1✓ Branch 1 taken 2 times.
|
2x | list += ", "; | |
| 508 |
1/1✓ Branch 1 taken 8 times.
|
8x | list += add; | |
| 509 | } | |||
| 510 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 9 times.
|
11x | if(list.empty()) | |
| 511 | 2x | erase(field::connection); | ||
| 512 | else | |||
| 513 |
1/1✓ Branch 2 taken 9 times.
|
9x | set(field::connection, list); | |
| 514 | 11x | } | ||
| 515 | ||||
| 516 | std::ostream& | |||
| 517 | 3x | operator<<( | ||
| 518 | std::ostream& os, | |||
| 519 | message_head_base const& h) | |||
| 520 | { | |||
| 521 | // in-place parsing leaves the start line | |||
| 522 | // empty until it has been parsed | |||
| 523 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
|
3x | if(h.prefix_ >= 2) | |
| 524 | os << std::string_view{ | |||
| 525 | 2x | h.base_(), | ||
| 526 |
2/2✓ Branch 2 taken 2 times.
✓ Branch 5 taken 2 times.
|
2x | std::size_t(h.prefix_) - 2 } << '\n'; | |
| 527 | 3x | return os << static_cast<fields_base const&>(h); | ||
| 528 | } | |||
| 529 | ||||
| 530 | } // namespace burl | |||
| 531 | } // namespace boost | |||
| 532 |