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