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