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/detail/align_up.hpp>
12 : #include <boost/http_proto/field.hpp>
13 : #include <boost/http_proto/fields_view_base.hpp>
14 : #include <boost/http_proto/header_limits.hpp>
15 : #include <boost/http_proto/rfc/list_rule.hpp>
16 : #include <boost/http_proto/rfc/token_rule.hpp>
17 : #include <boost/http_proto/rfc/transfer_encoding_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 : namespace boost {
32 : namespace http_proto {
33 : namespace detail {
34 :
35 : //------------------------------------------------
36 :
37 : auto
38 115 : header::
39 : entry::
40 : operator+(
41 : std::size_t dv) const noexcept ->
42 : entry
43 : {
44 : return {
45 : static_cast<
46 115 : offset_type>(np + dv),
47 115 : nn,
48 : static_cast<
49 115 : offset_type>(vp + dv),
50 115 : vn,
51 115 : id };
52 : }
53 :
54 : auto
55 79 : header::
56 : entry::
57 : operator-(
58 : std::size_t dv) const noexcept ->
59 : entry
60 : {
61 : return {
62 : static_cast<
63 79 : offset_type>(np - dv),
64 79 : nn,
65 : static_cast<
66 79 : offset_type>(vp - dv),
67 79 : vn,
68 79 : id };
69 : }
70 :
71 : //------------------------------------------------
72 :
73 : constexpr
74 : header::
75 : header(fields_tag) noexcept
76 : : kind(detail::kind::fields)
77 : , cbuf("\r\n")
78 : , size(2)
79 : , fld{}
80 : {
81 : }
82 :
83 : constexpr
84 : header::
85 : header(request_tag) noexcept
86 : : kind(detail::kind::request)
87 : , cbuf("GET / HTTP/1.1\r\n\r\n")
88 : , size(18)
89 : , prefix(16)
90 : , req{ 3, 1,
91 : http_proto::method::get }
92 : {
93 : }
94 :
95 : constexpr
96 : header::
97 : header(response_tag) noexcept
98 : : kind(detail::kind::response)
99 : , cbuf("HTTP/1.1 200 OK\r\n\r\n")
100 : , size(19)
101 : , prefix(17)
102 : , res{ 200,
103 : http_proto::status::ok }
104 : {
105 : }
106 :
107 : //------------------------------------------------
108 :
109 : header const*
110 201 : header::
111 : get_default(detail::kind k) noexcept
112 : {
113 : static constexpr header h[3] = {
114 : fields_tag{},
115 : request_tag{},
116 : response_tag{}};
117 201 : return &h[k];
118 : }
119 :
120 3315 : header::
121 3315 : header(empty v) noexcept
122 3315 : : kind(v.param)
123 : {
124 3315 : }
125 :
126 182 : header::
127 182 : header(detail::kind k) noexcept
128 182 : : header(*get_default(k))
129 : {
130 182 : }
131 :
132 : void
133 74 : header::
134 : swap(header& h) noexcept
135 : {
136 74 : std::swap(cbuf, h.cbuf);
137 74 : std::swap(buf, h.buf);
138 74 : std::swap(cap, h.cap);
139 74 : std::swap(max_cap, h.max_cap);
140 74 : std::swap(size, h.size);
141 74 : std::swap(count, h.count);
142 74 : std::swap(prefix, h.prefix);
143 74 : std::swap(version, h.version);
144 74 : std::swap(md, h.md);
145 74 : switch(kind)
146 : {
147 18 : default:
148 : case detail::kind::fields:
149 18 : break;
150 47 : case detail::kind::request:
151 47 : std::swap(
152 47 : req.method_len, h.req.method_len);
153 47 : std::swap(
154 47 : req.target_len, h.req.target_len);
155 47 : std::swap(req.method, h.req.method);
156 47 : break;
157 9 : case detail::kind::response:
158 9 : std::swap(
159 9 : res.status_int, h.res.status_int);
160 9 : std::swap(res.status, h.res.status);
161 9 : break;
162 : }
163 74 : }
164 :
165 : /* References:
166 :
167 : 6.3. Persistence
168 : https://datatracker.ietf.org/doc/html/rfc7230#section-6.3
169 : */
170 : bool
171 22 : header::
172 : keep_alive() const noexcept
173 : {
174 22 : if(md.payload == payload::error)
175 1 : return false;
176 21 : if( version ==
177 : http_proto::version::http_1_1)
178 : {
179 13 : if(md.connection.close)
180 3 : return false;
181 : }
182 : else
183 : {
184 8 : if(! md.connection.keep_alive)
185 4 : return false;
186 : }
187 : // can't use to_eof in requests
188 14 : BOOST_ASSERT(
189 : kind != detail::kind::request ||
190 : md.payload != payload::to_eof);
191 14 : if(md.payload == payload::to_eof)
192 3 : return false;
193 11 : return true;
194 : }
195 :
196 : //------------------------------------------------
197 :
198 : // return total bytes needed
199 : // to store message of `size`
200 : // bytes and `count` fields.
201 : std::size_t
202 833 : header::
203 : bytes_needed(
204 : std::size_t size,
205 : std::size_t count) noexcept
206 : {
207 : // make sure `size` is big enough
208 : // to hold the largest default buffer:
209 : // "HTTP/1.1 200 OK\r\n\r\n"
210 833 : if( size < 19)
211 172 : size = 19;
212 : static constexpr auto A =
213 : alignof(header::entry);
214 833 : return align_up(size, A) +
215 833 : (count * sizeof(
216 833 : header::entry));
217 : }
218 :
219 : std::size_t
220 1329 : header::
221 : table_space(
222 : std::size_t count) noexcept
223 : {
224 : return count *
225 1329 : sizeof(header::entry);
226 : }
227 :
228 : std::size_t
229 1329 : header::
230 : table_space() const noexcept
231 : {
232 1329 : return table_space(count);
233 : }
234 :
235 : auto
236 2500 : header::
237 : tab() const noexcept ->
238 : table
239 : {
240 2500 : BOOST_ASSERT(cap > 0);
241 2500 : BOOST_ASSERT(buf != nullptr);
242 2500 : return table(buf + cap);
243 : }
244 :
245 : auto
246 689 : header::
247 : tab_() const noexcept ->
248 : entry*
249 : {
250 : return reinterpret_cast<
251 689 : entry*>(buf + cap);
252 : }
253 :
254 : // return true if header cbuf is a default
255 : bool
256 43 : header::
257 : is_default() const noexcept
258 : {
259 43 : return buf == nullptr;
260 : }
261 :
262 : std::size_t
263 71 : header::
264 : find(
265 : field id) const noexcept
266 : {
267 71 : if(count == 0)
268 6 : return 0;
269 65 : std::size_t i = 0;
270 65 : auto const* p = &tab()[0];
271 89 : while(i < count)
272 : {
273 89 : if(p->id == id)
274 65 : break;
275 24 : ++i;
276 24 : --p;
277 : }
278 65 : return i;
279 : }
280 :
281 : std::size_t
282 20 : header::
283 : find(
284 : core::string_view name) const noexcept
285 : {
286 20 : if(count == 0)
287 5 : return 0;
288 15 : std::size_t i = 0;
289 15 : auto const* p = &tab()[0];
290 21 : while(i < count)
291 : {
292 : core::string_view s(
293 21 : cbuf + prefix + p->np,
294 21 : p->nn);
295 21 : if(grammar::ci_is_equal(s, name))
296 15 : break;
297 6 : ++i;
298 6 : --p;
299 : }
300 15 : return i;
301 : }
302 :
303 : void
304 30 : header::
305 : copy_table(
306 : void* dest,
307 : std::size_t n) const noexcept
308 : {
309 30 : std::memcpy(
310 : reinterpret_cast<
311 30 : entry*>(dest) - n,
312 : reinterpret_cast<
313 : entry const*>(
314 30 : cbuf + cap) - n,
315 : n * sizeof(entry));
316 30 : }
317 :
318 : void
319 30 : header::
320 : copy_table(
321 : void* dest) const noexcept
322 : {
323 30 : copy_table(dest, count);
324 30 : }
325 :
326 : // assign all the members but
327 : // preserve the allocated memory
328 : void
329 30 : header::
330 : assign_to(
331 : header& dest) const noexcept
332 : {
333 30 : auto const buf_ = dest.buf;
334 30 : auto const cbuf_ = dest.cbuf;
335 30 : auto const cap_ = dest.cap;
336 30 : dest = *this;
337 30 : dest.buf = buf_;
338 30 : dest.cbuf = cbuf_;
339 30 : dest.cap = cap_;
340 30 : }
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 21 : header::
375 : is_special(
376 : field id) const noexcept
377 : {
378 21 : if(kind == detail::kind::fields)
379 4 : return false;
380 17 : switch(id)
381 : {
382 9 : case field::connection:
383 : case field::content_length:
384 : case field::expect:
385 : case field::transfer_encoding:
386 : case field::upgrade:
387 9 : return true;
388 8 : default:
389 8 : break;
390 : }
391 8 : return false;
392 : }
393 :
394 : //------------------------------------------------
395 :
396 : // called when the start-line changes
397 : void
398 2034 : 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 2034 : update_payload();
408 2034 : }
409 :
410 : // called after a field is inserted
411 : void
412 2916 : header::
413 : on_insert(
414 : field id,
415 : core::string_view v)
416 : {
417 2916 : if(kind == detail::kind::fields)
418 510 : return;
419 2406 : switch(id)
420 : {
421 590 : case field::content_length:
422 590 : return on_insert_content_length(v);
423 147 : case field::connection:
424 147 : return on_insert_connection(v);
425 47 : case field::expect:
426 47 : return on_insert_expect(v);
427 48 : case field::transfer_encoding:
428 48 : return on_insert_transfer_encoding();
429 24 : case field::upgrade:
430 24 : return on_insert_upgrade(v);
431 1550 : default:
432 1550 : break;
433 : }
434 : }
435 :
436 : // called when one field is erased
437 : void
438 40 : header::
439 : on_erase(field id)
440 : {
441 40 : if(kind == detail::kind::fields)
442 3 : return;
443 37 : switch(id)
444 : {
445 9 : case field::connection:
446 9 : return on_erase_connection();
447 4 : case field::content_length:
448 4 : return on_erase_content_length();
449 10 : case field::expect:
450 10 : 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 151 : header::
467 : on_insert_connection(
468 : core::string_view v)
469 : {
470 151 : ++md.connection.count;
471 151 : if(md.connection.ec.failed())
472 5 : return;
473 : auto rv = grammar::parse(
474 150 : v, list_rule(token_rule, 1));
475 150 : if(! rv)
476 : {
477 4 : md.connection.ec =
478 8 : BOOST_HTTP_PROTO_ERR(
479 : error::bad_connection);
480 4 : return;
481 : }
482 146 : md.connection.ec = {};
483 303 : for(auto t : *rv)
484 : {
485 157 : if(grammar::ci_is_equal(
486 : t, "close"))
487 107 : md.connection.close = true;
488 50 : else if(grammar::ci_is_equal(
489 : t, "keep-alive"))
490 26 : 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 591 : 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 591 : ++md.content_length.count;
508 591 : if(md.content_length.ec.failed())
509 468 : return;
510 : auto rv =
511 589 : grammar::parse(v, num_rule);
512 589 : 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 584 : if(md.content_length.count == 1)
523 : {
524 : // one value
525 454 : md.content_length.ec = {};
526 454 : md.content_length.value = *rv;
527 454 : update_payload();
528 454 : 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 53 : header::
545 : on_insert_expect(
546 : core::string_view v)
547 : {
548 53 : ++md.expect.count;
549 53 : if(kind != detail::kind::request)
550 8 : return;
551 45 : if(md.expect.ec.failed())
552 4 : return;
553 : // VFALCO Should we allow duplicate
554 : // Expect fields that have 100-continue?
555 73 : if( md.expect.count > 1 ||
556 73 : ! grammar::ci_is_equal(v,
557 : "100-continue"))
558 : {
559 19 : md.expect.ec =
560 38 : BOOST_HTTP_PROTO_ERR(
561 : error::bad_expect);
562 19 : md.expect.is_100_continue = false;
563 19 : return;
564 : }
565 22 : md.expect.is_100_continue = true;
566 : }
567 :
568 : void
569 51 : header::
570 : on_insert_transfer_encoding()
571 : {
572 51 : ++md.transfer_encoding.count;
573 51 : if(md.transfer_encoding.ec.failed())
574 1 : return;
575 50 : auto const n =
576 : md.transfer_encoding.count;
577 50 : md.transfer_encoding = {};
578 50 : md.transfer_encoding.count = n;
579 57 : for(auto s :
580 : fields_view_base::subrange(
581 164 : this, find(field::transfer_encoding)))
582 : {
583 : auto rv = grammar::parse(
584 65 : s, transfer_encoding_rule);
585 65 : 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 61 : md.transfer_encoding.codings += rv->size();
597 127 : for(auto t : *rv)
598 : {
599 70 : if(! md.transfer_encoding.is_chunked)
600 : {
601 66 : if(t.id == transfer_coding::chunked)
602 30 : md.transfer_encoding.is_chunked = true;
603 66 : 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 42 : 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 9 : header::
675 : on_erase_connection()
676 : {
677 9 : BOOST_ASSERT(
678 : md.connection.count > 0);
679 : // reset and re-insert
680 9 : auto n = md.connection.count - 1;
681 9 : auto const p = cbuf + prefix;
682 9 : auto const* e = &tab()[0];
683 9 : md.connection = {};
684 14 : 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 9 : }
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 10 : header::
733 : on_erase_expect()
734 : {
735 10 : BOOST_ASSERT(
736 : md.expect.count > 0);
737 10 : --md.expect.count;
738 10 : if(kind != detail::kind::request)
739 1 : return;
740 9 : if(md.expect.count == 0)
741 : {
742 : // no Expect
743 3 : md.expect = {};
744 3 : 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 6 : auto n = count;
755 6 : auto const p = cbuf + prefix;
756 6 : auto const* e = &tab()[0];
757 6 : md.expect = {};
758 19 : while(n > 0)
759 : {
760 13 : if(e->id == field::expect)
761 6 : on_insert_expect(
762 : core::string_view(
763 6 : p + e->vp, e->vn));
764 13 : --n;
765 13 : --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 60 : header::
823 : on_erase_all(
824 : field id)
825 : {
826 60 : if(kind == detail::kind::fields)
827 17 : return;
828 43 : switch(id)
829 : {
830 3 : case field::connection:
831 3 : md.connection = {};
832 3 : 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 31 : default:
854 31 : 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 2678 : header::
873 : update_payload() noexcept
874 : {
875 2678 : BOOST_ASSERT(kind !=
876 : detail::kind::fields);
877 2678 : 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 2678 : 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 2550 : 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 2542 : if( md.content_length.count > 0 &&
911 458 : md.transfer_encoding.count > 0)
912 : {
913 3 : md.payload = payload::error;
914 3 : md.payload_size = 0;
915 3 : return;
916 : }
917 :
918 2539 : if(kind == detail::kind::response)
919 639 : 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 1900 : if(md.content_length.count > 0)
931 : {
932 297 : if(md.content_length.value > 0)
933 : {
934 : // non-zero Content-Length
935 291 : md.payload = payload::size;
936 291 : md.payload_size = md.content_length.value;
937 291 : return;
938 : }
939 : // Content-Length: 0
940 6 : md.payload = payload::none;
941 6 : md.payload_size = 0;
942 6 : return;
943 : }
944 1603 : 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 1589 : md.payload = payload::none;
953 1589 : md.payload_size = 0;
954 1589 : return;
955 :
956 : //--------------------------------------------
957 639 : do_response:
958 :
959 639 : if( res.status_int / 100 == 1 || // 1xx e.g. Continue
960 629 : res.status_int == 204 || // No Content
961 627 : 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 14 : md.payload = payload::none;
969 14 : md.payload_size = 0;
970 14 : return;
971 : }
972 625 : if(md.content_length.count > 0)
973 : {
974 155 : if(md.content_length.value > 0)
975 : {
976 : // Content-Length > 0
977 142 : md.payload = payload::size;
978 142 : md.payload_size = md.content_length.value;
979 142 : return;
980 : }
981 : // Content-Length: 0
982 13 : md.payload = payload::none;
983 13 : md.payload_size = 0;
984 13 : return;
985 : }
986 470 : if(md.transfer_encoding.is_chunked)
987 : {
988 : // chunked
989 9 : md.payload = payload::chunked;
990 9 : md.payload_size = 0;
991 9 : return;
992 : }
993 :
994 : // eof needed
995 461 : md.payload = payload::to_eof;
996 461 : md.payload_size = 0;
997 : }
998 :
999 : //------------------------------------------------
1000 :
1001 : std::size_t
1002 535 : header::
1003 : count_crlf(
1004 : core::string_view s) noexcept
1005 : {
1006 535 : auto it = s.data();
1007 535 : auto len = s.size();
1008 535 : std::size_t n = 0;
1009 18834 : while(len >= 2)
1010 : {
1011 18299 : if( it[0] == '\r' &&
1012 1714 : it[1] != '\r')
1013 : {
1014 1714 : if(it[1] == '\n')
1015 1714 : n++;
1016 1714 : it += 2;
1017 1714 : len -= 2;
1018 : }
1019 : else
1020 : {
1021 16585 : it++;
1022 16585 : len--;
1023 : }
1024 : }
1025 535 : return n;
1026 : }
1027 :
1028 : static
1029 : void
1030 3960 : 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 3960 : BOOST_ASSERT(h.size == 0);
1037 3960 : BOOST_ASSERT(h.prefix == 0);
1038 3960 : BOOST_ASSERT(h.cbuf != nullptr);
1039 3960 : BOOST_ASSERT(
1040 : h.kind != detail::kind::fields);
1041 :
1042 3960 : auto const it0 = h.cbuf;
1043 3960 : auto const end = it0 + new_size;
1044 3960 : char const* it = it0;
1045 3960 : if( new_size > lim.max_start_line)
1046 0 : new_size = lim.max_start_line;
1047 3960 : if(h.kind == detail::kind::request)
1048 : {
1049 : auto rv = grammar::parse(
1050 3356 : it, end, request_line_rule);
1051 3356 : if(! rv)
1052 : {
1053 1809 : ec = rv.error();
1054 3618 : if( ec == grammar::error::need_more &&
1055 1809 : new_size == lim.max_start_line)
1056 0 : ec = BOOST_HTTP_PROTO_ERR(
1057 : error::start_line_limit);
1058 1809 : return;
1059 : }
1060 : // method
1061 1547 : auto sm = std::get<0>(*rv);
1062 1547 : h.req.method = string_to_method(sm);
1063 1547 : h.req.method_len =
1064 1547 : static_cast<offset_type>(sm.size());
1065 : // target
1066 1547 : auto st = std::get<1>(*rv);
1067 1547 : h.req.target_len =
1068 1547 : static_cast<offset_type>(st.size());
1069 : // version
1070 1547 : 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 1527 : case 11:
1077 1527 : h.version =
1078 : http_proto::version::http_1_1;
1079 1527 : 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 604 : it, end, status_line_rule);
1092 604 : 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 453 : switch(std::get<0>(*rv))
1103 : {
1104 5 : case 10:
1105 5 : h.version =
1106 : http_proto::version::http_1_0;
1107 5 : break;
1108 448 : case 11:
1109 448 : h.version =
1110 : http_proto::version::http_1_1;
1111 448 : 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 453 : h.res.status_int =
1121 : static_cast<unsigned short>(
1122 453 : std::get<1>(*rv).v);
1123 453 : h.res.status = std::get<1>(*rv).st;
1124 : }
1125 2000 : h.prefix = static_cast<offset_type>(it - it0);
1126 2000 : h.size = h.prefix;
1127 2000 : h.on_start_line();
1128 : }
1129 :
1130 : // returns: true if we added a field
1131 : static
1132 : void
1133 6781 : parse_field(
1134 : header& h,
1135 : header_limits const& lim,
1136 : std::size_t new_size,
1137 : system::error_code& ec) noexcept
1138 : {
1139 6781 : if( new_size > lim.max_field)
1140 0 : new_size = lim.max_field;
1141 6781 : auto const it0 = h.cbuf + h.size;
1142 6781 : auto const end = h.cbuf + new_size;
1143 6781 : char const* it = it0;
1144 : auto rv = grammar::parse(
1145 6781 : it, end, field_rule);
1146 6781 : if(rv.has_error())
1147 : {
1148 4072 : ec = rv.error();
1149 4072 : if(ec == grammar::error::end_of_range)
1150 : {
1151 : // final CRLF
1152 1981 : h.size = static_cast<
1153 1981 : offset_type>(it - h.cbuf);
1154 4072 : return;
1155 : }
1156 3923 : if( ec == grammar::error::need_more &&
1157 1832 : new_size == lim.max_field)
1158 : {
1159 0 : ec = BOOST_HTTP_PROTO_ERR(
1160 : error::field_size_limit);
1161 : }
1162 2091 : return;
1163 : }
1164 2709 : if(h.count >= lim.max_fields)
1165 : {
1166 0 : ec = BOOST_HTTP_PROTO_ERR(
1167 : error::fields_limit);
1168 0 : return;
1169 : }
1170 2709 : if(rv->has_obs_fold)
1171 : {
1172 : // obs fold not allowed in test views
1173 210 : BOOST_ASSERT(h.buf != nullptr);
1174 210 : remove_obs_fold(h.buf + h.size, it);
1175 : }
1176 2709 : auto id = string_to_field(rv->name);
1177 2709 : h.size = static_cast<offset_type>(it - h.cbuf);
1178 :
1179 : // add field table entry
1180 2709 : if(h.buf != nullptr)
1181 : {
1182 5418 : auto& e = header::table(
1183 2709 : h.buf + h.cap)[h.count];
1184 2709 : auto const base =
1185 2709 : h.buf + h.prefix;
1186 2709 : e.np = static_cast<offset_type>(
1187 2709 : rv->name.data() - base);
1188 2709 : e.nn = static_cast<offset_type>(
1189 2709 : rv->name.size());
1190 2709 : e.vp = static_cast<offset_type>(
1191 2709 : rv->value.data() - base);
1192 2709 : e.vn = static_cast<offset_type>(
1193 2709 : rv->value.size());
1194 2709 : e.id = id;
1195 : }
1196 2709 : ++h.count;
1197 2709 : h.on_insert(id, rv->value);
1198 2709 : ec = {};
1199 : }
1200 :
1201 : void
1202 6032 : header::
1203 : parse(
1204 : std::size_t new_size,
1205 : header_limits const& lim,
1206 : system::error_code& ec) noexcept
1207 : {
1208 6032 : if( new_size > lim.max_size)
1209 0 : new_size = lim.max_size;
1210 6032 : if( this->prefix == 0 &&
1211 4200 : this->kind !=
1212 : detail::kind::fields)
1213 : {
1214 3960 : parse_start_line(
1215 : *this, lim, new_size, ec);
1216 3960 : if(ec.failed())
1217 : {
1218 3920 : if( ec == grammar::error::need_more &&
1219 1960 : new_size == lim.max_fields)
1220 : {
1221 0 : ec = BOOST_HTTP_PROTO_ERR(
1222 : error::headers_limit);
1223 : }
1224 1960 : return;
1225 : }
1226 : }
1227 : for(;;)
1228 : {
1229 6781 : parse_field(
1230 : *this, lim, new_size, ec);
1231 6781 : if(ec.failed())
1232 : {
1233 5904 : if( ec == grammar::error::need_more &&
1234 1832 : new_size == lim.max_size)
1235 : {
1236 0 : ec = BOOST_HTTP_PROTO_ERR(
1237 : error::headers_limit);
1238 0 : return;
1239 : }
1240 4072 : break;
1241 : }
1242 2709 : }
1243 4072 : if(ec == grammar::error::end_of_range)
1244 1981 : ec = {};
1245 : }
1246 :
1247 : } // detail
1248 : } // http_proto
1249 : } // boost
|