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