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