src/message_head_base.cpp

99.3% Lines (285/287) 100.0% List of functions (22/22) 96.1% Branches (197/205)
message_head_base.cpp
f(x) 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