TLA Line data Source code
1 : //
2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2024 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 "src/rfc/detail/rules.hpp"
12 : #include "src/rfc/detail/transfer_coding_rule.hpp"
13 :
14 : #include <boost/http/detail/header.hpp>
15 : #include <boost/http/field.hpp>
16 : #include <boost/http/header_limits.hpp>
17 : #include <boost/http/rfc/list_rule.hpp>
18 : #include <boost/http/rfc/token_rule.hpp>
19 : #include <boost/http/rfc/upgrade_rule.hpp>
20 : #include <boost/assert.hpp>
21 : #include <boost/assert/source_location.hpp>
22 : #include <boost/static_assert.hpp>
23 : #include <boost/url/grammar/ci_string.hpp>
24 : #include <boost/url/grammar/parse.hpp>
25 : #include <boost/url/grammar/range_rule.hpp>
26 : #include <boost/url/grammar/recycled.hpp>
27 : #include <boost/url/grammar/unsigned_rule.hpp>
28 :
29 : #include <utility>
30 :
31 : namespace boost {
32 : namespace http {
33 : namespace detail {
34 :
35 : //------------------------------------------------
36 :
37 : auto
38 HIT 87 : header::
39 : entry::
40 : operator+(
41 : std::size_t dv) const noexcept ->
42 : entry
43 : {
44 : return {
45 : static_cast<
46 87 : offset_type>(np + dv),
47 87 : nn,
48 : static_cast<
49 87 : offset_type>(vp + dv),
50 87 : vn,
51 87 : id };
52 : }
53 :
54 : auto
55 101 : header::
56 : entry::
57 : operator-(
58 : std::size_t dv) const noexcept ->
59 : entry
60 : {
61 : return {
62 : static_cast<
63 101 : offset_type>(np - dv),
64 101 : nn,
65 : static_cast<
66 101 : offset_type>(vp - dv),
67 101 : vn,
68 101 : id };
69 : }
70 :
71 : //------------------------------------------------
72 :
73 : constexpr field header::unknown_field;
74 :
75 : //------------------------------------------------
76 :
77 15 : header::
78 15 : header(fields_tag) noexcept
79 15 : : kind(detail::kind::fields)
80 15 : , cbuf("\r\n")
81 15 : , size(2)
82 15 : , fld{}
83 : {
84 15 : }
85 :
86 15 : header::
87 15 : header(request_tag) noexcept
88 15 : : kind(detail::kind::request)
89 15 : , cbuf("GET / HTTP/1.1\r\n\r\n")
90 15 : , size(18)
91 15 : , prefix(16)
92 15 : , req{ 3, 1,
93 15 : http::method::get }
94 : {
95 15 : }
96 :
97 15 : header::
98 15 : header(response_tag) noexcept
99 15 : : kind(detail::kind::response)
100 15 : , cbuf("HTTP/1.1 200 OK\r\n\r\n")
101 15 : , size(19)
102 15 : , prefix(17)
103 15 : , res{ 200,
104 15 : http::status::ok }
105 : {
106 15 : }
107 :
108 : //------------------------------------------------
109 :
110 : header const*
111 4872 : header::
112 : get_default(detail::kind k) noexcept
113 : {
114 : static header const h[3] = {
115 : fields_tag{},
116 : request_tag{},
117 4872 : response_tag{}};
118 4872 : return &h[k];
119 : }
120 :
121 13370 : header::
122 13370 : header(empty v) noexcept
123 13370 : : kind(v.param)
124 : {
125 13370 : }
126 :
127 2679 : header::
128 2679 : header(detail::kind k) noexcept
129 2679 : : header(*get_default(k))
130 : {
131 2679 : }
132 :
133 : void
134 79 : header::
135 : swap(header& h) noexcept
136 : {
137 79 : std::swap(cbuf, h.cbuf);
138 79 : std::swap(buf, h.buf);
139 79 : std::swap(cap, h.cap);
140 79 : std::swap(size, h.size);
141 79 : std::swap(count, h.count);
142 79 : std::swap(prefix, h.prefix);
143 79 : std::swap(version, h.version);
144 79 : std::swap(md, h.md);
145 79 : switch(kind)
146 : {
147 15 : default:
148 : case detail::kind::fields:
149 15 : break;
150 56 : case detail::kind::request:
151 56 : std::swap(
152 56 : req.method_len, h.req.method_len);
153 56 : std::swap(
154 56 : req.target_len, h.req.target_len);
155 56 : std::swap(req.method, h.req.method);
156 56 : break;
157 8 : case detail::kind::response:
158 8 : std::swap(
159 8 : res.status_int, h.res.status_int);
160 8 : std::swap(res.status, h.res.status);
161 8 : break;
162 : }
163 79 : }
164 :
165 : /* References:
166 :
167 : 6.3. Persistence
168 : https://datatracker.ietf.org/doc/html/rfc7230#section-6.3
169 : */
170 : bool
171 24 : header::
172 : keep_alive() const noexcept
173 : {
174 24 : if(md.payload == payload::error)
175 1 : return false;
176 23 : if( version ==
177 : http::version::http_1_1)
178 : {
179 15 : if(md.connection.close)
180 5 : return false;
181 : }
182 : else
183 : {
184 8 : if(! md.connection.keep_alive)
185 4 : return false;
186 : }
187 : // can't use to_eof in requests
188 14 : BOOST_ASSERT(
189 : kind != detail::kind::request ||
190 : md.payload != payload::to_eof);
191 14 : if(md.payload == payload::to_eof)
192 3 : return false;
193 11 : return true;
194 : }
195 :
196 : //------------------------------------------------
197 :
198 : // return total bytes needed
199 : // to store message of `size`
200 : // bytes and `count` fields.
201 : std::size_t
202 3156 : header::
203 : bytes_needed(
204 : std::size_t size,
205 : std::size_t count) noexcept
206 : {
207 : // make sure `size` is big enough
208 : // to hold the largest default buffer:
209 : // "HTTP/1.1 200 OK\r\n\r\n"
210 3156 : if(size < 19)
211 2388 : size = 19;
212 :
213 : // align size up to alignof(entry)
214 3156 : size = (size + alignof(entry) - 1) & ~(alignof(entry) - 1);
215 :
216 3156 : return size + count * sizeof(entry);
217 : }
218 :
219 : std::size_t
220 9585 : header::
221 : table_space(
222 : std::size_t count) noexcept
223 : {
224 : return count *
225 9585 : sizeof(header::entry);
226 : }
227 :
228 : std::size_t
229 9585 : header::
230 : table_space() const noexcept
231 : {
232 9585 : return table_space(count);
233 : }
234 :
235 : auto
236 2669 : header::
237 : tab() const noexcept ->
238 : table
239 : {
240 2669 : BOOST_ASSERT(cap > 0);
241 2669 : BOOST_ASSERT(buf != nullptr);
242 2669 : return table(buf + cap);
243 : }
244 :
245 : auto
246 680 : header::
247 : tab_() const noexcept ->
248 : entry*
249 : {
250 : return reinterpret_cast<
251 680 : entry*>(buf + cap);
252 : }
253 :
254 : // return true if header cbuf is a default
255 : bool
256 45 : header::
257 : is_default() const noexcept
258 : {
259 45 : return buf == nullptr;
260 : }
261 :
262 : std::size_t
263 135 : header::
264 : find(
265 : field id) const noexcept
266 : {
267 135 : if(count == 0)
268 64 : return 0;
269 71 : std::size_t i = 0;
270 71 : auto const* p = &tab()[0];
271 118 : while(i < count)
272 : {
273 95 : if(p->id == id)
274 48 : break;
275 47 : ++i;
276 47 : --p;
277 : }
278 71 : return i;
279 : }
280 :
281 : std::size_t
282 42 : header::
283 : find(
284 : core::string_view name) const noexcept
285 : {
286 42 : if(count == 0)
287 6 : return 0;
288 36 : std::size_t i = 0;
289 36 : auto const* p = &tab()[0];
290 57 : while(i < count)
291 : {
292 : core::string_view s(
293 54 : cbuf + prefix + p->np,
294 54 : p->nn);
295 54 : if(grammar::ci_is_equal(s, name))
296 33 : break;
297 21 : ++i;
298 21 : --p;
299 : }
300 36 : return i;
301 : }
302 :
303 : void
304 2267 : header::
305 : copy_table(
306 : void* dest,
307 : std::size_t n) const noexcept
308 : {
309 : // When `n == 0`, cbuf + cap may have incorrect
310 : // alignment, which can trigger UB sanitizer.
311 2267 : if(n == 0)
312 2246 : return;
313 :
314 21 : std::memcpy(
315 : reinterpret_cast<
316 21 : entry*>(dest) - n,
317 : reinterpret_cast<
318 : entry const*>(
319 21 : cbuf + cap) - n,
320 : n * sizeof(entry));
321 : }
322 :
323 : void
324 2267 : header::
325 : copy_table(
326 : void* dest) const noexcept
327 : {
328 2267 : copy_table(dest, count);
329 2267 : }
330 :
331 : // assign all the members but
332 : // preserve the allocated memory
333 : void
334 2217 : header::
335 : assign_to(
336 : header& dest) const noexcept
337 : {
338 2217 : auto const buf_ = dest.buf;
339 2217 : auto const cbuf_ = dest.cbuf;
340 2217 : auto const cap_ = dest.cap;
341 2217 : dest = *this;
342 2217 : dest.buf = buf_;
343 2217 : dest.cbuf = cbuf_;
344 2217 : dest.cap = cap_;
345 2217 : }
346 :
347 : //------------------------------------------------
348 : //
349 : // Metadata
350 : //
351 : //------------------------------------------------
352 :
353 : std::size_t
354 MIS 0 : header::
355 : maybe_count(
356 : field id) const noexcept
357 : {
358 0 : if(kind == detail::kind::fields)
359 0 : return std::size_t(-1);
360 0 : switch(id)
361 : {
362 0 : case field::connection:
363 0 : return md.connection.count;
364 0 : case field::content_encoding:
365 0 : return md.content_encoding.count;
366 0 : case field::content_length:
367 0 : return md.content_length.count;
368 0 : case field::expect:
369 0 : return md.expect.count;
370 0 : case field::transfer_encoding:
371 0 : return md.transfer_encoding.count;
372 0 : case field::upgrade:
373 0 : return md.upgrade.count;
374 0 : default:
375 0 : break;
376 : }
377 0 : return std::size_t(-1);
378 : }
379 :
380 : bool
381 HIT 24 : header::
382 : is_special(
383 : field id) const noexcept
384 : {
385 24 : if(kind == detail::kind::fields)
386 5 : return false;
387 19 : switch(id)
388 : {
389 9 : case field::connection:
390 : case field::content_encoding:
391 : case field::content_length:
392 : case field::expect:
393 : case field::transfer_encoding:
394 : case field::upgrade:
395 9 : return true;
396 10 : default:
397 10 : break;
398 : }
399 10 : return false;
400 : }
401 :
402 : //------------------------------------------------
403 :
404 : // called when the start-line changes
405 : void
406 10668 : header::
407 : on_start_line()
408 : {
409 : // items in both the request-line
410 : // and the status-line can affect
411 : // the payload, for example whether
412 : // or not EOF marks the end of the
413 : // payload.
414 :
415 10668 : update_payload();
416 10668 : }
417 :
418 : // called after a field is inserted
419 : void
420 11031 : header::
421 : on_insert(
422 : field id,
423 : core::string_view v)
424 : {
425 11031 : if(kind == detail::kind::fields)
426 482 : return;
427 10549 : switch(id)
428 : {
429 7 : case field::content_encoding:
430 7 : return on_insert_content_encoding(v);
431 4557 : case field::content_length:
432 4557 : return on_insert_content_length(v);
433 141 : case field::connection:
434 141 : return on_insert_connection(v);
435 47 : case field::expect:
436 47 : return on_insert_expect(v);
437 4413 : case field::transfer_encoding:
438 4413 : return on_insert_transfer_encoding(v);
439 24 : case field::upgrade:
440 24 : return on_insert_upgrade(v);
441 1360 : default:
442 1360 : break;
443 : }
444 : }
445 :
446 : // called when one field is erased
447 : void
448 39 : header::
449 : on_erase(field id)
450 : {
451 39 : if(kind == detail::kind::fields)
452 3 : return;
453 36 : switch(id)
454 : {
455 9 : case field::connection:
456 9 : return on_erase_connection();
457 MIS 0 : case field::content_encoding:
458 0 : return on_erase_content_encoding();
459 HIT 4 : case field::content_length:
460 4 : return on_erase_content_length();
461 10 : case field::expect:
462 10 : return on_erase_expect();
463 4 : case field::transfer_encoding:
464 4 : return on_erase_transfer_encoding();
465 4 : case field::upgrade:
466 4 : return on_erase_upgrade();
467 5 : default:
468 5 : break;
469 : }
470 : }
471 :
472 : //------------------------------------------------
473 :
474 : /*
475 : https://datatracker.ietf.org/doc/html/rfc7230#section-6.1
476 : */
477 : void
478 148 : header::
479 : on_insert_connection(
480 : core::string_view v)
481 : {
482 148 : ++md.connection.count;
483 148 : if(md.connection.ec)
484 5 : return;
485 : auto rv = grammar::parse(
486 147 : v, list_rule(token_rule, 1));
487 147 : if(! rv)
488 : {
489 4 : md.connection.ec =
490 : error::bad_connection;
491 4 : return;
492 : }
493 143 : md.connection.ec = {};
494 297 : for(auto t : *rv)
495 : {
496 154 : if(grammar::ci_is_equal(
497 : t, "close"))
498 99 : md.connection.close = true;
499 55 : else if(grammar::ci_is_equal(
500 : t, "keep-alive"))
501 28 : md.connection.keep_alive = true;
502 27 : else if(grammar::ci_is_equal(
503 : t, "upgrade"))
504 20 : md.connection.upgrade = true;
505 : }
506 147 : }
507 :
508 : void
509 4558 : header::
510 : on_insert_content_length(
511 : core::string_view v)
512 : {
513 : static
514 : constexpr
515 : grammar::unsigned_rule<
516 : std::uint64_t> num_rule{};
517 :
518 4558 : ++md.content_length.count;
519 4558 : if(md.content_length.ec)
520 4495 : return;
521 : auto rv =
522 4556 : grammar::parse(v, num_rule);
523 4556 : if(! rv)
524 : {
525 : // parse failure
526 5 : md.content_length.ec =
527 : error::bad_content_length;
528 5 : md.content_length.value = 0;
529 5 : update_payload();
530 5 : return;
531 : }
532 4551 : if(md.content_length.count == 1)
533 : {
534 : // one value
535 4481 : md.content_length.ec = {};
536 4481 : md.content_length.value = *rv;
537 4481 : update_payload();
538 4481 : return;
539 : }
540 70 : if(*rv == md.content_length.value)
541 : {
542 : // ok: duplicate value
543 7 : return;
544 : }
545 : // bad: different values
546 63 : md.content_length.ec =
547 : error::multiple_content_length;
548 63 : md.content_length.value = 0;
549 63 : update_payload();
550 : }
551 :
552 : void
553 53 : header::
554 : on_insert_expect(
555 : core::string_view v)
556 : {
557 53 : ++md.expect.count;
558 53 : if(kind != detail::kind::request)
559 8 : return;
560 45 : if(md.expect.ec)
561 4 : return;
562 : // VFALCO Should we allow duplicate
563 : // Expect fields that have 100-continue?
564 73 : if( md.expect.count > 1 ||
565 73 : ! grammar::ci_is_equal(v,
566 : "100-continue"))
567 : {
568 19 : md.expect.ec =
569 : error::bad_expect;
570 19 : md.expect.is_100_continue = false;
571 19 : return;
572 : }
573 22 : md.expect.is_100_continue = true;
574 : }
575 :
576 : void
577 4415 : header::
578 : on_insert_transfer_encoding(
579 : core::string_view v)
580 : {
581 4415 : ++md.transfer_encoding.count;
582 4415 : if(md.transfer_encoding.ec)
583 4407 : return;
584 :
585 : auto rv = grammar::parse(
586 4414 : v, list_rule(transfer_coding_rule, 1));
587 4414 : if(! rv)
588 : {
589 : // parse error
590 4 : goto error;
591 : }
592 8823 : for(auto t : *rv)
593 : {
594 4417 : if(! md.transfer_encoding.is_chunked)
595 : {
596 4413 : if(t.id == transfer_coding_rule_t::chunked)
597 4394 : md.transfer_encoding.is_chunked = true;
598 4413 : continue;
599 : }
600 4 : if(t.id == transfer_coding_rule_t::chunked)
601 : {
602 : // chunked appears twice
603 2 : goto error;
604 : }
605 : // chunked must be last
606 2 : goto error;
607 8831 : }
608 4406 : update_payload();
609 4406 : return;
610 :
611 8 : error:
612 8 : md.transfer_encoding.ec =
613 : error::bad_transfer_encoding;
614 8 : md.transfer_encoding.is_chunked = false;
615 8 : update_payload();
616 4414 : }
617 :
618 : void
619 7 : header::
620 : on_insert_content_encoding(
621 : core::string_view v)
622 : {
623 7 : ++md.content_encoding.count;
624 7 : if(md.content_encoding.ec)
625 3 : return;
626 :
627 : auto rv = grammar::parse(
628 7 : v, list_rule(token_rule, 1));
629 7 : if(!rv)
630 : {
631 1 : md.content_encoding.ec =
632 : error::bad_content_encoding;
633 1 : md.content_encoding.coding =
634 : content_coding::unknown;
635 1 : return;
636 : }
637 :
638 6 : if(rv->size() > 1 || md.content_encoding.count > 1)
639 : {
640 2 : md.content_encoding.coding =
641 : content_coding::unknown;
642 2 : return;
643 : }
644 :
645 8 : if(grammar::ci_is_equal(
646 8 : *rv->begin(), "deflate"))
647 : {
648 MIS 0 : md.content_encoding.coding =
649 : content_coding::deflate;
650 : }
651 HIT 8 : else if(grammar::ci_is_equal(
652 8 : *rv->begin(), "gzip"))
653 : {
654 2 : md.content_encoding.coding =
655 : content_coding::gzip;
656 : }
657 4 : else if(grammar::ci_is_equal(
658 4 : *rv->begin(), "br"))
659 : {
660 1 : md.content_encoding.coding =
661 : content_coding::br;
662 : }
663 2 : else if(grammar::ci_is_equal(
664 2 : *rv->begin(), "zstd"))
665 : {
666 1 : md.content_encoding.coding =
667 : content_coding::zstd;
668 : }
669 : else
670 : {
671 MIS 0 : md.content_encoding.coding =
672 : content_coding::unknown;
673 : }
674 HIT 7 : }
675 :
676 : void
677 26 : header::
678 : on_insert_upgrade(
679 : core::string_view v)
680 : {
681 26 : ++md.upgrade.count;
682 26 : if(md.upgrade.ec)
683 5 : return;
684 25 : if( version !=
685 : http::version::http_1_1)
686 : {
687 1 : md.upgrade.ec =
688 : error::bad_upgrade;
689 1 : md.upgrade.websocket = false;
690 1 : return;
691 : }
692 : auto rv = grammar::parse(
693 24 : v, upgrade_rule);
694 24 : if(! rv)
695 : {
696 3 : md.upgrade.ec =
697 : error::bad_upgrade;
698 3 : md.upgrade.websocket = false;
699 3 : return;
700 : }
701 21 : if(! md.upgrade.websocket)
702 : {
703 23 : for(auto t : *rv)
704 : {
705 16 : if( grammar::ci_is_equal(
706 26 : t.name, "websocket") &&
707 10 : t.version.empty())
708 : {
709 9 : md.upgrade.websocket = true;
710 9 : break;
711 : }
712 : }
713 : }
714 24 : }
715 :
716 : //------------------------------------------------
717 :
718 : void
719 9 : header::
720 : on_erase_connection()
721 : {
722 9 : BOOST_ASSERT(
723 : md.connection.count > 0);
724 : // reset and re-insert
725 9 : auto n = md.connection.count - 1;
726 9 : auto const p = cbuf + prefix;
727 9 : auto const* e = &tab()[0];
728 9 : md.connection = {};
729 17 : while(n > 0)
730 : {
731 8 : if(e->id == field::connection)
732 : {
733 7 : on_insert_connection(
734 : core::string_view(
735 7 : p + e->vp, e->vn));
736 7 : --n;
737 : }
738 8 : --e;
739 : }
740 9 : }
741 :
742 : void
743 4 : header::
744 : on_erase_content_length()
745 : {
746 4 : BOOST_ASSERT(
747 : md.content_length.count > 0);
748 4 : --md.content_length.count;
749 4 : if(md.content_length.count == 0)
750 : {
751 : // no Content-Length
752 1 : md.content_length = {};
753 1 : update_payload();
754 1 : return;
755 : }
756 3 : if(! md.content_length.ec)
757 : {
758 : // removing a duplicate value
759 2 : return;
760 : }
761 : // reset and re-insert
762 1 : auto n = md.content_length.count;
763 1 : auto const p = cbuf + prefix;
764 1 : auto const* e = &tab()[0];
765 1 : md.content_length = {};
766 2 : while(n > 0)
767 : {
768 1 : if(e->id == field::content_length)
769 : {
770 1 : on_insert_content_length(
771 : core::string_view(
772 1 : p + e->vp, e->vn));
773 1 : --n;
774 : }
775 1 : --e;
776 : }
777 1 : update_payload();
778 : }
779 :
780 : void
781 10 : header::
782 : on_erase_expect()
783 : {
784 10 : BOOST_ASSERT(
785 : md.expect.count > 0);
786 10 : --md.expect.count;
787 10 : if(kind != detail::kind::request)
788 1 : return;
789 9 : if(md.expect.count == 0)
790 : {
791 : // no Expect
792 3 : md.expect = {};
793 3 : return;
794 : }
795 : // VFALCO This should be uncommented
796 : // if we want to allow multiple Expect
797 : // fields with the value 100-continue
798 : /*
799 : if(! md.expect.ec)
800 : return;
801 : */
802 : // reset and re-insert
803 6 : auto n = md.expect.count;
804 6 : auto const p = cbuf + prefix;
805 6 : auto const* e = &tab()[0];
806 6 : md.expect = {};
807 18 : while(n > 0)
808 : {
809 12 : if(e->id == field::expect)
810 : {
811 6 : on_insert_expect(
812 : core::string_view(
813 6 : p + e->vp, e->vn));
814 6 : --n;
815 : }
816 12 : --e;
817 : }
818 : }
819 :
820 : void
821 4 : header::
822 : on_erase_transfer_encoding()
823 : {
824 4 : BOOST_ASSERT(
825 : md.transfer_encoding.count > 0);
826 : // reset and re-insert
827 4 : auto n = md.transfer_encoding.count - 1;
828 4 : auto const p = cbuf + prefix;
829 4 : auto const* e = &tab()[0];
830 4 : md.transfer_encoding = {};
831 7 : while(n > 0)
832 : {
833 3 : if(e->id == field::transfer_encoding)
834 : {
835 2 : on_insert_transfer_encoding(
836 : core::string_view(
837 2 : p + e->vp, e->vn));
838 2 : --n;
839 : }
840 3 : --e;
841 : }
842 4 : }
843 :
844 : void
845 MIS 0 : header::
846 : on_erase_content_encoding()
847 : {
848 0 : BOOST_ASSERT(
849 : md.content_encoding.count > 0);
850 0 : --md.content_encoding.count;
851 0 : if(md.content_encoding.count == 0)
852 : {
853 : // no Content-Encoding
854 0 : md.content_encoding = {};
855 0 : return;
856 : }
857 : // re-insert everything
858 0 : --md.content_encoding.count;
859 : // TODO
860 : // on_insert_content_encoding();
861 : }
862 :
863 : // called when Upgrade is erased
864 : void
865 HIT 4 : header::
866 : on_erase_upgrade()
867 : {
868 4 : BOOST_ASSERT(
869 : md.upgrade.count > 0);
870 4 : --md.upgrade.count;
871 4 : if(md.upgrade.count == 0)
872 : {
873 : // no Upgrade
874 2 : md.upgrade = {};
875 2 : return;
876 : }
877 : // reset and re-insert
878 2 : auto n = md.upgrade.count;
879 2 : auto const p = cbuf + prefix;
880 2 : auto const* e = &tab()[0];
881 2 : md.upgrade = {};
882 4 : while(n > 0)
883 : {
884 2 : if(e->id == field::upgrade)
885 2 : on_insert_upgrade(
886 : core::string_view(
887 2 : p + e->vp, e->vn));
888 2 : --n;
889 2 : --e;
890 : }
891 : }
892 :
893 : //------------------------------------------------
894 :
895 : // called when all fields with id are removed
896 : void
897 72 : header::
898 : on_erase_all(
899 : field id)
900 : {
901 72 : if(kind == detail::kind::fields)
902 21 : return;
903 51 : switch(id)
904 : {
905 3 : case field::connection:
906 3 : md.connection = {};
907 3 : return;
908 :
909 2 : case field::content_length:
910 2 : md.content_length = {};
911 2 : update_payload();
912 2 : return;
913 :
914 5 : case field::expect:
915 5 : md.expect = {};
916 5 : update_payload();
917 5 : return;
918 :
919 1 : case field::transfer_encoding:
920 1 : md.transfer_encoding = {};
921 1 : update_payload();
922 1 : return;
923 :
924 1 : case field::upgrade:
925 1 : md.upgrade = {};
926 1 : return;
927 :
928 39 : default:
929 39 : break;
930 : }
931 : }
932 :
933 : //------------------------------------------------
934 :
935 : /* References:
936 :
937 : 3.3. Message Body
938 : https://datatracker.ietf.org/doc/html/rfc7230#section-3.3
939 :
940 : 3.3.1. Transfer-Encoding
941 : https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.1
942 :
943 : 3.3.2. Content-Length
944 : https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
945 : */
946 : void
947 19641 : header::
948 : update_payload() noexcept
949 : {
950 19641 : BOOST_ASSERT(kind !=
951 : detail::kind::fields);
952 19641 : if(md.payload_override)
953 : {
954 : // e.g. response to
955 : // a HEAD request
956 MIS 0 : return;
957 : }
958 :
959 : /* If there is an error in either Content-Length
960 : or Transfer-Encoding, then the payload is
961 : undefined. Clients should probably close the
962 : connection. Servers can send a Bad Request
963 : and avoid reading any payload bytes.
964 : */
965 HIT 19641 : if(md.content_length.ec)
966 : {
967 : // invalid Content-Length
968 68 : md.payload = payload::error;
969 68 : md.payload_size = 0;
970 68 : return;
971 : }
972 19573 : if(md.transfer_encoding.ec)
973 : {
974 : // invalid Transfer-Encoding
975 8 : md.payload = payload::error;
976 8 : md.payload_size = 0;
977 8 : return;
978 : }
979 :
980 : /* A sender MUST NOT send a Content-Length
981 : header field in any message that contains
982 : a Transfer-Encoding header field.
983 : https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
984 : */
985 19565 : if( md.content_length.count > 0 &&
986 4485 : md.transfer_encoding.count > 0)
987 : {
988 3 : md.payload = payload::error;
989 3 : md.payload_size = 0;
990 3 : return;
991 : }
992 :
993 19562 : if(kind == detail::kind::response)
994 1924 : goto do_response;
995 :
996 : //--------------------------------------------
997 :
998 : /* The presence of a message body in a
999 : request is signaled by a Content-Length
1000 : or Transfer-Encoding header field. Request
1001 : message framing is independent of method
1002 : semantics, even if the method does not
1003 : define any use for a message body.
1004 : */
1005 17638 : if(md.content_length.count > 0)
1006 : {
1007 4177 : if(md.content_length.value > 0)
1008 : {
1009 : // non-zero Content-Length
1010 4150 : md.payload = payload::size;
1011 4150 : md.payload_size = md.content_length.value;
1012 4150 : return;
1013 : }
1014 : // Content-Length: 0
1015 27 : md.payload = payload::none;
1016 27 : md.payload_size = 0;
1017 27 : return;
1018 : }
1019 13461 : if(md.transfer_encoding.is_chunked)
1020 : {
1021 : // chunked
1022 4012 : md.payload = payload::chunked;
1023 4012 : md.payload_size = 0;
1024 4012 : return;
1025 : }
1026 : // no payload
1027 9449 : md.payload = payload::none;
1028 9449 : md.payload_size = 0;
1029 9449 : return;
1030 :
1031 : //--------------------------------------------
1032 1924 : do_response:
1033 :
1034 1924 : if( res.status_int / 100 == 1 || // 1xx e.g. Continue
1035 1913 : res.status_int == 204 || // No Content
1036 1910 : res.status_int == 304) // Not Modified
1037 : {
1038 : /* The correctness of any Content-Length
1039 : here is defined by the particular
1040 : resource, and cannot be determined
1041 : here. In any case there is no payload.
1042 : */
1043 16 : md.payload = payload::none;
1044 16 : md.payload_size = 0;
1045 16 : return;
1046 : }
1047 1908 : if(md.content_length.count > 0)
1048 : {
1049 302 : if(md.content_length.value > 0)
1050 : {
1051 : // Content-Length > 0
1052 283 : md.payload = payload::size;
1053 283 : md.payload_size = md.content_length.value;
1054 283 : return;
1055 : }
1056 : // Content-Length: 0
1057 19 : md.payload = payload::none;
1058 19 : md.payload_size = 0;
1059 19 : return;
1060 : }
1061 1606 : if(md.transfer_encoding.is_chunked)
1062 : {
1063 : // chunked
1064 377 : md.payload = payload::chunked;
1065 377 : md.payload_size = 0;
1066 377 : return;
1067 : }
1068 :
1069 : // eof needed
1070 1229 : md.payload = payload::to_eof;
1071 1229 : md.payload_size = 0;
1072 : }
1073 :
1074 : //------------------------------------------------
1075 :
1076 : std::size_t
1077 549 : header::
1078 : count_crlf(
1079 : core::string_view s) noexcept
1080 : {
1081 549 : auto it = s.data();
1082 549 : auto len = s.size();
1083 549 : std::size_t n = 0;
1084 19120 : while(len >= 2)
1085 : {
1086 18571 : if( it[0] == '\r' &&
1087 1749 : it[1] != '\r')
1088 : {
1089 1749 : if(it[1] == '\n')
1090 1749 : n++;
1091 1749 : it += 2;
1092 1749 : len -= 2;
1093 : }
1094 : else
1095 : {
1096 16822 : it++;
1097 16822 : len--;
1098 : }
1099 : }
1100 549 : return n;
1101 : }
1102 :
1103 : static
1104 : void
1105 29145 : parse_start_line(
1106 : header& h,
1107 : header_limits const& lim,
1108 : std::size_t new_size,
1109 : std::error_code& ec) noexcept
1110 : {
1111 29145 : BOOST_ASSERT(h.size == 0);
1112 29145 : BOOST_ASSERT(h.prefix == 0);
1113 29145 : BOOST_ASSERT(h.cbuf != nullptr);
1114 29145 : BOOST_ASSERT(
1115 : h.kind != detail::kind::fields);
1116 :
1117 29145 : auto const it0 = h.cbuf;
1118 29145 : auto const end = it0 + new_size;
1119 29145 : char const* it = it0;
1120 29145 : if( new_size > lim.max_start_line)
1121 10 : new_size = lim.max_start_line;
1122 29145 : if(h.kind == detail::kind::request)
1123 : {
1124 : auto rv = grammar::parse(
1125 11375 : it, end, request_line_rule);
1126 11375 : if(! rv)
1127 : {
1128 1991 : ec = rv.error();
1129 3982 : if( ec == system::error_code(grammar::error::need_more) &&
1130 1991 : new_size == lim.max_start_line)
1131 MIS 0 : ec = error::start_line_limit;
1132 HIT 1991 : return;
1133 : }
1134 : // method
1135 9384 : auto sm = std::get<0>(*rv);
1136 9384 : h.req.method = string_to_method(sm);
1137 9384 : h.req.method_len =
1138 9384 : static_cast<header::offset_type>(sm.size());
1139 : // target
1140 9384 : auto st = std::get<1>(*rv);
1141 9384 : h.req.target_len =
1142 9384 : static_cast<header::offset_type>(st.size());
1143 : // version
1144 9384 : switch(std::get<2>(*rv))
1145 : {
1146 25 : case 10:
1147 25 : h.version =
1148 : http::version::http_1_0;
1149 25 : break;
1150 9359 : case 11:
1151 9359 : h.version =
1152 : http::version::http_1_1;
1153 9359 : break;
1154 MIS 0 : default:
1155 : {
1156 0 : ec = error::bad_version;
1157 0 : return;
1158 : }
1159 : }
1160 : }
1161 : else
1162 : {
1163 : auto rv = grammar::parse(
1164 HIT 17770 : it, end, status_line_rule);
1165 17770 : if(! rv)
1166 : {
1167 16554 : ec = rv.error();
1168 33108 : if( ec == system::error_code(grammar::error::need_more) &&
1169 16554 : new_size == lim.max_start_line)
1170 MIS 0 : ec = error::start_line_limit;
1171 HIT 16554 : return;
1172 : }
1173 : // version
1174 1216 : switch(std::get<0>(*rv))
1175 : {
1176 4 : case 10:
1177 4 : h.version =
1178 : http::version::http_1_0;
1179 4 : break;
1180 1212 : case 11:
1181 1212 : h.version =
1182 : http::version::http_1_1;
1183 1212 : break;
1184 MIS 0 : default:
1185 : {
1186 0 : ec = error::bad_version;
1187 0 : return;
1188 : }
1189 : }
1190 : // status-code
1191 HIT 1216 : h.res.status_int =
1192 : static_cast<unsigned short>(
1193 1216 : std::get<1>(*rv).v);
1194 1216 : h.res.status = std::get<1>(*rv).st;
1195 : }
1196 10600 : h.prefix = static_cast<header::offset_type>(it - it0);
1197 10600 : h.size = h.prefix;
1198 10600 : h.on_start_line();
1199 : }
1200 :
1201 : // returns: true if we added a field
1202 : static
1203 : void
1204 37744 : parse_field(
1205 : header& h,
1206 : header_limits const& lim,
1207 : std::size_t new_size,
1208 : std::error_code& ec) noexcept
1209 : {
1210 37744 : if( new_size > lim.max_field)
1211 20 : new_size = lim.max_field;
1212 37744 : auto const it0 = h.cbuf + h.size;
1213 37744 : auto const end = h.cbuf + new_size;
1214 37744 : char const* it = it0;
1215 37744 : auto rv = grammar::parse(
1216 : it, end, field_rule);
1217 37744 : if(rv.has_error())
1218 : {
1219 27030 : ec = rv.error();
1220 27030 : if(ec == system::error_code(grammar::error::end_of_range))
1221 : {
1222 : // final CRLF
1223 10131 : h.size = static_cast<
1224 10131 : header::offset_type>(it - h.cbuf);
1225 27030 : return;
1226 : }
1227 33539 : if( ec == system::error_code(grammar::error::need_more) &&
1228 16640 : new_size == lim.max_field)
1229 : {
1230 MIS 0 : ec = error::field_size_limit;
1231 : }
1232 HIT 16899 : return;
1233 : }
1234 10714 : if(h.count >= lim.max_fields)
1235 : {
1236 MIS 0 : ec = error::fields_limit;
1237 0 : return;
1238 : }
1239 HIT 10714 : if(rv->has_obs_fold)
1240 : {
1241 : // obs fold not allowed in test views
1242 210 : BOOST_ASSERT(h.buf != nullptr);
1243 210 : remove_obs_fold(h.buf + h.size, it);
1244 : }
1245 10714 : auto id = string_to_field(rv->name)
1246 10714 : .value_or(header::unknown_field);
1247 10714 : h.size = static_cast<header::offset_type>(it - h.cbuf);
1248 :
1249 : // add field table entry
1250 10714 : if(h.buf != nullptr)
1251 : {
1252 21428 : auto& e = header::table(
1253 10714 : h.buf + h.cap)[h.count];
1254 10714 : auto const base =
1255 10714 : h.buf + h.prefix;
1256 10714 : e.np = static_cast<header::offset_type>(
1257 10714 : rv->name.data() - base);
1258 10714 : e.nn = static_cast<header::offset_type>(
1259 10714 : rv->name.size());
1260 10714 : e.vp = static_cast<header::offset_type>(
1261 10714 : rv->value.data() - base);
1262 10714 : e.vn = static_cast<header::offset_type>(
1263 10714 : rv->value.size());
1264 10714 : e.id = id;
1265 : }
1266 10714 : ++h.count;
1267 10714 : h.on_insert(id, rv->value);
1268 10714 : ec = {};
1269 : }
1270 :
1271 : void
1272 45575 : header::
1273 : parse(
1274 : std::size_t new_size,
1275 : header_limits const& lim,
1276 : std::error_code& ec) noexcept
1277 : {
1278 45575 : if( new_size > lim.max_size)
1279 10 : new_size = lim.max_size;
1280 45575 : if( this->prefix == 0 &&
1281 29379 : this->kind !=
1282 : detail::kind::fields)
1283 : {
1284 29145 : parse_start_line(
1285 : *this, lim, new_size, ec);
1286 29145 : if(ec)
1287 : {
1288 37090 : if( ec == system::error_code(grammar::error::need_more) &&
1289 18545 : new_size == lim.max_fields)
1290 : {
1291 MIS 0 : ec = error::headers_limit;
1292 : }
1293 HIT 18545 : return;
1294 : }
1295 : }
1296 : for(;;)
1297 : {
1298 37744 : parse_field(
1299 : *this, lim, new_size, ec);
1300 37744 : if(ec)
1301 : {
1302 43670 : if( ec == system::error_code(grammar::error::need_more) &&
1303 16640 : new_size == lim.max_size)
1304 : {
1305 MIS 0 : ec = error::headers_limit;
1306 0 : return;
1307 : }
1308 HIT 27030 : break;
1309 : }
1310 : }
1311 27030 : if(ec == system::error_code(grammar::error::end_of_range))
1312 10131 : ec = {};
1313 : }
1314 :
1315 : } // detail
1316 : } // http
1317 : } // boost
|