Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com) | ||
3 | // Copyright (c) 2025 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/http_proto | ||
9 | // | ||
10 | |||
11 | #include <boost/http_proto/detail/config.hpp> | ||
12 | #include <boost/http_proto/detail/except.hpp> | ||
13 | #include <boost/http_proto/detail/header.hpp> | ||
14 | #include <boost/http_proto/error.hpp> | ||
15 | #include <boost/http_proto/field.hpp> | ||
16 | #include <boost/http_proto/fields_base.hpp> | ||
17 | #include <boost/http_proto/header_limits.hpp> | ||
18 | #include <boost/http_proto/rfc/token_rule.hpp> | ||
19 | |||
20 | #include "src/detail/move_chars.hpp" | ||
21 | #include "src/rfc/detail/rules.hpp" | ||
22 | |||
23 | #include <boost/assert.hpp> | ||
24 | #include <boost/assert/source_location.hpp> | ||
25 | #include <boost/core/detail/string_view.hpp> | ||
26 | #include <boost/system/result.hpp> | ||
27 | #include <boost/url/grammar/ci_string.hpp> | ||
28 | #include <boost/url/grammar/error.hpp> | ||
29 | #include <boost/url/grammar/parse.hpp> | ||
30 | #include <boost/url/grammar/token_rule.hpp> | ||
31 | |||
32 | namespace boost { | ||
33 | namespace http_proto { | ||
34 | |||
35 | namespace { | ||
36 | |||
37 | std::size_t | ||
38 | 96 | align_down( | |
39 | void * ptr, | ||
40 | std::size_t size, | ||
41 | std::size_t alignment) | ||
42 | { | ||
43 | 96 | auto addr = reinterpret_cast<std::uintptr_t>(ptr); | |
44 | 96 | auto aligned_end = (addr + size) & ~(alignment - 1); | |
45 | |||
46 |
1/2✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
|
96 | if(aligned_end > addr) |
47 | 96 | return aligned_end - addr; | |
48 | |||
49 | ✗ | return 0; | |
50 | } | ||
51 | |||
52 | void | ||
53 | 250 | verify_field_name( | |
54 | core::string_view name, | ||
55 | system::error_code& ec) | ||
56 | { | ||
57 | 250 | auto rv = grammar::parse( | |
58 | name, detail::field_name_rule); | ||
59 |
2/2✓ Branch 1 taken 9 times.
✓ Branch 2 taken 241 times.
|
250 | if(rv.has_error()) |
60 | { | ||
61 | 18 | ec = BOOST_HTTP_PROTO_ERR( | |
62 | error::bad_field_name); | ||
63 | } | ||
64 | 250 | } | |
65 | |||
66 | system::result<detail::field_value_rule_t::value_type> | ||
67 | 382 | verify_field_value( | |
68 | core::string_view value) | ||
69 | { | ||
70 | 382 | auto it = value.begin(); | |
71 | 382 | auto end = value.end(); | |
72 | auto rv = | ||
73 | 382 | grammar::parse(it, end, detail::field_value_rule); | |
74 |
2/2✓ Branch 1 taken 7 times.
✓ Branch 2 taken 375 times.
|
382 | if( rv.has_error() ) |
75 | { | ||
76 |
1/2✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
|
7 | if( rv.error() == condition::need_more_input ) |
77 | 7 | return error::bad_field_value; | |
78 | ✗ | return rv.error(); | |
79 | } | ||
80 | |||
81 |
2/2✓ Branch 1 taken 16 times.
✓ Branch 2 taken 359 times.
|
375 | if( rv->has_crlf ) |
82 | 16 | return error::bad_field_smuggle; | |
83 | |||
84 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 352 times.
|
359 | if( it != end ) |
85 | 7 | return error::bad_field_value; | |
86 | |||
87 | 352 | return rv; | |
88 | } | ||
89 | |||
90 | } // namespace | ||
91 | |||
92 | class fields_base:: | ||
93 | op_t | ||
94 | { | ||
95 | fields_base& self_; | ||
96 | core::string_view* s0_; | ||
97 | core::string_view* s1_; | ||
98 | char* buf_ = nullptr; | ||
99 | char const* cbuf_ = nullptr; | ||
100 | std::size_t cap_ = 0; | ||
101 | |||
102 | public: | ||
103 | explicit | ||
104 | 1035 | op_t( | |
105 | fields_base& self, | ||
106 | core::string_view* s0 = nullptr, | ||
107 | core::string_view* s1 = nullptr) noexcept | ||
108 | 1035 | : self_(self) | |
109 | 1035 | , s0_(s0) | |
110 | 1035 | , s1_(s1) | |
111 | { | ||
112 | 1035 | } | |
113 | |||
114 | 1035 | ~op_t() | |
115 | { | ||
116 |
2/2✓ Branch 0 taken 162 times.
✓ Branch 1 taken 873 times.
|
1035 | if(buf_) |
117 |
1/2✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
|
162 | delete[] buf_; |
118 | 1035 | } | |
119 | |||
120 | char const* | ||
121 | 12 | buf() const noexcept | |
122 | { | ||
123 | 12 | return buf_; | |
124 | } | ||
125 | |||
126 | char const* | ||
127 | 449 | cbuf() const noexcept | |
128 | { | ||
129 | 449 | return cbuf_; | |
130 | } | ||
131 | |||
132 | char* | ||
133 | 12 | end() const noexcept | |
134 | { | ||
135 | 12 | return buf_ + cap_; | |
136 | } | ||
137 | |||
138 | table | ||
139 | 6 | tab() const noexcept | |
140 | { | ||
141 | 6 | return table(end()); | |
142 | } | ||
143 | |||
144 | bool | ||
145 | reserve(std::size_t n); | ||
146 | |||
147 | bool | ||
148 | grow( | ||
149 | std::size_t extra_char, | ||
150 | std::size_t extra_field); | ||
151 | |||
152 | void | ||
153 | move_chars( | ||
154 | char* dest, | ||
155 | char const* src, | ||
156 | std::size_t n) const noexcept; | ||
157 | }; | ||
158 | |||
159 | bool | ||
160 | 1011 | fields_base:: | |
161 | op_t:: | ||
162 | reserve( | ||
163 | std::size_t n) | ||
164 | { | ||
165 | // TODO: consider using a growth factor | ||
166 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 992 times.
|
1011 | if(n > self_.max_cap_) |
167 | { | ||
168 | // max capacity exceeded | ||
169 | 19 | detail::throw_length_error(); | |
170 | } | ||
171 |
2/2✓ Branch 0 taken 150 times.
✓ Branch 1 taken 842 times.
|
992 | if(n <= self_.h_.cap) |
172 | 150 | return false; | |
173 | 842 | auto buf = new char[n]; | |
174 | 842 | buf_ = self_.h_.buf; | |
175 | 842 | cbuf_ = self_.h_.cbuf; | |
176 | 842 | cap_ = self_.h_.cap; | |
177 | 842 | self_.h_.buf = buf; | |
178 | 842 | self_.h_.cbuf = buf; | |
179 | 842 | self_.h_.cap = n; | |
180 | 842 | return true; | |
181 | } | ||
182 | |||
183 | bool | ||
184 | 914 | fields_base:: | |
185 | op_t:: | ||
186 | grow( | ||
187 | std::size_t extra_char, | ||
188 | std::size_t extra_field) | ||
189 | { | ||
190 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 914 times.
|
914 | if(extra_field > detail::header::max_offset - self_.h_.count) |
191 | ✗ | detail::throw_length_error(); | |
192 | |||
193 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 912 times.
|
914 | if(extra_char > detail::header::max_offset - self_.h_.size) |
194 | 2 | detail::throw_length_error(); | |
195 | |||
196 | 912 | return reserve( | |
197 | detail::header::bytes_needed( | ||
198 | 912 | self_.h_.size + extra_char, | |
199 | 1818 | self_.h_.count + extra_field)); | |
200 | } | ||
201 | |||
202 | void | ||
203 | 121 | fields_base:: | |
204 | op_t:: | ||
205 | move_chars( | ||
206 | char* dest, | ||
207 | char const* src, | ||
208 | std::size_t n) const noexcept | ||
209 | { | ||
210 | 121 | detail::move_chars( | |
211 | 121 | dest, src, n, s0_, s1_); | |
212 | 121 | } | |
213 | |||
214 | //------------------------------------------------ | ||
215 | |||
216 | 73 | fields_base:: | |
217 | prefix_op_t:: | ||
218 | prefix_op_t( | ||
219 | fields_base& self, | ||
220 | std::size_t new_prefix, | ||
221 | core::string_view* s0, | ||
222 | 73 | core::string_view* s1) | |
223 | 73 | : self_(self) | |
224 | 73 | , new_prefix_(static_cast< | |
225 | 73 | offset_type>(new_prefix)) | |
226 | { | ||
227 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 71 times.
|
73 | if(self.h_.size - self.h_.prefix + new_prefix |
228 | > detail::header::max_offset) | ||
229 | 2 | detail::throw_length_error(); | |
230 | |||
231 | // memmove happens in the destructor | ||
232 | // to avoid overlaping with start line. | ||
233 | 142 | if(new_prefix_ < self_.h_.prefix | |
234 |
5/6✓ Branch 0 taken 10 times.
✓ Branch 1 taken 61 times.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 61 times.
|
71 | && !self.h_.is_default()) |
235 | 10 | return; | |
236 | |||
237 | 61 | auto new_size = static_cast<offset_type>( | |
238 | 61 | self.h_.size - self.h_.prefix + new_prefix_); | |
239 | |||
240 | auto bytes_needed = | ||
241 | 61 | detail::header::bytes_needed( | |
242 | new_size, | ||
243 | 61 | self.h_.count); | |
244 | |||
245 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 33 times.
|
61 | if(bytes_needed > self.h_.cap) |
246 | { | ||
247 | // static storage will always throw which is | ||
248 | // intended since they cannot reallocate. | ||
249 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 27 times.
|
28 | if(self.max_cap_ < bytes_needed) |
250 | 1 | detail::throw_length_error(); | |
251 | // TODO: consider using a growth factor | ||
252 | 27 | char* p = new char[bytes_needed]; | |
253 | 27 | std::memcpy( | |
254 | 27 | p + new_prefix_, | |
255 | 27 | self.h_.cbuf + self.h_.prefix, | |
256 | 27 | self.h_.size - self.h_.prefix); | |
257 | 27 | self.h_.copy_table(p + bytes_needed); | |
258 | |||
259 | // old buffer gets released in the destructor | ||
260 | // to avoid invalidating any string_views | ||
261 | // that may still reference it. | ||
262 | 27 | buf_ = self.h_.buf; | |
263 | 27 | self.h_.buf = p; | |
264 | 27 | self.h_.cap = bytes_needed; | |
265 | } | ||
266 | else | ||
267 | { | ||
268 | // memmove to the right and update any | ||
269 | // string_views that reference that region. | ||
270 | 33 | detail::move_chars( | |
271 | 33 | self.h_.buf + new_prefix_, | |
272 | 33 | self.h_.cbuf + self.h_.prefix, | |
273 | 33 | self.h_.size - self.h_.prefix, | |
274 | s0, | ||
275 | s1); | ||
276 | } | ||
277 | |||
278 | 60 | self.h_.cbuf = self.h_.buf; | |
279 | 60 | self.h_.size = new_size; | |
280 | 60 | self.h_.prefix = new_prefix_; | |
281 | } | ||
282 | |||
283 | 70 | fields_base:: | |
284 | prefix_op_t:: | ||
285 | ~prefix_op_t() | ||
286 | { | ||
287 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 60 times.
|
70 | if(new_prefix_ < self_.h_.prefix) |
288 | { | ||
289 | 10 | std::memmove( | |
290 | 10 | self_.h_.buf + new_prefix_, | |
291 | 10 | self_.h_.cbuf + self_.h_.prefix, | |
292 | 10 | self_.h_.size - self_.h_.prefix); | |
293 | |||
294 | 10 | self_.h_.size = | |
295 | 10 | self_.h_.size - self_.h_.prefix + new_prefix_; | |
296 | 10 | self_.h_.prefix = new_prefix_; | |
297 | } | ||
298 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 55 times.
|
60 | else if(buf_) |
299 | { | ||
300 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | delete[] buf_; |
301 | } | ||
302 | 70 | } | |
303 | |||
304 | //------------------------------------------------ | ||
305 | |||
306 | 386 | fields_base:: | |
307 | fields_base( | ||
308 | ✗ | detail::kind k) noexcept | |
309 | ✗ | : fields_view_base(&h_) | |
310 | 386 | , h_(k) | |
311 | { | ||
312 | 386 | } | |
313 | |||
314 | 98 | fields_base:: | |
315 | fields_base( | ||
316 | detail::kind k, | ||
317 | char* storage, | ||
318 | ✗ | std::size_t cap) noexcept | |
319 | : fields_base( | ||
320 | 98 | *detail::header::get_default(k), storage, cap) | |
321 | { | ||
322 | 98 | } | |
323 | |||
324 | // copy s and parse it | ||
325 | 1138 | fields_base:: | |
326 | fields_base( | ||
327 | detail::kind k, | ||
328 | ✗ | core::string_view s) | |
329 | ✗ | : fields_view_base(&h_) | |
330 | 1138 | , h_(detail::empty{k}) | |
331 | { | ||
332 | 1138 | auto n = detail::header::count_crlf(s); | |
333 |
2/2✓ Branch 0 taken 265 times.
✓ Branch 1 taken 304 times.
|
1138 | if(h_.kind == detail::kind::fields) |
334 | { | ||
335 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 264 times.
|
530 | if(n < 1) |
336 | 2 | detail::throw_invalid_argument(); | |
337 | 528 | n -= 1; | |
338 | } | ||
339 | else | ||
340 | { | ||
341 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 302 times.
|
608 | if(n < 2) |
342 | 4 | detail::throw_invalid_argument(); | |
343 | 604 | n -= 2; | |
344 | } | ||
345 | 1132 | op_t op(*this); | |
346 |
1/2✓ Branch 2 taken 566 times.
✗ Branch 3 not taken.
|
1132 | op.grow(s.size(), n); |
347 |
1/2✓ Branch 2 taken 566 times.
✗ Branch 3 not taken.
|
1132 | s.copy(h_.buf, s.size()); |
348 | 1132 | system::error_code ec; | |
349 | // VFALCO This is using defaults? | ||
350 | 1132 | header_limits lim; | |
351 | 1132 | h_.parse(s.size(), lim, ec); | |
352 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 566 times.
|
1132 | if(ec.failed()) |
353 | ✗ | detail::throw_system_error(ec); | |
354 | 1132 | } | |
355 | |||
356 | // copy s and parse it | ||
357 | 74 | fields_base:: | |
358 | fields_base( | ||
359 | detail::kind k, | ||
360 | char* storage, | ||
361 | std::size_t cap, | ||
362 | ✗ | core::string_view s) | |
363 | ✗ | : fields_view_base(&h_) | |
364 | 74 | , h_(detail::empty{k}) | |
365 | 74 | , external_storage_(true) | |
366 | { | ||
367 | 74 | h_.cbuf = storage; | |
368 | 74 | h_.buf = storage; | |
369 | 74 | h_.cap = align_down( | |
370 | storage, | ||
371 | cap, | ||
372 | alignof(detail::header::entry)); | ||
373 | 74 | max_cap_ = h_.cap; | |
374 | |||
375 | 74 | auto n = detail::header::count_crlf(s); | |
376 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 25 times.
|
74 | if(h_.kind == detail::kind::fields) |
377 | { | ||
378 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
24 | if(n < 1) |
379 | ✗ | detail::throw_invalid_argument(); | |
380 | 24 | n -= 1; | |
381 | } | ||
382 | else | ||
383 | { | ||
384 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
|
50 | if(n < 2) |
385 | ✗ | detail::throw_invalid_argument(); | |
386 | 50 | n -= 2; | |
387 | } | ||
388 | |||
389 | 74 | if(detail::header::bytes_needed( | |
390 | s.size(), n) | ||
391 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
74 | >= h_.cap) |
392 | ✗ | detail::throw_length_error(); | |
393 | |||
394 |
1/2✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
|
74 | s.copy(h_.buf, s.size()); |
395 | 74 | system::error_code ec; | |
396 | // VFALCO This is using defaults? | ||
397 | 74 | header_limits lim; | |
398 | 74 | h_.parse(s.size(), lim, ec); | |
399 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
|
74 | if(ec.failed()) |
400 | ✗ | detail::throw_system_error(ec); | |
401 | 74 | } | |
402 | |||
403 | // construct a complete copy of h | ||
404 | 52 | fields_base:: | |
405 | fields_base( | ||
406 | 28 | detail::header const& h) | |
407 | 28 | : fields_view_base(&h_) | |
408 | 52 | , h_(h.kind) | |
409 | { | ||
410 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 18 times.
|
52 | if(h.is_default()) |
411 | 16 | return; | |
412 | |||
413 | // allocate and copy the buffer | ||
414 | 36 | op_t op(*this); | |
415 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
36 | op.grow(h.size, h.count); |
416 | 36 | h.assign_to(h_); | |
417 | 36 | std::memcpy( | |
418 | 36 | h_.buf, h.cbuf, h.size); | |
419 | 36 | h.copy_table(h_.buf + h_.cap); | |
420 | 36 | } | |
421 | |||
422 | // construct a complete copy of h | ||
423 | 118 | fields_base:: | |
424 | fields_base( | ||
425 | detail::header const& h, | ||
426 | char* storage, | ||
427 | ✗ | std::size_t cap) | |
428 | ✗ | : fields_view_base(&h_) | |
429 | 118 | , h_(h.kind) | |
430 | 118 | , external_storage_(true) | |
431 | { | ||
432 | 118 | h_.cbuf = storage; | |
433 | 118 | h_.buf = storage; | |
434 | 118 | h_.cap = align_down( | |
435 | storage, | ||
436 | cap, | ||
437 | alignof(detail::header::entry)); | ||
438 | 118 | max_cap_ = h_.cap; | |
439 | |||
440 | 236 | if(detail::header::bytes_needed( | |
441 | 118 | h.size, h.count) | |
442 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 59 times.
|
118 | >= h_.cap) |
443 | ✗ | detail::throw_length_error(); | |
444 | |||
445 | 118 | h.assign_to(h_); | |
446 | 118 | std::memcpy( | |
447 | 118 | h_.buf, h.cbuf, h.size); | |
448 | 118 | h.copy_table(h_.buf + h_.cap); | |
449 | 118 | } | |
450 | |||
451 | //------------------------------------------------ | ||
452 | |||
453 | 1762 | fields_base:: | |
454 | 1762 | ~fields_base() | |
455 | { | ||
456 |
4/4✓ Branch 0 taken 798 times.
✓ Branch 1 taken 83 times.
✓ Branch 2 taken 702 times.
✓ Branch 3 taken 96 times.
|
1762 | if(h_.buf && !external_storage_) |
457 |
1/2✓ Branch 0 taken 702 times.
✗ Branch 1 not taken.
|
1404 | delete[] h_.buf; |
458 | 1762 | } | |
459 | |||
460 | //------------------------------------------------ | ||
461 | // | ||
462 | // Capacity | ||
463 | // | ||
464 | //------------------------------------------------ | ||
465 | |||
466 | void | ||
467 | 14 | fields_base:: | |
468 | clear() noexcept | ||
469 | { | ||
470 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 9 times.
|
14 | if(! h_.buf) |
471 | 5 | return; | |
472 | using H = | ||
473 | detail::header; | ||
474 | auto const& h = | ||
475 | 9 | *H::get_default( | |
476 | 9 | h_.kind); | |
477 | 9 | h.assign_to(h_); | |
478 | 9 | std::memcpy( | |
479 | 9 | h_.buf, | |
480 | 9 | h.cbuf, | |
481 | 9 | h_.size); | |
482 | } | ||
483 | |||
484 | void | ||
485 | 99 | fields_base:: | |
486 | reserve_bytes( | ||
487 | std::size_t n) | ||
488 | { | ||
489 | 99 | op_t op(*this); | |
490 |
4/4✓ Branch 1 taken 86 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 51 times.
✓ Branch 4 taken 35 times.
|
99 | if(! op.reserve(n)) |
491 | 51 | return; | |
492 | 70 | std::memcpy( | |
493 | 35 | h_.buf, op.cbuf(), h_.size); | |
494 | 35 | auto const nt = | |
495 | 35 | sizeof(entry) * h_.count; | |
496 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 29 times.
|
35 | if(nt > 0) |
497 | 6 | std::memcpy( | |
498 | 6 | h_.buf + h_.cap - nt, | |
499 | 6 | op.end() - nt, | |
500 | nt); | ||
501 |
2/2✓ Branch 1 taken 35 times.
✓ Branch 2 taken 51 times.
|
99 | } |
502 | |||
503 | void | ||
504 | 8 | fields_base:: | |
505 | shrink_to_fit() | ||
506 | { | ||
507 | 16 | if(detail::header::bytes_needed( | |
508 | 8 | h_.size, h_.count) >= | |
509 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
|
8 | h_.cap) |
510 | 4 | return; | |
511 | |||
512 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
|
5 | if(external_storage_) |
513 | 1 | return; | |
514 | |||
515 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | fields_base tmp(h_); |
516 | 4 | tmp.h_.swap(h_); | |
517 | 4 | } | |
518 | |||
519 | |||
520 | void | ||
521 | 30 | fields_base:: | |
522 | set_max_capacity_in_bytes(std::size_t n) | ||
523 | { | ||
524 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 24 times.
|
30 | if(n < h_.cap) |
525 | 6 | detail::throw_invalid_argument(); | |
526 | 24 | max_cap_ = n; | |
527 | 24 | } | |
528 | |||
529 | //------------------------------------------------ | ||
530 | // | ||
531 | // Modifiers | ||
532 | // | ||
533 | //------------------------------------------------ | ||
534 | |||
535 | auto | ||
536 | 31 | fields_base:: | |
537 | erase( | ||
538 | iterator it) noexcept -> iterator | ||
539 | { | ||
540 | 31 | auto const id = it->id.value_or( | |
541 | detail::header::unknown_field); | ||
542 | 31 | raw_erase(it.i_); | |
543 | 31 | h_.on_erase(id); | |
544 | 31 | return it; | |
545 | } | ||
546 | |||
547 | std::size_t | ||
548 | 30 | fields_base:: | |
549 | erase( | ||
550 | field id) noexcept | ||
551 | { | ||
552 | 30 | auto const i0 = h_.find(id); | |
553 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 27 times.
|
30 | if(i0 == h_.count) |
554 | 3 | return 0; | |
555 | 27 | return erase_all(i0, id); | |
556 | } | ||
557 | |||
558 | std::size_t | ||
559 | 18 | fields_base:: | |
560 | erase( | ||
561 | core::string_view name) noexcept | ||
562 | { | ||
563 | 18 | auto const i0 = h_.find(name); | |
564 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
|
18 | if(i0 == h_.count) |
565 | 3 | return 0; | |
566 | 15 | auto const ft = h_.tab(); | |
567 | 15 | auto const id = ft[i0].id; | |
568 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
|
15 | if(id == detail::header::unknown_field) |
569 | 6 | return erase_all(i0, name); | |
570 | 9 | return erase_all(i0, id); | |
571 | } | ||
572 | |||
573 | //------------------------------------------------ | ||
574 | |||
575 | void | ||
576 | 32 | fields_base:: | |
577 | set( | ||
578 | iterator it, | ||
579 | core::string_view value, | ||
580 | system::error_code& ec) | ||
581 | { | ||
582 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | auto rv = verify_field_value(value); |
583 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 28 times.
|
32 | if(rv.has_error()) |
584 | { | ||
585 | 4 | ec = rv.error(); | |
586 | 4 | return; | |
587 | } | ||
588 | |||
589 | 28 | value = rv->value; | |
590 | 28 | bool has_obs_fold = rv->has_obs_fold; | |
591 | |||
592 | 28 | auto const i = it.i_; | |
593 | 28 | auto tab = h_.tab(); | |
594 | 28 | auto const& e0 = tab[i]; | |
595 | 28 | auto const pos0 = offset(i); | |
596 | 28 | auto const pos1 = offset(i + 1); | |
597 | std::ptrdiff_t dn = | ||
598 | 28 | value.size() - | |
599 | 28 | it->value.size(); | |
600 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
|
28 | if( value.empty() && |
601 |
1/4✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
|
28 | ! it->value.empty()) |
602 | ✗ | --dn; // remove SP | |
603 | 28 | else if( | |
604 |
2/4✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
|
28 | it->value.empty() && |
605 | ✗ | ! value.empty()) | |
606 | ✗ | ++dn; // add SP | |
607 | |||
608 | 28 | op_t op(*this, &value); | |
609 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 22 times.
|
34 | if( dn > 0 && |
610 |
2/4✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
12 | op.grow(value.size() - |
611 |
2/2✓ Branch 3 taken 6 times.
✓ Branch 4 taken 22 times.
|
34 | it->value.size(), 0)) |
612 | { | ||
613 | // reallocated | ||
614 | 6 | auto dest = h_.buf + | |
615 | 6 | pos0 + e0.nn + 1; | |
616 | 12 | std::memcpy( | |
617 | 6 | h_.buf, | |
618 | 6 | op.buf(), | |
619 | 6 | dest - h_.buf); | |
620 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | if(! value.empty()) |
621 | { | ||
622 | 6 | *dest++ = ' '; | |
623 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | value.copy( |
624 | dest, | ||
625 | value.size()); | ||
626 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if( has_obs_fold ) |
627 | 3 | detail::remove_obs_fold( | |
628 | 3 | dest, dest + value.size()); | |
629 | 6 | dest += value.size(); | |
630 | } | ||
631 | 6 | *dest++ = '\r'; | |
632 | 6 | *dest++ = '\n'; | |
633 | 12 | std::memcpy( | |
634 | 6 | h_.buf + pos1 + dn, | |
635 | 12 | op.buf() + pos1, | |
636 | 6 | h_.size - pos1); | |
637 | 12 | std::memcpy( | |
638 | 6 | h_.buf + h_.cap - | |
639 | 6 | sizeof(entry) * h_.count, | |
640 | 6 | &op.tab()[h_.count - 1], | |
641 | 6 | sizeof(entry) * h_.count); | |
642 | } | ||
643 | else | ||
644 | { | ||
645 | // copy the value first | ||
646 | 44 | auto dest = h_.buf + pos0 + | |
647 | 22 | it->name.size() + 1; | |
648 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
22 | if(! value.empty()) |
649 | { | ||
650 | 22 | *dest++ = ' '; | |
651 |
1/2✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
|
22 | value.copy( |
652 | dest, | ||
653 | value.size()); | ||
654 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
|
22 | if( has_obs_fold ) |
655 | ✗ | detail::remove_obs_fold( | |
656 | ✗ | dest, dest + value.size()); | |
657 | 22 | dest += value.size(); | |
658 | } | ||
659 | 22 | op.move_chars( | |
660 | 22 | h_.buf + pos1 + dn, | |
661 | 22 | h_.buf + pos1, | |
662 | 22 | h_.size - pos1); | |
663 | 22 | *dest++ = '\r'; | |
664 | 22 | *dest++ = '\n'; | |
665 | } | ||
666 | { | ||
667 | // update tab | ||
668 | 28 | auto ft = h_.tab(); | |
669 | 40 | for(std::size_t j = h_.count - 1; | |
670 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 28 times.
|
40 | j > i; --j) |
671 | 12 | ft[j] = ft[j] + dn; | |
672 | 28 | auto& e = ft[i]; | |
673 | 56 | e.vp = e.np + e.nn + | |
674 | 28 | 1 + ! value.empty(); | |
675 | 28 | e.vn = static_cast< | |
676 | 28 | offset_type>(value.size()); | |
677 | 28 | h_.size = static_cast< | |
678 | 28 | offset_type>(h_.size + dn); | |
679 | } | ||
680 |
1/2✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
|
28 | auto const id = it->id.value_or( |
681 | detail::header::unknown_field); | ||
682 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 15 times.
|
28 | if(h_.is_special(id)) |
683 | { | ||
684 | // replace first char of name | ||
685 | // with null to hide metadata | ||
686 | 13 | char saved = h_.buf[pos0]; | |
687 | 13 | auto& e = h_.tab()[i]; | |
688 | 13 | e.id = detail::header::unknown_field; | |
689 | 13 | h_.buf[pos0] = '\0'; | |
690 |
1/2✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
13 | h_.on_erase(id); |
691 | 13 | h_.buf[pos0] = saved; // restore | |
692 | 13 | e.id = id; | |
693 |
1/2✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
|
13 | h_.on_insert(id, it->value); |
694 | } | ||
695 | 28 | } | |
696 | |||
697 | // erase existing fields with id | ||
698 | // and then add the field with value | ||
699 | void | ||
700 | 109 | fields_base:: | |
701 | set( | ||
702 | field id, | ||
703 | core::string_view value, | ||
704 | system::error_code& ec) | ||
705 | { | ||
706 |
1/2✓ Branch 1 taken 109 times.
✗ Branch 2 not taken.
|
109 | auto rv = verify_field_value(value); |
707 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 105 times.
|
109 | if(rv.has_error()) |
708 | { | ||
709 | 4 | ec = rv.error(); | |
710 | 4 | return; | |
711 | } | ||
712 | |||
713 | 105 | auto const i0 = h_.find(id); | |
714 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 84 times.
|
105 | if(i0 != h_.count) |
715 | { | ||
716 | // field exists | ||
717 | 21 | auto const ft = h_.tab(); | |
718 | { | ||
719 | // provide strong guarantee | ||
720 | auto const n0 = | ||
721 | 21 | h_.size - length(i0); | |
722 | auto const n = | ||
723 | 21 | ft[i0].nn + 2 + | |
724 | 21 | rv->value.size() + 2; | |
725 | // VFALCO missing overflow check | ||
726 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | reserve_bytes(n0 + n); |
727 | } | ||
728 | 21 | erase_all(i0, id); | |
729 | } | ||
730 | |||
731 |
3/6✓ Branch 1 taken 105 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 105 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 105 times.
✗ Branch 8 not taken.
|
105 | insert_unchecked( |
732 | id, | ||
733 | to_string(id), | ||
734 | 105 | rv->value, | |
735 | 105 | h_.count, | |
736 | 105 | rv->has_obs_fold); | |
737 | } | ||
738 | |||
739 | // erase existing fields with name | ||
740 | // and then add the field with value | ||
741 | void | ||
742 | 33 | fields_base:: | |
743 | set( | ||
744 | core::string_view name, | ||
745 | core::string_view value, | ||
746 | system::error_code& ec) | ||
747 | { | ||
748 |
1/2✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
|
33 | verify_field_name(name , ec); |
749 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 29 times.
|
33 | if(ec.failed()) |
750 | 8 | return; | |
751 | |||
752 |
1/2✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
|
29 | auto rv = verify_field_value(value); |
753 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 25 times.
|
29 | if(rv.has_error()) |
754 | { | ||
755 | 4 | ec = rv.error(); | |
756 | 4 | return; | |
757 | } | ||
758 | |||
759 | 25 | auto const i0 = h_.find(name); | |
760 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 7 times.
|
25 | if(i0 != h_.count) |
761 | { | ||
762 | // field exists | ||
763 | 18 | auto const ft = h_.tab(); | |
764 | 18 | auto const id = ft[i0].id; | |
765 | { | ||
766 | // provide strong guarantee | ||
767 | auto const n0 = | ||
768 | 18 | h_.size - length(i0); | |
769 | auto const n = | ||
770 | 18 | ft[i0].nn + 2 + | |
771 | 18 | rv->value.size() + 2; | |
772 | // VFALCO missing overflow check | ||
773 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 | reserve_bytes(n0 + n); |
774 | } | ||
775 | // VFALCO simple algorithm but | ||
776 | // costs one extra memmove | ||
777 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
|
18 | if(id != detail::header::unknown_field) |
778 | 15 | erase_all(i0, id); | |
779 | else | ||
780 | 3 | erase_all(i0, name); | |
781 | } | ||
782 |
2/2✓ Branch 2 taken 24 times.
✓ Branch 3 taken 1 times.
|
25 | insert_unchecked( |
783 | string_to_field(name), | ||
784 | name, | ||
785 | 25 | rv->value, | |
786 | 25 | h_.count, | |
787 | 25 | rv->has_obs_fold); | |
788 | } | ||
789 | |||
790 | //------------------------------------------------ | ||
791 | // | ||
792 | // (implementation) | ||
793 | // | ||
794 | //------------------------------------------------ | ||
795 | |||
796 | // copy start line and fields | ||
797 | void | ||
798 | 31 | fields_base:: | |
799 | copy_impl( | ||
800 | detail::header const& h) | ||
801 | { | ||
802 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
|
31 | BOOST_ASSERT( |
803 | h.kind == ph_->kind); | ||
804 | |||
805 | auto const n = | ||
806 | 31 | detail::header::bytes_needed( | |
807 | 31 | h.size, h.count); | |
808 |
8/8✓ Branch 0 taken 24 times.
✓ Branch 1 taken 7 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 20 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 21 times.
✓ Branch 8 taken 10 times.
|
31 | if(n <= h_.cap && (!h.is_default() || external_storage_)) |
809 | { | ||
810 | // no realloc | ||
811 | 21 | h.assign_to(h_); | |
812 | 21 | h.copy_table( | |
813 | 21 | h_.buf + h_.cap); | |
814 | 21 | std::memcpy( | |
815 | 21 | h_.buf, | |
816 | 21 | h.cbuf, | |
817 | 21 | h.size); | |
818 | 21 | return; | |
819 | } | ||
820 | |||
821 | // static storages cannot reallocate | ||
822 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if(external_storage_) |
823 | ✗ | detail::throw_length_error(); | |
824 | |||
825 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | fields_base tmp(h); |
826 | 10 | tmp.h_.swap(h_); | |
827 | 10 | } | |
828 | |||
829 | void | ||
830 | 217 | fields_base:: | |
831 | insert_impl( | ||
832 | optional<field> id, | ||
833 | core::string_view name, | ||
834 | core::string_view value, | ||
835 | std::size_t before, | ||
836 | system::error_code& ec) | ||
837 | { | ||
838 |
1/2✓ Branch 1 taken 217 times.
✗ Branch 2 not taken.
|
217 | verify_field_name(name, ec); |
839 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 212 times.
|
217 | if(ec.failed()) |
840 | 23 | return; | |
841 | |||
842 |
1/2✓ Branch 1 taken 212 times.
✗ Branch 2 not taken.
|
212 | auto rv = verify_field_value(value); |
843 |
2/2✓ Branch 1 taken 18 times.
✓ Branch 2 taken 194 times.
|
212 | if(rv.has_error()) |
844 | { | ||
845 | 18 | ec = rv.error(); | |
846 | 18 | return; | |
847 | } | ||
848 | |||
849 |
2/2✓ Branch 1 taken 187 times.
✓ Branch 2 taken 7 times.
|
194 | insert_unchecked( |
850 | id, | ||
851 | name, | ||
852 | 194 | rv->value, | |
853 | before, | ||
854 | 194 | rv->has_obs_fold); | |
855 | } | ||
856 | |||
857 | void | ||
858 | 324 | fields_base:: | |
859 | insert_unchecked( | ||
860 | optional<field> id, | ||
861 | core::string_view name, | ||
862 | core::string_view value, | ||
863 | std::size_t before, | ||
864 | bool has_obs_fold) | ||
865 | { | ||
866 | 324 | auto const tab0 = h_.tab_(); | |
867 | 324 | auto const pos = offset(before); | |
868 | auto const n = | ||
869 | 324 | name.size() + // name | |
870 | 324 | 1 + // ':' | |
871 | 324 | ! value.empty() + // [SP] | |
872 | 324 | value.size() + // value | |
873 | 324 | 2; // CRLF | |
874 | |||
875 | 324 | op_t op(*this, &name, &value); | |
876 |
4/4✓ Branch 1 taken 316 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 217 times.
✓ Branch 4 taken 99 times.
|
324 | if(op.grow(n, 1)) |
877 | { | ||
878 | // reallocated | ||
879 |
2/2✓ Branch 0 taken 197 times.
✓ Branch 1 taken 20 times.
|
217 | if(pos > 0) |
880 | 197 | std::memcpy( | |
881 | 197 | h_.buf, | |
882 | 197 | op.cbuf(), | |
883 | pos); | ||
884 |
2/2✓ Branch 0 taken 89 times.
✓ Branch 1 taken 128 times.
|
217 | if(before > 0) |
885 | 178 | std::memcpy( | |
886 | 89 | h_.tab_() - before, | |
887 | 89 | tab0 - before, | |
888 | before * sizeof(entry)); | ||
889 | 434 | std::memcpy( | |
890 | 217 | h_.buf + pos + n, | |
891 | 217 | op.cbuf() + pos, | |
892 | 217 | h_.size - pos); | |
893 | } | ||
894 | else | ||
895 | { | ||
896 | 99 | op.move_chars( | |
897 | 99 | h_.buf + pos + n, | |
898 | 99 | h_.buf + pos, | |
899 | 99 | h_.size - pos); | |
900 | } | ||
901 | |||
902 | // serialize | ||
903 | { | ||
904 | 316 | auto dest = h_.buf + pos; | |
905 |
1/2✓ Branch 2 taken 316 times.
✗ Branch 3 not taken.
|
316 | name.copy(dest, name.size()); |
906 | 316 | dest += name.size(); | |
907 | 316 | *dest++ = ':'; | |
908 |
2/2✓ Branch 1 taken 304 times.
✓ Branch 2 taken 12 times.
|
316 | if(! value.empty()) |
909 | { | ||
910 | 304 | *dest++ = ' '; | |
911 |
1/2✓ Branch 2 taken 304 times.
✗ Branch 3 not taken.
|
304 | value.copy( |
912 | dest, value.size()); | ||
913 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 286 times.
|
304 | if( has_obs_fold ) |
914 | 18 | detail::remove_obs_fold( | |
915 | 18 | dest, dest + value.size()); | |
916 | 304 | dest += value.size(); | |
917 | } | ||
918 | 316 | *dest++ = '\r'; | |
919 | 316 | *dest = '\n'; | |
920 | } | ||
921 | |||
922 | // update table | ||
923 | 316 | auto const tab = h_.tab_(); | |
924 | { | ||
925 | 316 | auto i = h_.count - before; | |
926 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 273 times.
|
316 | if(i > 0) |
927 | { | ||
928 | 43 | auto p0 = tab0 - h_.count; | |
929 | 43 | auto p = tab - h_.count - 1; | |
930 | do | ||
931 | { | ||
932 | 80 | *p++ = *p0++ + n; | |
933 | } | ||
934 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 43 times.
|
80 | while(--i); |
935 | } | ||
936 | } | ||
937 | 316 | auto& e = tab[0 - static_cast<std::ptrdiff_t>(before) - 1]; | |
938 | 316 | e.np = static_cast<offset_type>( | |
939 | 316 | pos - h_.prefix); | |
940 | 316 | e.nn = static_cast< | |
941 | 316 | offset_type>(name.size()); | |
942 | 316 | e.vp = static_cast<offset_type>( | |
943 | 632 | pos - h_.prefix + | |
944 | 316 | name.size() + 1 + | |
945 | 316 | ! value.empty()); | |
946 | 316 | e.vn = static_cast< | |
947 | 316 | offset_type>(value.size()); | |
948 |
1/2✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
|
316 | e.id = id.value_or( |
949 | detail::header::unknown_field); | ||
950 | |||
951 | // update container | ||
952 | 316 | h_.count++; | |
953 | 316 | h_.size = static_cast< | |
954 | 316 | offset_type>(h_.size + n); | |
955 |
1/2✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
|
316 | h_.on_insert(e.id, value); |
956 | 324 | } | |
957 | |||
958 | void | ||
959 | 175 | fields_base:: | |
960 | raw_erase( | ||
961 | std::size_t i) noexcept | ||
962 | { | ||
963 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 175 times.
|
175 | BOOST_ASSERT(i < h_.count); |
964 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 175 times.
|
175 | BOOST_ASSERT(h_.buf != nullptr); |
965 | 175 | auto const p0 = offset(i); | |
966 | 175 | auto const p1 = offset(i + 1); | |
967 | 175 | std::memmove( | |
968 | 175 | h_.buf + p0, | |
969 | 175 | h_.buf + p1, | |
970 | 175 | h_.size - p1); | |
971 | 175 | auto const n = p1 - p0; | |
972 | 175 | --h_.count; | |
973 | 175 | auto ft = h_.tab(); | |
974 |
2/2✓ Branch 0 taken 102 times.
✓ Branch 1 taken 175 times.
|
277 | for(;i < h_.count; ++i) |
975 | 102 | ft[i] = ft[i + 1] - n; | |
976 | 175 | h_.size = static_cast< | |
977 | 175 | offset_type>(h_.size - n); | |
978 | 175 | } | |
979 | |||
980 | // erase n fields matching id | ||
981 | // without updating metadata | ||
982 | void | ||
983 | 8 | fields_base:: | |
984 | raw_erase_n( | ||
985 | field id, | ||
986 | std::size_t n) noexcept | ||
987 | { | ||
988 | // iterate in reverse | ||
989 | 8 | auto e = &h_.tab()[h_.count]; | |
990 | 8 | auto const e0 = &h_.tab()[0]; | |
991 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 8 times.
|
20 | while(n > 0) |
992 | { | ||
993 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | BOOST_ASSERT(e != e0); |
994 | 12 | ++e; // decrement | |
995 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
|
12 | if(e->id == id) |
996 | { | ||
997 | 10 | raw_erase(e0 - e); | |
998 | 10 | --n; | |
999 | } | ||
1000 | } | ||
1001 | 8 | } | |
1002 | |||
1003 | // erase all fields with id | ||
1004 | // and update metadata | ||
1005 | std::size_t | ||
1006 | 72 | fields_base:: | |
1007 | erase_all( | ||
1008 | std::size_t i0, | ||
1009 | field id) noexcept | ||
1010 | { | ||
1011 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
|
72 | BOOST_ASSERT( |
1012 | id != detail::header::unknown_field); | ||
1013 | 72 | std::size_t n = 1; | |
1014 | 72 | std::size_t i = h_.count - 1; | |
1015 | 72 | auto const ft = h_.tab(); | |
1016 |
2/2✓ Branch 0 taken 77 times.
✓ Branch 1 taken 72 times.
|
149 | while(i > i0) |
1017 | { | ||
1018 |
2/2✓ Branch 1 taken 44 times.
✓ Branch 2 taken 33 times.
|
77 | if(ft[i].id == id) |
1019 | { | ||
1020 | 44 | raw_erase(i); | |
1021 | 44 | ++n; | |
1022 | } | ||
1023 | // go backwards to | ||
1024 | // reduce memmoves | ||
1025 | 77 | --i; | |
1026 | } | ||
1027 | 72 | raw_erase(i0); | |
1028 | 72 | h_.on_erase_all(id); | |
1029 | 72 | return n; | |
1030 | } | ||
1031 | |||
1032 | // erase all fields with name | ||
1033 | // when id == detail::header::unknown_field | ||
1034 | std::size_t | ||
1035 | 9 | fields_base:: | |
1036 | erase_all( | ||
1037 | std::size_t i0, | ||
1038 | core::string_view name) noexcept | ||
1039 | { | ||
1040 | 9 | std::size_t n = 1; | |
1041 | 9 | std::size_t i = h_.count - 1; | |
1042 | 9 | auto const ft = h_.tab(); | |
1043 | 9 | auto const* p = h_.cbuf + h_.prefix; | |
1044 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
|
36 | while(i > i0) |
1045 | { | ||
1046 | core::string_view s( | ||
1047 | 27 | p + ft[i].np, ft[i].nn); | |
1048 |
2/2✓ Branch 1 taken 9 times.
✓ Branch 2 taken 18 times.
|
27 | if(s == name) |
1049 | { | ||
1050 | 9 | raw_erase(i); | |
1051 | 9 | ++n; | |
1052 | } | ||
1053 | // go backwards to | ||
1054 | // reduce memmoves | ||
1055 | 27 | --i; | |
1056 | } | ||
1057 | 9 | raw_erase(i0); | |
1058 | 9 | return n; | |
1059 | } | ||
1060 | |||
1061 | // return i-th field absolute offset | ||
1062 | std::size_t | ||
1063 | 808 | fields_base:: | |
1064 | offset( | ||
1065 | std::size_t i) const noexcept | ||
1066 | { | ||
1067 |
2/2✓ Branch 0 taken 323 times.
✓ Branch 1 taken 485 times.
|
808 | if(i == 0) |
1068 | 323 | return h_.prefix; | |
1069 |
2/2✓ Branch 0 taken 227 times.
✓ Branch 1 taken 258 times.
|
485 | if(i < h_.count) |
1070 | 227 | return h_.prefix + h_.tab()[i].np; | |
1071 | // make final CRLF the last "field" | ||
1072 | 258 | return h_.size - 2; | |
1073 | } | ||
1074 | |||
1075 | // return i-th field absolute length | ||
1076 | std::size_t | ||
1077 | 39 | fields_base:: | |
1078 | length( | ||
1079 | std::size_t i) const noexcept | ||
1080 | { | ||
1081 | return | ||
1082 | 39 | offset(i + 1) - | |
1083 | 39 | offset(i); | |
1084 | } | ||
1085 | |||
1086 | } // http_proto | ||
1087 | } // boost | ||
1088 |