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