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