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