Line data Source code
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 : /*
38 : std::size_t
39 : align_down(
40 : void * ptr,
41 : std::size_t size,
42 : std::size_t alignment)
43 : {
44 : auto addr = reinterpret_cast<std::uintptr_t>(ptr);
45 : auto aligned_end = (addr + size) & ~(alignment - 1);
46 :
47 : if(aligned_end > addr)
48 : return aligned_end - addr;
49 :
50 : return 0;
51 : }
52 : */
53 :
54 : void
55 230 : verify_field_name(
56 : core::string_view name,
57 : system::error_code& ec)
58 : {
59 230 : auto rv = grammar::parse(
60 : name, detail::field_name_rule);
61 230 : if(rv.has_error())
62 : {
63 18 : ec = BOOST_HTTP_PROTO_ERR(
64 : error::bad_field_name);
65 : }
66 230 : }
67 :
68 : system::result<detail::field_value_rule_t::value_type>
69 360 : verify_field_value(
70 : core::string_view value)
71 : {
72 360 : auto it = value.begin();
73 360 : auto end = value.end();
74 : auto rv =
75 360 : grammar::parse(it, end, detail::field_value_rule);
76 360 : if( rv.has_error() )
77 : {
78 7 : if( rv.error() == condition::need_more_input )
79 7 : return error::bad_field_value;
80 0 : return rv.error();
81 : }
82 :
83 353 : if( rv->has_crlf )
84 16 : return error::bad_field_smuggle;
85 :
86 337 : if( it != end )
87 7 : return error::bad_field_value;
88 :
89 330 : return rv;
90 : }
91 :
92 : } // namespace
93 :
94 : class fields_base::
95 : op_t
96 : {
97 : fields_base& self_;
98 : core::string_view* s0_;
99 : core::string_view* s1_;
100 : char* buf_ = nullptr;
101 : char const* cbuf_ = nullptr;
102 : std::size_t cap_ = 0;
103 :
104 : public:
105 : explicit
106 977 : op_t(
107 : fields_base& self,
108 : core::string_view* s0 = nullptr,
109 : core::string_view* s1 = nullptr) noexcept
110 977 : : self_(self)
111 977 : , s0_(s0)
112 977 : , s1_(s1)
113 : {
114 977 : }
115 :
116 977 : ~op_t()
117 : {
118 977 : if(buf_)
119 163 : delete[] buf_;
120 977 : }
121 :
122 : char const*
123 12 : buf() const noexcept
124 : {
125 12 : return buf_;
126 : }
127 :
128 : char const*
129 452 : cbuf() const noexcept
130 : {
131 452 : return cbuf_;
132 : }
133 :
134 : char*
135 12 : end() const noexcept
136 : {
137 12 : return buf_ + cap_;
138 : }
139 :
140 : table
141 6 : tab() const noexcept
142 : {
143 6 : return table(end());
144 : }
145 :
146 : bool
147 : reserve(std::size_t n);
148 :
149 : bool
150 : grow(
151 : std::size_t extra_char,
152 : std::size_t extra_field);
153 :
154 : void
155 : move_chars(
156 : char* dest,
157 : char const* src,
158 : std::size_t n) const noexcept;
159 : };
160 :
161 : bool
162 957 : fields_base::
163 : op_t::
164 : reserve(
165 : std::size_t n)
166 : {
167 : // TODO: consider using a growth factor
168 957 : if(n > self_.max_cap_)
169 : {
170 : // max capacity exceeded
171 16 : detail::throw_length_error();
172 : }
173 941 : if(n <= self_.h_.cap)
174 130 : return false;
175 811 : auto buf = new char[n];
176 811 : buf_ = self_.h_.buf;
177 811 : cbuf_ = self_.h_.cbuf;
178 811 : cap_ = self_.h_.cap;
179 811 : self_.h_.buf = buf;
180 811 : self_.h_.cbuf = buf;
181 811 : self_.h_.cap = n;
182 811 : return true;
183 : }
184 :
185 : bool
186 864 : fields_base::
187 : op_t::
188 : grow(
189 : std::size_t extra_char,
190 : std::size_t extra_field)
191 : {
192 864 : if(extra_field > detail::header::max_offset - self_.h_.count)
193 0 : detail::throw_length_error();
194 :
195 864 : if(extra_char > detail::header::max_offset - self_.h_.size)
196 2 : detail::throw_length_error();
197 :
198 862 : return reserve(
199 : detail::header::bytes_needed(
200 862 : self_.h_.size + extra_char,
201 1721 : self_.h_.count + extra_field));
202 : }
203 :
204 : void
205 100 : fields_base::
206 : op_t::
207 : move_chars(
208 : char* dest,
209 : char const* src,
210 : std::size_t n) const noexcept
211 : {
212 100 : detail::move_chars(
213 100 : dest, src, n, s0_, s1_);
214 100 : }
215 :
216 : //------------------------------------------------
217 :
218 40 : fields_base::
219 : prefix_op_t::
220 : prefix_op_t(
221 : fields_base& self,
222 : std::size_t new_prefix,
223 : core::string_view* s0,
224 40 : core::string_view* s1)
225 40 : : self_(self)
226 40 : , new_prefix_(static_cast<
227 40 : offset_type>(new_prefix))
228 : {
229 40 : if(self.h_.size - self.h_.prefix + new_prefix
230 : > detail::header::max_offset)
231 2 : detail::throw_length_error();
232 :
233 : // memmove happens in the destructor
234 : // to avoid overlaping with start line.
235 76 : if(new_prefix_ < self_.h_.prefix
236 38 : && !self.h_.is_default())
237 6 : return;
238 :
239 32 : auto new_size = static_cast<offset_type>(
240 32 : self.h_.size - self.h_.prefix + new_prefix_);
241 :
242 : auto bytes_needed =
243 32 : detail::header::bytes_needed(
244 : new_size,
245 32 : self.h_.count);
246 :
247 32 : if(bytes_needed > self.h_.cap)
248 : {
249 : // static storage will always throw which is
250 : // intended since they cannot reallocate.
251 26 : if(self.max_cap_ < bytes_needed)
252 0 : detail::throw_length_error();
253 : // TODO: consider using a growth factor
254 26 : char* p = new char[bytes_needed];
255 26 : std::memcpy(
256 26 : p + new_prefix_,
257 26 : self.h_.cbuf + self.h_.prefix,
258 26 : self.h_.size - self.h_.prefix);
259 26 : self.h_.copy_table(p + bytes_needed);
260 :
261 : // old buffer gets released in the destructor
262 : // to avoid invalidating any string_views
263 : // that may still reference it.
264 26 : buf_ = self.h_.buf;
265 26 : self.h_.buf = p;
266 26 : self.h_.cap = bytes_needed;
267 : }
268 : else
269 : {
270 : // memmove to the right and update any
271 : // string_views that reference that region.
272 6 : detail::move_chars(
273 6 : self.h_.buf + new_prefix_,
274 6 : self.h_.cbuf + self.h_.prefix,
275 6 : self.h_.size - self.h_.prefix,
276 : s0,
277 : s1);
278 : }
279 :
280 32 : self.h_.cbuf = self.h_.buf;
281 32 : self.h_.size = new_size;
282 32 : self.h_.prefix = new_prefix_;
283 : }
284 :
285 38 : fields_base::
286 : prefix_op_t::
287 : ~prefix_op_t()
288 : {
289 38 : if(new_prefix_ < self_.h_.prefix)
290 : {
291 6 : std::memmove(
292 6 : self_.h_.buf + new_prefix_,
293 6 : self_.h_.cbuf + self_.h_.prefix,
294 6 : self_.h_.size - self_.h_.prefix);
295 :
296 6 : self_.h_.size =
297 6 : self_.h_.size - self_.h_.prefix + new_prefix_;
298 6 : self_.h_.prefix = new_prefix_;
299 : }
300 32 : else if(buf_)
301 : {
302 5 : delete[] buf_;
303 : }
304 38 : }
305 :
306 : //------------------------------------------------
307 :
308 194 : fields_base::
309 : fields_base(
310 194 : detail::kind k) noexcept
311 194 : : h_(k)
312 : {
313 194 : }
314 :
315 : // copy s and parse it
316 542 : fields_base::
317 : fields_base(
318 : detail::kind k,
319 542 : core::string_view s)
320 542 : : h_(detail::empty{k})
321 : {
322 542 : auto n = detail::header::count_crlf(s);
323 542 : if(h_.kind == detail::kind::fields)
324 : {
325 235 : if(n < 1)
326 1 : detail::throw_invalid_argument();
327 234 : n -= 1;
328 : }
329 : else
330 : {
331 307 : if(n < 2)
332 2 : detail::throw_invalid_argument();
333 305 : n -= 2;
334 : }
335 539 : op_t op(*this);
336 539 : op.grow(s.size(), n);
337 539 : s.copy(h_.buf, s.size());
338 539 : system::error_code ec;
339 : // VFALCO This is using defaults?
340 539 : header_limits lim;
341 539 : h_.parse(s.size(), lim, ec);
342 539 : if(ec.failed())
343 0 : detail::throw_system_error(ec);
344 539 : }
345 :
346 : // construct a complete copy of h
347 19 : fields_base::
348 : fields_base(
349 19 : detail::header const& h)
350 19 : : h_(h.kind)
351 : {
352 19 : if(h.is_default())
353 6 : return;
354 :
355 : // allocate and copy the buffer
356 13 : op_t op(*this);
357 13 : op.grow(h.size, h.count);
358 13 : h.assign_to(h_);
359 13 : std::memcpy(
360 13 : h_.buf, h.cbuf, h.size);
361 13 : h.copy_table(h_.buf + h_.cap);
362 13 : }
363 :
364 316 : fields_base::
365 : fields_base(
366 : view_tag_t,
367 316 : detail::header const& h)
368 316 : : h_(h)
369 316 : , view_(true)
370 : {
371 316 : }
372 :
373 : //------------------------------------------------
374 :
375 9 : fields_base::
376 9 : fields_base(fields_base const& other)
377 9 : : fields_base(other.h_)
378 : {
379 9 : }
380 :
381 1068 : fields_base::
382 : ~fields_base()
383 : {
384 1068 : if(h_.buf && !view_)
385 669 : delete[] h_.buf;
386 1068 : }
387 :
388 : //------------------------------------------------
389 : //
390 : // Capacity
391 : //
392 : //------------------------------------------------
393 :
394 : void
395 10 : fields_base::
396 : clear() noexcept
397 : {
398 10 : clone_if_needed();
399 :
400 10 : if(! h_.buf)
401 5 : return;
402 : using H =
403 : detail::header;
404 : auto const& h =
405 5 : *H::get_default(
406 5 : h_.kind);
407 5 : h.assign_to(h_);
408 5 : std::memcpy(
409 5 : h_.buf,
410 5 : h.cbuf,
411 5 : h_.size);
412 : }
413 :
414 : void
415 95 : fields_base::
416 : reserve_bytes(
417 : std::size_t n)
418 : {
419 95 : clone_if_needed();
420 :
421 95 : op_t op(*this);
422 95 : if(! op.reserve(n))
423 48 : return;
424 68 : std::memcpy(
425 34 : h_.buf, op.cbuf(), h_.size);
426 34 : auto const nt =
427 34 : sizeof(entry) * h_.count;
428 34 : if(nt > 0)
429 6 : std::memcpy(
430 6 : h_.buf + h_.cap - nt,
431 6 : op.end() - nt,
432 : nt);
433 95 : }
434 :
435 : void
436 7 : fields_base::
437 : shrink_to_fit()
438 : {
439 7 : clone_if_needed();
440 :
441 14 : if(detail::header::bytes_needed(
442 7 : h_.size, h_.count) >=
443 7 : h_.cap)
444 3 : return;
445 :
446 4 : fields_base tmp(h_);
447 4 : tmp.h_.swap(h_);
448 4 : }
449 :
450 : void
451 30 : fields_base::
452 : set_max_capacity_in_bytes(std::size_t n)
453 : {
454 30 : clone_if_needed();
455 :
456 30 : if(n < h_.cap)
457 6 : detail::throw_invalid_argument();
458 24 : max_cap_ = n;
459 24 : }
460 :
461 : //--------------------------------------------
462 : //
463 : // Observers
464 : //
465 : //--------------------------------------------
466 :
467 :
468 0 : fields_base::
469 : value_type::
470 : value_type(
471 0 : reference const& other)
472 0 : : id(other.id)
473 0 : , name(other.name)
474 0 : , value(other.value)
475 : {
476 0 : }
477 :
478 : //------------------------------------------------
479 :
480 : auto
481 1816 : fields_base::
482 : iterator::
483 : operator*() const noexcept ->
484 : reference
485 : {
486 1816 : BOOST_ASSERT(i_ < ph_->count);
487 : auto tab =
488 1816 : ph_->tab();
489 : auto const& e =
490 1816 : tab[i_];
491 1816 : auto const* p =
492 1816 : ph_->cbuf + ph_->prefix;
493 : return {
494 1816 : (e.id == detail::header::unknown_field)
495 1816 : ? optional<field>{} : e.id,
496 : core::string_view(
497 1816 : p + e.np, e.nn),
498 : core::string_view(
499 1816 : p + e.vp, e.vn) };
500 : }
501 :
502 : //------------------------------------------------
503 :
504 : auto
505 24 : fields_base::
506 : reverse_iterator::
507 : operator*() const noexcept ->
508 : reference
509 : {
510 24 : BOOST_ASSERT(i_ > 0);
511 : auto tab =
512 24 : ph_->tab();
513 : auto const& e =
514 24 : tab[i_-1];
515 24 : auto const* p =
516 24 : ph_->cbuf + ph_->prefix;
517 : return {
518 24 : (e.id == detail::header::unknown_field)
519 24 : ? optional<field>{} : e.id,
520 : core::string_view(
521 24 : p + e.np, e.nn),
522 : core::string_view(
523 24 : p + e.vp, e.vn) };
524 : }
525 :
526 : //------------------------------------------------
527 :
528 21 : fields_base::
529 : subrange::
530 : iterator::
531 : iterator(
532 : detail::header const* ph,
533 21 : std::size_t i) noexcept
534 21 : : ph_(ph)
535 21 : , i_(i)
536 : {
537 21 : BOOST_ASSERT(i <= ph_->count);
538 21 : }
539 :
540 21 : fields_base::
541 : subrange::
542 : iterator::
543 : iterator(
544 21 : detail::header const* ph) noexcept
545 21 : : ph_(ph)
546 21 : , i_(ph->count)
547 : {
548 21 : }
549 :
550 : auto
551 11 : fields_base::
552 : subrange::
553 : iterator::
554 : operator*() const noexcept ->
555 : reference const
556 : {
557 : auto tab =
558 11 : ph_->tab();
559 : auto const& e =
560 11 : tab[i_];
561 11 : auto const p =
562 11 : ph_->cbuf + ph_->prefix;
563 22 : return core::string_view(
564 11 : p + e.vp, e.vn);
565 : }
566 :
567 : auto
568 27 : fields_base::
569 : subrange::
570 : iterator::
571 : operator++() noexcept ->
572 : iterator&
573 : {
574 27 : BOOST_ASSERT(i_ < ph_->count);
575 27 : auto const* e = &ph_->tab()[i_];
576 27 : auto const id = e->id;
577 27 : if(id != detail::header::unknown_field)
578 : {
579 20 : ++i_;
580 20 : --e;
581 38 : while(i_ != ph_->count)
582 : {
583 26 : if(e->id == id)
584 8 : break;
585 18 : ++i_;
586 18 : --e;
587 : }
588 20 : return *this;
589 : }
590 7 : auto const p =
591 7 : ph_->cbuf + ph_->prefix;
592 : auto name = core::string_view(
593 7 : p + e->np, e->nn);
594 7 : ++i_;
595 7 : --e;
596 24 : while(i_ != ph_->count)
597 : {
598 20 : if(grammar::ci_is_equal(
599 : name, core::string_view(
600 20 : p + e->np, e->nn)))
601 3 : break;
602 17 : ++i_;
603 17 : --e;
604 : }
605 7 : return *this;
606 : }
607 :
608 : //------------------------------------------------
609 : //
610 : // fields_base
611 : //
612 : //------------------------------------------------
613 :
614 : core::string_view
615 2 : fields_base::
616 : at(
617 : field id) const
618 : {
619 2 : auto const it = find(id);
620 2 : if(it == end())
621 2 : BOOST_THROW_EXCEPTION(
622 : std::out_of_range{ "field not found" });
623 1 : return it->value;
624 : }
625 :
626 : core::string_view
627 2 : fields_base::
628 : at(
629 : core::string_view name) const
630 : {
631 2 : auto const it = find(name);
632 2 : if(it == end())
633 2 : BOOST_THROW_EXCEPTION(
634 : std::out_of_range{ "field not found" });
635 1 : return it->value;
636 : }
637 :
638 : bool
639 4 : fields_base::
640 : exists(
641 : field id) const noexcept
642 : {
643 4 : return find(id) != end();
644 : }
645 :
646 : bool
647 7 : fields_base::
648 : exists(
649 : core::string_view name) const noexcept
650 : {
651 7 : return find(name) != end();
652 : }
653 :
654 : std::size_t
655 12 : fields_base::
656 : count(field id) const noexcept
657 : {
658 12 : std::size_t n = 0;
659 57 : for(auto v : *this)
660 45 : if(v.id == id)
661 11 : ++n;
662 12 : return n;
663 : }
664 :
665 : std::size_t
666 14 : fields_base::
667 : count(
668 : core::string_view name) const noexcept
669 : {
670 14 : std::size_t n = 0;
671 76 : for(auto v : *this)
672 62 : if(grammar::ci_is_equal(
673 : v.name, name))
674 19 : ++n;
675 14 : return n;
676 : }
677 :
678 : auto
679 94 : fields_base::
680 : find(field id) const noexcept ->
681 : iterator
682 : {
683 94 : auto it = begin();
684 94 : auto const last = end();
685 208 : while(it != last)
686 : {
687 199 : if(it->id == id)
688 85 : break;
689 114 : ++it;
690 : }
691 94 : return it;
692 : }
693 :
694 : auto
695 93 : fields_base::
696 : find(
697 : core::string_view name) const noexcept ->
698 : iterator
699 : {
700 93 : auto it = begin();
701 93 : auto const last = end();
702 206 : while(it != last)
703 : {
704 200 : if(grammar::ci_is_equal(
705 400 : it->name, name))
706 87 : break;
707 113 : ++it;
708 : }
709 93 : return it;
710 : }
711 :
712 : auto
713 2 : fields_base::
714 : find(
715 : iterator from,
716 : field id) const noexcept ->
717 : iterator
718 : {
719 2 : auto const last = end();
720 11 : while(from != last)
721 : {
722 10 : if(from->id == id)
723 1 : break;
724 9 : ++from;
725 : }
726 2 : return from;
727 : }
728 :
729 : auto
730 2 : fields_base::
731 : find(
732 : iterator from,
733 : core::string_view name) const noexcept ->
734 : iterator
735 : {
736 2 : auto const last = end();
737 12 : while(from != last)
738 : {
739 11 : if(grammar::ci_is_equal(
740 22 : name, from->name))
741 1 : break;
742 10 : ++from;
743 : }
744 2 : return from;
745 : }
746 :
747 : auto
748 3 : fields_base::
749 : find_last(
750 : iterator it,
751 : field id) const noexcept ->
752 : iterator
753 : {
754 3 : auto const it0 = begin();
755 : for(;;)
756 : {
757 10 : if(it == it0)
758 1 : return end();
759 9 : --it;
760 9 : if(it->id == id)
761 2 : return it;
762 : }
763 : }
764 :
765 : auto
766 3 : fields_base::
767 : find_last(
768 : iterator it,
769 : core::string_view name) const noexcept ->
770 : iterator
771 : {
772 3 : auto const it0 = begin();
773 : for(;;)
774 : {
775 14 : if(it == it0)
776 1 : return end();
777 13 : --it;
778 13 : if(grammar::ci_is_equal(
779 26 : it->name, name))
780 2 : return it;
781 : }
782 : }
783 :
784 : core::string_view
785 2 : fields_base::
786 : value_or(
787 : field id,
788 : core::string_view s) const noexcept
789 : {
790 2 : auto it = find(id);
791 2 : if(it != end())
792 1 : return it->value;
793 1 : return s;
794 : }
795 :
796 : core::string_view
797 2 : fields_base::
798 : value_or(
799 : core::string_view name,
800 : core::string_view s) const noexcept
801 : {
802 2 : auto it = find(name);
803 2 : if(it != end())
804 1 : return it->value;
805 1 : return s;
806 : }
807 :
808 : //------------------------------------------------
809 :
810 : auto
811 16 : fields_base::
812 : find_all(
813 : field id) const noexcept ->
814 : subrange
815 : {
816 16 : return subrange(
817 32 : &h_, find(id).i_);
818 : }
819 :
820 : auto
821 5 : fields_base::
822 : find_all(
823 : core::string_view name) const noexcept ->
824 : subrange
825 : {
826 5 : return subrange(
827 10 : &h_, find(name).i_);
828 : }
829 :
830 : std::ostream&
831 1 : operator<<(
832 : std::ostream& os,
833 : const fields_base& f)
834 : {
835 1 : if(f.h_.prefix != 0)
836 1 : os << core::string_view(f.h_.cbuf, f.h_.prefix - 2) << '\n';
837 :
838 3 : for(auto ref : f)
839 2 : os << ref.name << ": " << ref.value << '\n';
840 :
841 1 : return os;
842 : }
843 :
844 : //------------------------------------------------
845 : //
846 : // Modifiers
847 : //
848 : //------------------------------------------------
849 :
850 : auto
851 30 : fields_base::
852 : erase(
853 : iterator it) noexcept -> iterator
854 : {
855 30 : clone_if_needed();
856 :
857 30 : auto const id = it->id.value_or(
858 : detail::header::unknown_field);
859 30 : raw_erase(it.i_);
860 30 : h_.on_erase(id);
861 30 : return it;
862 : }
863 :
864 : std::size_t
865 30 : fields_base::
866 : erase(
867 : field id) noexcept
868 : {
869 30 : clone_if_needed();
870 :
871 30 : auto const i0 = h_.find(id);
872 30 : if(i0 == h_.count)
873 3 : return 0;
874 27 : return erase_all(i0, id);
875 : }
876 :
877 : std::size_t
878 18 : fields_base::
879 : erase(
880 : core::string_view name) noexcept
881 : {
882 18 : clone_if_needed();
883 :
884 18 : auto const i0 = h_.find(name);
885 18 : if(i0 == h_.count)
886 3 : return 0;
887 15 : auto const ft = h_.tab();
888 15 : auto const id = ft[i0].id;
889 15 : if(id == detail::header::unknown_field)
890 6 : return erase_all(i0, name);
891 9 : return erase_all(i0, id);
892 : }
893 :
894 : //------------------------------------------------
895 :
896 : void
897 28 : fields_base::
898 : set(
899 : iterator it,
900 : core::string_view value,
901 : system::error_code& ec)
902 : {
903 28 : clone_if_needed();
904 :
905 28 : auto rv = verify_field_value(value);
906 28 : if(rv.has_error())
907 : {
908 4 : ec = rv.error();
909 4 : return;
910 : }
911 :
912 24 : value = rv->value;
913 24 : bool has_obs_fold = rv->has_obs_fold;
914 :
915 24 : auto const i = it.i_;
916 24 : auto tab = h_.tab();
917 24 : auto const& e0 = tab[i];
918 24 : auto const pos0 = offset(i);
919 24 : auto const pos1 = offset(i + 1);
920 : std::ptrdiff_t dn =
921 24 : value.size() -
922 24 : it->value.size();
923 24 : if( value.empty() &&
924 24 : ! it->value.empty())
925 0 : --dn; // remove SP
926 24 : else if(
927 24 : it->value.empty() &&
928 0 : ! value.empty())
929 0 : ++dn; // add SP
930 :
931 24 : op_t op(*this, &value);
932 30 : if( dn > 0 &&
933 12 : op.grow(value.size() -
934 30 : it->value.size(), 0))
935 : {
936 : // reallocated
937 6 : auto dest = h_.buf +
938 6 : pos0 + e0.nn + 1;
939 12 : std::memcpy(
940 6 : h_.buf,
941 6 : op.buf(),
942 6 : dest - h_.buf);
943 6 : if(! value.empty())
944 : {
945 6 : *dest++ = ' ';
946 6 : value.copy(
947 : dest,
948 : value.size());
949 6 : if( has_obs_fold )
950 3 : detail::remove_obs_fold(
951 3 : dest, dest + value.size());
952 6 : dest += value.size();
953 : }
954 6 : *dest++ = '\r';
955 6 : *dest++ = '\n';
956 12 : std::memcpy(
957 6 : h_.buf + pos1 + dn,
958 12 : op.buf() + pos1,
959 6 : h_.size - pos1);
960 12 : std::memcpy(
961 6 : h_.buf + h_.cap -
962 6 : sizeof(entry) * h_.count,
963 6 : &op.tab()[h_.count - 1],
964 6 : sizeof(entry) * h_.count);
965 : }
966 : else
967 : {
968 : // copy the value first
969 36 : auto dest = h_.buf + pos0 +
970 18 : it->name.size() + 1;
971 18 : if(! value.empty())
972 : {
973 18 : *dest++ = ' ';
974 18 : value.copy(
975 : dest,
976 : value.size());
977 18 : if( has_obs_fold )
978 0 : detail::remove_obs_fold(
979 0 : dest, dest + value.size());
980 18 : dest += value.size();
981 : }
982 18 : op.move_chars(
983 18 : h_.buf + pos1 + dn,
984 18 : h_.buf + pos1,
985 18 : h_.size - pos1);
986 18 : *dest++ = '\r';
987 18 : *dest++ = '\n';
988 : }
989 : {
990 : // update tab
991 24 : auto ft = h_.tab();
992 31 : for(std::size_t j = h_.count - 1;
993 31 : j > i; --j)
994 7 : ft[j] = ft[j] + dn;
995 24 : auto& e = ft[i];
996 48 : e.vp = e.np + e.nn +
997 24 : 1 + ! value.empty();
998 24 : e.vn = static_cast<
999 24 : offset_type>(value.size());
1000 24 : h_.size = static_cast<
1001 24 : offset_type>(h_.size + dn);
1002 : }
1003 24 : auto const id = it->id.value_or(
1004 : detail::header::unknown_field);
1005 24 : if(h_.is_special(id))
1006 : {
1007 : // replace first char of name
1008 : // with null to hide metadata
1009 9 : char saved = h_.buf[pos0];
1010 9 : auto& e = h_.tab()[i];
1011 9 : e.id = detail::header::unknown_field;
1012 9 : h_.buf[pos0] = '\0';
1013 9 : h_.on_erase(id);
1014 9 : h_.buf[pos0] = saved; // restore
1015 9 : e.id = id;
1016 9 : h_.on_insert(id, it->value);
1017 : }
1018 24 : }
1019 :
1020 : // erase existing fields with id
1021 : // and then add the field with value
1022 : void
1023 111 : fields_base::
1024 : set(
1025 : field id,
1026 : core::string_view value,
1027 : system::error_code& ec)
1028 : {
1029 111 : clone_if_needed();
1030 :
1031 111 : auto rv = verify_field_value(value);
1032 111 : if(rv.has_error())
1033 : {
1034 4 : ec = rv.error();
1035 4 : return;
1036 : }
1037 :
1038 107 : auto const i0 = h_.find(id);
1039 107 : if(i0 != h_.count)
1040 : {
1041 : // field exists
1042 21 : auto const ft = h_.tab();
1043 : {
1044 : // provide strong guarantee
1045 : auto const n0 =
1046 21 : h_.size - length(i0);
1047 : auto const n =
1048 21 : ft[i0].nn + 2 +
1049 21 : rv->value.size() + 2;
1050 : // VFALCO missing overflow check
1051 21 : reserve_bytes(n0 + n);
1052 : }
1053 21 : erase_all(i0, id);
1054 : }
1055 :
1056 107 : insert_unchecked(
1057 : id,
1058 : to_string(id),
1059 107 : rv->value,
1060 107 : h_.count,
1061 107 : rv->has_obs_fold);
1062 : }
1063 :
1064 : // erase existing fields with name
1065 : // and then add the field with value
1066 : void
1067 32 : fields_base::
1068 : set(
1069 : core::string_view name,
1070 : core::string_view value,
1071 : system::error_code& ec)
1072 : {
1073 32 : clone_if_needed();
1074 :
1075 32 : verify_field_name(name , ec);
1076 32 : if(ec.failed())
1077 8 : return;
1078 :
1079 28 : auto rv = verify_field_value(value);
1080 28 : if(rv.has_error())
1081 : {
1082 4 : ec = rv.error();
1083 4 : return;
1084 : }
1085 :
1086 24 : auto const i0 = h_.find(name);
1087 24 : if(i0 != h_.count)
1088 : {
1089 : // field exists
1090 18 : auto const ft = h_.tab();
1091 18 : auto const id = ft[i0].id;
1092 : {
1093 : // provide strong guarantee
1094 : auto const n0 =
1095 18 : h_.size - length(i0);
1096 : auto const n =
1097 18 : ft[i0].nn + 2 +
1098 18 : rv->value.size() + 2;
1099 : // VFALCO missing overflow check
1100 18 : reserve_bytes(n0 + n);
1101 : }
1102 : // VFALCO simple algorithm but
1103 : // costs one extra memmove
1104 18 : if(id != detail::header::unknown_field)
1105 15 : erase_all(i0, id);
1106 : else
1107 3 : erase_all(i0, name);
1108 : }
1109 24 : insert_unchecked(
1110 : string_to_field(name),
1111 : name,
1112 24 : rv->value,
1113 24 : h_.count,
1114 24 : rv->has_obs_fold);
1115 : }
1116 :
1117 : auto
1118 26 : fields_base::
1119 : insert(
1120 : iterator before,
1121 : field id,
1122 : core::string_view value)
1123 : -> iterator
1124 : {
1125 26 : system::error_code ec;
1126 26 : auto const it = insert(before, id, value, ec);
1127 26 : if(ec.failed())
1128 1 : detail::throw_system_error(ec);
1129 25 : return it;
1130 : }
1131 :
1132 : auto
1133 33 : fields_base::
1134 : insert(
1135 : iterator before,
1136 : field id,
1137 : core::string_view value,
1138 : system::error_code& ec)
1139 : -> iterator
1140 : {
1141 33 : clone_if_needed();
1142 :
1143 33 : insert_impl(
1144 : id,
1145 : to_string(id),
1146 : value,
1147 : before.i_, ec);
1148 33 : return before;
1149 : }
1150 :
1151 : auto
1152 13 : fields_base::
1153 : insert(
1154 : iterator before,
1155 : core::string_view name,
1156 : core::string_view value)
1157 : -> iterator
1158 : {
1159 13 : system::error_code ec;
1160 13 : insert(before, name, value, ec);
1161 13 : if(ec.failed())
1162 1 : detail::throw_system_error(ec);
1163 12 : return before;
1164 : }
1165 :
1166 : auto
1167 16 : fields_base::
1168 : insert(
1169 : iterator before,
1170 : core::string_view name,
1171 : core::string_view value,
1172 : system::error_code& ec)
1173 : -> iterator
1174 : {
1175 16 : clone_if_needed();
1176 :
1177 16 : insert_impl(
1178 : string_to_field(name),
1179 : name,
1180 : value,
1181 : before.i_,
1182 : ec);
1183 16 : return before;
1184 : }
1185 :
1186 : void
1187 23 : fields_base::
1188 : set(
1189 : iterator it,
1190 : core::string_view value)
1191 : {
1192 23 : system::error_code ec;
1193 23 : set(it, value, ec);
1194 23 : if(ec.failed())
1195 2 : detail::throw_system_error(ec);
1196 21 : }
1197 :
1198 : //------------------------------------------------
1199 : //
1200 : // (implementation)
1201 : //
1202 : //------------------------------------------------
1203 :
1204 : // copy start line and fields
1205 : void
1206 8 : fields_base::
1207 : copy_impl(
1208 : detail::header const& h)
1209 : {
1210 8 : BOOST_ASSERT(
1211 : h.kind == h_.kind);
1212 :
1213 : auto const n =
1214 8 : detail::header::bytes_needed(
1215 8 : h.size, h.count);
1216 8 : if(n <= h_.cap && !view_ && !h.is_default())
1217 : {
1218 : // no realloc
1219 2 : h.assign_to(h_);
1220 2 : h.copy_table(
1221 2 : h_.buf + h_.cap);
1222 2 : std::memcpy(
1223 2 : h_.buf,
1224 2 : h.cbuf,
1225 2 : h.size);
1226 2 : return;
1227 : }
1228 :
1229 6 : fields_base tmp(h);
1230 6 : tmp.h_.swap(h_);
1231 6 : std::swap(tmp.view_, view_);
1232 6 : }
1233 :
1234 : void
1235 492 : fields_base::
1236 : clone_if_needed()
1237 : {
1238 492 : if(view_)
1239 : {
1240 0 : fields_base tmp(h_);
1241 0 : tmp.h_.swap(h_);
1242 0 : tmp.view_ = true;
1243 0 : view_ = false;
1244 0 : }
1245 492 : }
1246 :
1247 : void
1248 198 : fields_base::
1249 : insert_impl(
1250 : optional<field> id,
1251 : core::string_view name,
1252 : core::string_view value,
1253 : std::size_t before,
1254 : system::error_code& ec)
1255 : {
1256 198 : verify_field_name(name, ec);
1257 198 : if(ec.failed())
1258 23 : return;
1259 :
1260 193 : auto rv = verify_field_value(value);
1261 193 : if(rv.has_error())
1262 : {
1263 18 : ec = rv.error();
1264 18 : return;
1265 : }
1266 :
1267 175 : insert_unchecked(
1268 : id,
1269 : name,
1270 175 : rv->value,
1271 : before,
1272 175 : rv->has_obs_fold);
1273 : }
1274 :
1275 : void
1276 306 : fields_base::
1277 : insert_unchecked(
1278 : optional<field> id,
1279 : core::string_view name,
1280 : core::string_view value,
1281 : std::size_t before,
1282 : bool has_obs_fold)
1283 : {
1284 306 : auto const tab0 = h_.tab_();
1285 306 : auto const pos = offset(before);
1286 : auto const n =
1287 306 : name.size() + // name
1288 306 : 1 + // ':'
1289 306 : ! value.empty() + // [SP]
1290 306 : value.size() + // value
1291 306 : 2; // CRLF
1292 :
1293 306 : op_t op(*this, &name, &value);
1294 306 : if(op.grow(n, 1))
1295 : {
1296 : // reallocated
1297 219 : if(pos > 0)
1298 199 : std::memcpy(
1299 199 : h_.buf,
1300 199 : op.cbuf(),
1301 : pos);
1302 219 : if(before > 0)
1303 180 : std::memcpy(
1304 90 : h_.tab_() - before,
1305 90 : tab0 - before,
1306 : before * sizeof(entry));
1307 438 : std::memcpy(
1308 219 : h_.buf + pos + n,
1309 219 : op.cbuf() + pos,
1310 219 : h_.size - pos);
1311 : }
1312 : else
1313 : {
1314 82 : op.move_chars(
1315 82 : h_.buf + pos + n,
1316 82 : h_.buf + pos,
1317 82 : h_.size - pos);
1318 : }
1319 :
1320 : // serialize
1321 : {
1322 301 : auto dest = h_.buf + pos;
1323 301 : name.copy(dest, name.size());
1324 301 : dest += name.size();
1325 301 : *dest++ = ':';
1326 301 : if(! value.empty())
1327 : {
1328 289 : *dest++ = ' ';
1329 289 : value.copy(
1330 : dest, value.size());
1331 289 : if( has_obs_fold )
1332 18 : detail::remove_obs_fold(
1333 18 : dest, dest + value.size());
1334 289 : dest += value.size();
1335 : }
1336 301 : *dest++ = '\r';
1337 301 : *dest = '\n';
1338 : }
1339 :
1340 : // update table
1341 301 : auto const tab = h_.tab_();
1342 : {
1343 301 : auto i = h_.count - before;
1344 301 : if(i > 0)
1345 : {
1346 43 : auto p0 = tab0 - h_.count;
1347 43 : auto p = tab - h_.count - 1;
1348 : do
1349 : {
1350 80 : *p++ = *p0++ + n;
1351 : }
1352 80 : while(--i);
1353 : }
1354 : }
1355 301 : auto& e = tab[0 - static_cast<std::ptrdiff_t>(before) - 1];
1356 301 : e.np = static_cast<offset_type>(
1357 301 : pos - h_.prefix);
1358 301 : e.nn = static_cast<
1359 301 : offset_type>(name.size());
1360 301 : e.vp = static_cast<offset_type>(
1361 602 : pos - h_.prefix +
1362 301 : name.size() + 1 +
1363 301 : ! value.empty());
1364 301 : e.vn = static_cast<
1365 301 : offset_type>(value.size());
1366 301 : e.id = id.value_or(
1367 : detail::header::unknown_field);
1368 :
1369 : // update container
1370 301 : h_.count++;
1371 301 : h_.size = static_cast<
1372 301 : offset_type>(h_.size + n);
1373 301 : h_.on_insert(e.id, value);
1374 306 : }
1375 :
1376 : void
1377 169 : fields_base::
1378 : raw_erase(
1379 : std::size_t i) noexcept
1380 : {
1381 169 : BOOST_ASSERT(i < h_.count);
1382 169 : BOOST_ASSERT(h_.buf != nullptr);
1383 169 : auto const p0 = offset(i);
1384 169 : auto const p1 = offset(i + 1);
1385 169 : std::memmove(
1386 169 : h_.buf + p0,
1387 169 : h_.buf + p1,
1388 169 : h_.size - p1);
1389 169 : auto const n = p1 - p0;
1390 169 : --h_.count;
1391 169 : auto ft = h_.tab();
1392 270 : for(;i < h_.count; ++i)
1393 101 : ft[i] = ft[i + 1] - n;
1394 169 : h_.size = static_cast<
1395 169 : offset_type>(h_.size - n);
1396 169 : }
1397 :
1398 : // erase n fields matching id
1399 : // without updating metadata
1400 : void
1401 4 : fields_base::
1402 : raw_erase_n(
1403 : field id,
1404 : std::size_t n) noexcept
1405 : {
1406 : // iterate in reverse
1407 4 : auto e = &h_.tab()[h_.count];
1408 4 : auto const e0 = &h_.tab()[0];
1409 10 : while(n > 0)
1410 : {
1411 6 : BOOST_ASSERT(e != e0);
1412 6 : ++e; // decrement
1413 6 : if(e->id == id)
1414 : {
1415 5 : raw_erase(e0 - e);
1416 5 : --n;
1417 : }
1418 : }
1419 4 : }
1420 :
1421 : // erase all fields with id
1422 : // and update metadata
1423 : std::size_t
1424 72 : fields_base::
1425 : erase_all(
1426 : std::size_t i0,
1427 : field id) noexcept
1428 : {
1429 72 : BOOST_ASSERT(
1430 : id != detail::header::unknown_field);
1431 72 : std::size_t n = 1;
1432 72 : std::size_t i = h_.count - 1;
1433 72 : auto const ft = h_.tab();
1434 149 : while(i > i0)
1435 : {
1436 77 : if(ft[i].id == id)
1437 : {
1438 44 : raw_erase(i);
1439 44 : ++n;
1440 : }
1441 : // go backwards to
1442 : // reduce memmoves
1443 77 : --i;
1444 : }
1445 72 : raw_erase(i0);
1446 72 : h_.on_erase_all(id);
1447 72 : return n;
1448 : }
1449 :
1450 : // erase all fields with name
1451 : // when id == detail::header::unknown_field
1452 : std::size_t
1453 9 : fields_base::
1454 : erase_all(
1455 : std::size_t i0,
1456 : core::string_view name) noexcept
1457 : {
1458 9 : std::size_t n = 1;
1459 9 : std::size_t i = h_.count - 1;
1460 9 : auto const ft = h_.tab();
1461 9 : auto const* p = h_.cbuf + h_.prefix;
1462 36 : while(i > i0)
1463 : {
1464 : core::string_view s(
1465 27 : p + ft[i].np, ft[i].nn);
1466 27 : if(s == name)
1467 : {
1468 9 : raw_erase(i);
1469 9 : ++n;
1470 : }
1471 : // go backwards to
1472 : // reduce memmoves
1473 27 : --i;
1474 : }
1475 9 : raw_erase(i0);
1476 9 : return n;
1477 : }
1478 :
1479 : // return i-th field absolute offset
1480 : std::size_t
1481 770 : fields_base::
1482 : offset(
1483 : std::size_t i) const noexcept
1484 : {
1485 770 : if(i == 0)
1486 308 : return h_.prefix;
1487 462 : if(i < h_.count)
1488 219 : return h_.prefix + h_.tab()[i].np;
1489 : // make final CRLF the last "field"
1490 243 : return h_.size - 2;
1491 : }
1492 :
1493 : // return i-th field absolute length
1494 : std::size_t
1495 39 : fields_base::
1496 : length(
1497 : std::size_t i) const noexcept
1498 : {
1499 : return
1500 39 : offset(i + 1) -
1501 39 : offset(i);
1502 : }
1503 :
1504 : } // http_proto
1505 : } // boost
|