src/message_head_base.cpp

99.3% Lines (285/287) 100.0% List of functions (22/22) 96.6% Branches (198/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 374x 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 166x 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 41748x 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 26944x 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 26422x 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 331x 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 17610x 100.0% 100.0% 100.0% boost::burl::message_head_base::validate_framing_() const :273 9088x 100.0% 100.0% 100.0% boost::burl::message_head_base::on_special_(boost::http::field) :284 369x 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 934x 100.0% 95.8% 100.0% boost::burl::message_head_base::content_length() const :394 271x 100.0% 100.0% 100.0% boost::burl::message_head_base::chunked() const :403 151x 100.0% – 100.0% boost::burl::message_head_base::keep_alive() const :410 156x 100.0% 83.3% 100.0% boost::burl::message_head_base::set_content_length(unsigned long) :428 141x 100.0% 100.0% 86.0% boost::burl::message_head_base::set_chunked(bool) :440 262x 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 374x 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 371 times.
374x if(s.empty())
46 3x return false;
47 371x n = 0;
48
2/2
✓ Branch 2 taken 594 times.
✓ Branch 3 taken 363 times.
957x for(char const c : s)
49 {
50
4/4
✓ Branch 0 taken 592 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 589 times.
594x if(c < '0' || c > '9')
51 5x return false;
52 589x auto const d = static_cast<std::uint64_t>(c - '0');
53
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 586 times.
589x if(n > ((std::numeric_limits<std::uint64_t>::max)() - d) / 10)
54 3x return false;
55 586x n = n * 10 + d;
56 }
57 363x 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 166x last_coding_is_chunked(
80 std::string_view value) noexcept
81 {
82 166x auto const rv = grammar::parse(value, token_list_rule);
83 166x auto chunked = false;
84
2/2
✓ Branch 1 taken 165 times.
✓ Branch 2 taken 1 time.
166x if(rv)
85 {
86
2/2
✓ Branch 5 taken 170 times.
✓ Branch 6 taken 165 times.
335x for(auto t : *rv)
87 170x chunked = ci_is_equal(t, "chunked");
88 }
89 332x return chunked;
90 166x }
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 41748x 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 41748x std::uint16_t prefix) noexcept
128 41748x : fields_base(base, cap, size, 0, prefix)
129 {
130
3/4
✓ Branch 0 taken 40931 times.
✓ Branch 1 taken 817 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 40931 times.
41748x BOOST_ASSERT(
131 cap == 0 ||
132 (reinterpret_cast<std::uintptr_t>(base) + cap) %
133 alignof(entry) == 0);
134
2/2
✓ Branch 0 taken 40852 times.
✓ Branch 1 taken 896 times.
41748x if(is_request)
135 {
136 40852x flags_ |= f_req;
137 40852x req_ = req_t{};
138 }
139 else
140 896x res_ = res_t{};
141 41748x }
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 26944x message_head_base::
158 set_version_(http::version v) noexcept
159 {
160
2/2
✓ Branch 0 taken 26915 times.
✓ Branch 1 taken 29 times.
26944x if(v == http::version::http_1_1)
161 26915x flags_ |= f_http_1_1;
162 else
163 29x flags_ &= ~f_http_1_1;
164 26944x }
165
166 void
167 26422x 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 26422 times.
26422x BOOST_ASSERT(flags_ & f_req);
175 26422x req_.method_len_ = static_cast<std::uint16_t>(method.size());
176 26422x req_.target_len_ = static_cast<std::uint16_t>(target.size());
177 26422x req_.method_ = http::string_to_method(method);
178 26422x set_version_(v);
179 26422x prefix_ = n;
180 26422x buf_ += n;
181 26422x }
182
183 void
184 331x 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 331 times.
331x BOOST_ASSERT(!(flags_ & f_req));
192 331x res_.status_int_ = status_int;
193 331x res_.status_ = http::int_to_status(status_int);
194 331x set_version_(v);
195 331x prefix_ = n;
196 331x buf_ += n;
197 331x }
198
199 http::error
200 17610x message_head_base::
201 push_field_(
202 std::string_view name,
203 std::string_view value,
204 std::uint16_t n) noexcept
205 {
206 17610x auto const id = resolve_(name);
207
208
6/6
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 216 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 145 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 17225 times.
17610x switch(static_cast<field>(id))
209 {
210 18x case field::connection:
211 18x flags_ |= conn_flags_(value);
212 18x break;
213 216x case field::content_length:
214 {
215
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 212 times.
216x if(flags_ & f_content_length)
216 14x return error::multiple_content_length;
217 212x std::uint64_t n = 0;
218
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 204 times.
212x if(!parse_dec(value, n))
219 8x return error::bad_content_length;
220
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 202 times.
204x if(flags_ & f_transfer_encoding)
221 2x return error::bad_payload;
222 202x flags_ |= f_content_length;
223 202x content_length_v_ = n;
224 202x 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 145x case field::transfer_encoding:
231 {
232
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 141 times.
145x if(flags_ & f_chunked)
233 20x return error::bad_transfer_encoding;
234
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 137 times.
141x if(!(flags_ & f_http_1_1))
235 4x return error::bad_transfer_encoding;
236 137x auto const rv = grammar::parse(value, token_list_rule);
237
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 135 times.
137x if(!rv)
238 2x return error::bad_transfer_encoding;
239 135x std::size_t n_chunked = 0;
240 135x auto is_last = false;
241
2/2
✓ Branch 6 taken 142 times.
✓ Branch 7 taken 135 times.
277x for(auto t : *rv)
242 {
243 142x is_last = ci_is_equal(t, "chunked");
244
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 12 times.
142x if(is_last)
245 130x ++n_chunked;
246 }
247
4/4
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 131 times.
135x 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 125 times.
131x if(flags_ & f_content_length)
250 6x return error::bad_payload;
251 125x flags_ |= f_transfer_encoding;
252
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 7 times.
125x if(is_last)
253 118x flags_ |= f_chunked;
254 125x break;
255 137x }
256 2x case field::upgrade:
257 2x flags_ |= f_upgrade;
258 2x break;
259 17225x default:
260 17225x break;
261 }
262 17576x auto& e = ent_(count_++);
263 17576x e.of = size_;
264 17576x e.id = id;
265 17576x e.nn = static_cast<std::uint16_t>(name.size());
266 17576x e.ws = static_cast<std::uint16_t>(value.data() - name.data() - name.size());
267 17576x e.vn = static_cast<std::uint16_t>(value.size());
268 17576x size_ += n; // includes CRLF
269 17576x return error::success;
270 }
271
272 http::error
273 9088x message_head_base::
274 validate_framing_() const noexcept
275 {
276
2/2
✓ Branch 0 taken 8765 times.
✓ Branch 1 taken 323 times.
9088x if( (flags_ & f_req) &&
277
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 8752 times.
8765x (flags_ & f_transfer_encoding) &&
278
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 7 times.
13x !(flags_ & f_chunked))
279 6x return error::bad_transfer_encoding;
280 9082x return error::success;
281 }
282
283 void
284 369x message_head_base::
285 on_special_(field id) noexcept
286 {
287
5/6
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 169 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 162 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
369x 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 169x case field::content_length:
300 169x flags_ &= ~f_content_length;
301 169x content_length_v_ = 0;
302
2/2
✓ Branch 5 taken 167 times.
✓ Branch 6 taken 161 times.
328x for(auto v : find_all(field::content_length))
303 {
304
4/4
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 159 times.
329x if((flags_ & f_content_length) ||
305
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 159 times.
162x !parse_dec(v, content_length_v_))
306 {
307 8x flags_ &= ~f_content_length;
308 8x content_length_v_ = 0;
309 8x break;
310 }
311 159x flags_ |= f_content_length;
312 }
313 169x 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 162x case field::transfer_encoding:
326 {
327 162x flags_ &= ~(f_transfer_encoding | f_chunked);
328 162x auto const it = find_last(end(), field::transfer_encoding);
329
2/2
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 137 times.
162x if(it == end())
330 25x break;
331 137x flags_ |= f_transfer_encoding;
332
2/2
✓ Branch 2 taken 125 times.
✓ Branch 3 taken 12 times.
137x if(last_coding_is_chunked((*it).value))
333 125x flags_ |= f_chunked;
334 137x 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 369x }
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 934x message_head_base::
364 payload() const noexcept
365 {
366
2/2
✓ Branch 0 taken 609 times.
✓ Branch 1 taken 325 times.
934x if(!(flags_ & f_req))
367 {
368 609x auto const i = res_.status_int_;
369
7/8
✓ Branch 0 taken 609 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 608 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 604 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 602 times.
609x if((i >= 100 && i <= 199) || i == 204 || i == 304)
370 7x return payload::none;
371 }
372
2/2
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 638 times.
927x if(flags_ & f_transfer_encoding)
373 {
374
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 287 times.
289x if(flags_ & f_content_length)
375 2x return payload::error;
376
2/2
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 9 times.
287x if(flags_ & f_chunked)
377 278x return payload::chunked;
378
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9x if(flags_ & f_req)
379 7x return payload::error;
380 2x return payload::to_eof;
381 }
382
2/2
✓ Branch 0 taken 386 times.
✓ Branch 1 taken 252 times.
638x if(flags_ & f_content_length)
383 {
384
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 297 times.
386x if(content_length_v_ == 0)
385 89x return payload::none;
386 297x return payload::size;
387 }
388
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 180 times.
252x if(flags_ & f_req)
389 72x return payload::none;
390 180x return payload::to_eof;
391 }
392
393 std::optional<std::uint64_t>
394 271x message_head_base::
395 content_length() const noexcept
396 {
397
2/2
✓ Branch 0 taken 233 times.
✓ Branch 1 taken 38 times.
271x if(flags_ & f_content_length)
398 233x return content_length_v_;
399 38x return std::nullopt;
400 }
401
402 bool
403 151x message_head_base::
404 chunked() const noexcept
405 {
406 151x return payload() == payload::chunked;
407 }
408
409 bool
410 156x message_head_base::
411 keep_alive() const noexcept
412 {
413 156x auto const p = payload();
414
3/4
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 154 times.
156x if(p == payload::error || p == payload::to_eof)
415 2x return false;
416
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 142 times.
154x if(!(flags_ & f_http_1_1))
417 12x return (flags_ & f_conn_keep_alive) != 0;
418 142x return !(flags_ & f_conn_close);
419 }
420
421 //------------------------------------------------
422 //
423 // Modifiers
424 //
425 //------------------------------------------------
426
427 void
428 141x message_head_base::
429 set_content_length(std::uint64_t n)
430 {
431
1/1
✓ Branch 1 taken 141 times.
141x set_chunked(false);
432 char tmp[20];
433
1/1
✓ Branch 1 taken 141 times.
141x auto const r = std::to_chars(tmp, tmp + sizeof(tmp), n);
434
1/1
✓ Branch 1 taken 141 times.
141x set(
435 field::content_length,
436 141x std::string_view{ tmp, std::size_t(r.ptr - tmp) });
437 141x }
438
439 void
440 262x message_head_base::
441 set_chunked(bool value)
442 {
443
2/2
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 146 times.
262x if(value)
444 {
445 116x erase(field::content_length);
446 116x auto const it = find_last(end(), field::transfer_encoding);
447
6/6
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 114 times.
✓ Branch 6 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 115 times.
116x if(it != end() && last_coding_is_chunked((*it).value))
448 1x return;
449
1/1
✓ Branch 2 taken 115 times.
115x append(field::transfer_encoding, "chunked");
450 115x return;
451 }
452 146x auto const it = find_last(end(), field::transfer_encoding);
453
2/2
✓ Branch 2 taken 119 times.
✓ Branch 3 taken 27 times.
146x if(it == end())
454 119x return;
455 27x auto const v = (*it).value;
456
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 26 times.
27x if(!last_coding_is_chunked(v))
457 1x return;
458 26x auto const comma = v.rfind(',');
459
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2 times.
26x if(comma == std::string_view::npos)
460 {
461 24x erase(it);
462 24x 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