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/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 "../rfc/transfer_encoding_rule.hpp"
31 :
32 : namespace boost {
33 : namespace http_proto {
34 : namespace detail {
35 :
36 : //------------------------------------------------
37 :
38 : auto
39 115 : header::
40 : entry::
41 : operator+(
42 : std::size_t dv) const noexcept ->
43 : entry
44 : {
45 : return {
46 : static_cast<
47 115 : offset_type>(np + dv),
48 115 : nn,
49 : static_cast<
50 115 : offset_type>(vp + dv),
51 115 : vn,
52 115 : 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 249 : 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 249 : return &h[k];
119 : }
120 :
121 3404 : header::
122 3404 : header(empty v) noexcept
123 3404 : : kind(v.param)
124 : {
125 3404 : }
126 :
127 230 : header::
128 230 : header(detail::kind k) noexcept
129 230 : : header(*get_default(k))
130 : {
131 230 : }
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 904 : 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 904 : if( size < 19)
212 172 : size = 19;
213 : static constexpr auto A =
214 : alignof(header::entry);
215 904 : return align_up(size, A) +
216 904 : (count * sizeof(
217 904 : header::entry));
218 : }
219 :
220 : std::size_t
221 1418 : header::
222 : table_space(
223 : std::size_t count) noexcept
224 : {
225 : return count *
226 1418 : sizeof(header::entry);
227 : }
228 :
229 : std::size_t
230 1418 : header::
231 : table_space() const noexcept
232 : {
233 1418 : return table_space(count);
234 : }
235 :
236 : auto
237 2999 : header::
238 : tab() const noexcept ->
239 : table
240 : {
241 2999 : BOOST_ASSERT(cap > 0);
242 2999 : BOOST_ASSERT(buf != nullptr);
243 2999 : return table(buf + cap);
244 : }
245 :
246 : auto
247 857 : header::
248 : tab_() const noexcept ->
249 : entry*
250 : {
251 : return reinterpret_cast<
252 857 : 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 227 : header::
265 : find(
266 : field id) const noexcept
267 : {
268 227 : if(count == 0)
269 6 : return 0;
270 221 : std::size_t i = 0;
271 221 : auto const* p = &tab()[0];
272 242 : while(i < count)
273 : {
274 242 : if(p->id == id)
275 221 : break;
276 21 : ++i;
277 21 : --p;
278 : }
279 221 : return i;
280 : }
281 :
282 : std::size_t
283 68 : header::
284 : find(
285 : core::string_view name) const noexcept
286 : {
287 68 : if(count == 0)
288 53 : 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 2122 : 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 2122 : update_payload();
409 2122 : }
410 :
411 : // called after a field is inserted
412 : void
413 3076 : header::
414 : on_insert(
415 : field id,
416 : core::string_view v)
417 : {
418 3076 : if(kind == detail::kind::fields)
419 510 : return;
420 2566 : switch(id)
421 : {
422 590 : case field::content_length:
423 590 : return on_insert_content_length(v);
424 147 : case field::connection:
425 147 : return on_insert_connection(v);
426 47 : case field::expect:
427 47 : return on_insert_expect(v);
428 208 : case field::transfer_encoding:
429 208 : return on_insert_transfer_encoding();
430 24 : case field::upgrade:
431 24 : return on_insert_upgrade(v);
432 1550 : default:
433 1550 : 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 151 : header::
468 : on_insert_connection(
469 : core::string_view v)
470 : {
471 151 : ++md.connection.count;
472 151 : if(md.connection.ec.failed())
473 5 : return;
474 : auto rv = grammar::parse(
475 150 : v, list_rule(token_rule, 1));
476 150 : if(! rv)
477 : {
478 4 : md.connection.ec =
479 8 : BOOST_HTTP_PROTO_ERR(
480 : error::bad_connection);
481 4 : return;
482 : }
483 146 : md.connection.ec = {};
484 303 : for(auto t : *rv)
485 : {
486 157 : if(grammar::ci_is_equal(
487 : t, "close"))
488 107 : 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 150 : }
497 :
498 : void
499 591 : 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 591 : ++md.content_length.count;
509 591 : if(md.content_length.ec.failed())
510 468 : return;
511 : auto rv =
512 589 : grammar::parse(v, num_rule);
513 589 : 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 584 : if(md.content_length.count == 1)
524 : {
525 : // one value
526 454 : md.content_length.ec = {};
527 454 : md.content_length.value = *rv;
528 454 : update_payload();
529 454 : 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 211 : header::
571 : on_insert_transfer_encoding()
572 : {
573 211 : ++md.transfer_encoding.count;
574 211 : if(md.transfer_encoding.ec.failed())
575 5 : return;
576 206 : auto const n =
577 : md.transfer_encoding.count;
578 206 : md.transfer_encoding = {};
579 206 : md.transfer_encoding.count = n;
580 206 : for(auto s :
581 : fields_view_base::subrange(
582 639 : this, find(field::transfer_encoding)))
583 : {
584 : auto rv = grammar::parse(
585 238 : s, transfer_encoding_rule);
586 238 : 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 234 : md.transfer_encoding.codings += rv->size();
598 470 : for(auto t : *rv)
599 : {
600 243 : auto& mte = md.transfer_encoding;
601 :
602 243 : if(! mte.is_chunked )
603 : {
604 239 : if( t.id == transfer_encoding::chunked )
605 : {
606 138 : mte.is_chunked = true;
607 138 : continue;
608 : }
609 :
610 101 : auto b =
611 101 : mte.encoding ==
612 : http_proto::encoding::identity;
613 :
614 101 : if( t.id == transfer_encoding::deflate )
615 37 : mte.encoding = http_proto::encoding::deflate;
616 :
617 101 : if( t.id == transfer_encoding::gzip )
618 43 : mte.encoding = http_proto::encoding::gzip;
619 :
620 101 : if( b )
621 98 : continue;
622 : }
623 7 : if(t.id == transfer_encoding::chunked)
624 : {
625 : // chunked appears twice
626 2 : md.transfer_encoding.ec =
627 4 : BOOST_HTTP_PROTO_ERR(
628 : error::bad_transfer_encoding);
629 2 : md.transfer_encoding.codings = 0;
630 2 : md.transfer_encoding.is_chunked = false;
631 2 : md.transfer_encoding.encoding =
632 : http_proto::encoding::identity;
633 2 : update_payload();
634 2 : return;
635 : }
636 : // chunked must be last
637 5 : md.transfer_encoding.ec =
638 10 : BOOST_HTTP_PROTO_ERR(
639 : error::bad_transfer_encoding);
640 5 : md.transfer_encoding.codings = 0;
641 5 : md.transfer_encoding.is_chunked = false;
642 5 : md.transfer_encoding.encoding =
643 : http_proto::encoding::identity;
644 5 : update_payload();
645 5 : return;
646 484 : }
647 238 : }
648 195 : update_payload();
649 : }
650 :
651 : void
652 26 : header::
653 : on_insert_upgrade(
654 : core::string_view v)
655 : {
656 26 : ++md.upgrade.count;
657 26 : if(md.upgrade.ec.failed())
658 5 : return;
659 25 : if( version !=
660 : http_proto::version::http_1_1)
661 : {
662 1 : md.upgrade.ec =
663 2 : BOOST_HTTP_PROTO_ERR(
664 : error::bad_upgrade);
665 1 : md.upgrade.websocket = false;
666 1 : return;
667 : }
668 : auto rv = grammar::parse(
669 24 : v, upgrade_rule);
670 24 : if(! rv)
671 : {
672 3 : md.upgrade.ec =
673 6 : BOOST_HTTP_PROTO_ERR(
674 : error::bad_upgrade);
675 3 : md.upgrade.websocket = false;
676 3 : return;
677 : }
678 21 : if(! md.upgrade.websocket)
679 : {
680 23 : for(auto t : *rv)
681 : {
682 16 : if( grammar::ci_is_equal(
683 26 : t.name, "websocket") &&
684 10 : t.version.empty())
685 : {
686 9 : md.upgrade.websocket = true;
687 9 : break;
688 : }
689 : }
690 : }
691 24 : }
692 :
693 : //------------------------------------------------
694 :
695 : void
696 9 : header::
697 : on_erase_connection()
698 : {
699 9 : BOOST_ASSERT(
700 : md.connection.count > 0);
701 : // reset and re-insert
702 9 : auto n = md.connection.count - 1;
703 9 : auto const p = cbuf + prefix;
704 9 : auto const* e = &tab()[0];
705 9 : md.connection = {};
706 14 : while(n > 0)
707 : {
708 5 : if(e->id == field::connection)
709 4 : on_insert_connection(
710 : core::string_view(
711 4 : p + e->vp, e->vn));
712 5 : --n;
713 5 : --e;
714 : }
715 9 : }
716 :
717 : void
718 4 : header::
719 : on_erase_content_length()
720 : {
721 4 : BOOST_ASSERT(
722 : md.content_length.count > 0);
723 4 : --md.content_length.count;
724 4 : if(md.content_length.count == 0)
725 : {
726 : // no Content-Length
727 1 : md.content_length = {};
728 1 : update_payload();
729 1 : return;
730 : }
731 3 : if(! md.content_length.ec.failed())
732 : {
733 : // removing a duplicate value
734 2 : return;
735 : }
736 : // reset and re-insert
737 1 : auto n = md.content_length.count;
738 1 : auto const p = cbuf + prefix;
739 1 : auto const* e = &tab()[0];
740 1 : md.content_length = {};
741 2 : while(n > 0)
742 : {
743 1 : if(e->id == field::content_length)
744 1 : on_insert_content_length(
745 : core::string_view(
746 1 : p + e->vp, e->vn));
747 1 : --n;
748 1 : --e;
749 : }
750 1 : update_payload();
751 : }
752 :
753 : void
754 10 : header::
755 : on_erase_expect()
756 : {
757 10 : BOOST_ASSERT(
758 : md.expect.count > 0);
759 10 : --md.expect.count;
760 10 : if(kind != detail::kind::request)
761 1 : return;
762 9 : if(md.expect.count == 0)
763 : {
764 : // no Expect
765 3 : md.expect = {};
766 3 : return;
767 : }
768 : // VFALCO This should be uncommented
769 : // if we want to allow multiple Expect
770 : // fields with the value 100-continue
771 : /*
772 : if(! md.expect.ec.failed())
773 : return;
774 : */
775 : // reset and re-insert
776 6 : auto n = count;
777 6 : auto const p = cbuf + prefix;
778 6 : auto const* e = &tab()[0];
779 6 : md.expect = {};
780 19 : while(n > 0)
781 : {
782 13 : if(e->id == field::expect)
783 6 : on_insert_expect(
784 : core::string_view(
785 6 : p + e->vp, e->vn));
786 13 : --n;
787 13 : --e;
788 : }
789 : }
790 :
791 : void
792 5 : header::
793 : on_erase_transfer_encoding()
794 : {
795 5 : BOOST_ASSERT(
796 : md.transfer_encoding.count > 0);
797 5 : --md.transfer_encoding.count;
798 5 : if(md.transfer_encoding.count == 0)
799 : {
800 : // no Transfer-Encoding
801 2 : md.transfer_encoding = {};
802 2 : update_payload();
803 2 : return;
804 : }
805 : // re-insert everything
806 3 : --md.transfer_encoding.count;
807 3 : on_insert_transfer_encoding();
808 : }
809 :
810 : // called when Upgrade is erased
811 : void
812 4 : header::
813 : on_erase_upgrade()
814 : {
815 4 : BOOST_ASSERT(
816 : md.upgrade.count > 0);
817 4 : --md.upgrade.count;
818 4 : if(md.upgrade.count == 0)
819 : {
820 : // no Upgrade
821 2 : md.upgrade = {};
822 2 : return;
823 : }
824 : // reset and re-insert
825 2 : auto n = md.upgrade.count;
826 2 : auto const p = cbuf + prefix;
827 2 : auto const* e = &tab()[0];
828 2 : md.upgrade = {};
829 4 : while(n > 0)
830 : {
831 2 : if(e->id == field::upgrade)
832 2 : on_insert_upgrade(
833 : core::string_view(
834 2 : p + e->vp, e->vn));
835 2 : --n;
836 2 : --e;
837 : }
838 : }
839 :
840 : //------------------------------------------------
841 :
842 : // called when all fields with id are removed
843 : void
844 60 : header::
845 : on_erase_all(
846 : field id)
847 : {
848 60 : if(kind == detail::kind::fields)
849 17 : return;
850 43 : switch(id)
851 : {
852 3 : case field::connection:
853 3 : md.connection = {};
854 3 : return;
855 :
856 2 : case field::content_length:
857 2 : md.content_length = {};
858 2 : update_payload();
859 2 : return;
860 :
861 5 : case field::expect:
862 5 : md.expect = {};
863 5 : update_payload();
864 5 : return;
865 :
866 1 : case field::transfer_encoding:
867 1 : md.transfer_encoding = {};
868 1 : update_payload();
869 1 : return;
870 :
871 1 : case field::upgrade:
872 1 : md.upgrade = {};
873 1 : return;
874 :
875 31 : default:
876 31 : break;
877 : }
878 : }
879 :
880 : //------------------------------------------------
881 :
882 : /* References:
883 :
884 : 3.3. Message Body
885 : https://datatracker.ietf.org/doc/html/rfc7230#section-3.3
886 :
887 : 3.3.1. Transfer-Encoding
888 : https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.1
889 :
890 : 3.3.2. Content-Length
891 : https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
892 : */
893 : void
894 2922 : header::
895 : update_payload() noexcept
896 : {
897 2922 : BOOST_ASSERT(kind !=
898 : detail::kind::fields);
899 2922 : if(md.payload_override)
900 : {
901 : // e.g. response to
902 : // a HEAD request
903 0 : return;
904 : }
905 :
906 : /* If there is an error in either Content-Length
907 : or Transfer-Encoding, then the payload is
908 : undefined. Clients should probably close the
909 : connection. Servers can send a Bad Request
910 : and avoid reading any payload bytes.
911 : */
912 2922 : if(md.content_length.ec.failed())
913 : {
914 : // invalid Content-Length
915 128 : md.payload = payload::error;
916 128 : md.payload_size = 0;
917 128 : return;
918 : }
919 2794 : if(md.transfer_encoding.ec.failed())
920 : {
921 : // invalid Transfer-Encoding
922 11 : md.payload = payload::error;
923 11 : md.payload_size = 0;
924 11 : return;
925 : }
926 :
927 : /* A sender MUST NOT send a Content-Length
928 : header field in any message that contains
929 : a Transfer-Encoding header field.
930 : https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
931 : */
932 2783 : if( md.content_length.count > 0 &&
933 458 : md.transfer_encoding.count > 0)
934 : {
935 3 : md.payload = payload::error;
936 3 : md.payload_size = 0;
937 3 : return;
938 : }
939 :
940 2780 : if(kind == detail::kind::response)
941 887 : goto do_response;
942 :
943 : //--------------------------------------------
944 :
945 : /* The presence of a message body in a
946 : request is signaled by a Content-Length
947 : or Transfer-Encoding header field. Request
948 : message framing is independent of method
949 : semantics, even if the method does not
950 : define any use for a message body.
951 : */
952 1893 : if(md.content_length.count > 0)
953 : {
954 297 : if(md.content_length.value > 0)
955 : {
956 : // non-zero Content-Length
957 291 : md.payload = payload::size;
958 291 : md.payload_size = md.content_length.value;
959 291 : return;
960 : }
961 : // Content-Length: 0
962 6 : md.payload = payload::none;
963 6 : md.payload_size = 0;
964 6 : return;
965 : }
966 1596 : if(md.transfer_encoding.is_chunked)
967 : {
968 : // chunked
969 10 : md.payload = payload::chunked;
970 10 : md.payload_size = 0;
971 10 : return;
972 : }
973 : // no payload
974 1586 : md.payload = payload::none;
975 1586 : md.payload_size = 0;
976 1586 : return;
977 :
978 : //--------------------------------------------
979 887 : do_response:
980 :
981 887 : if( res.status_int / 100 == 1 || // 1xx e.g. Continue
982 877 : res.status_int == 204 || // No Content
983 875 : res.status_int == 304) // Not Modified
984 : {
985 : /* The correctness of any Content-Length
986 : here is defined by the particular
987 : resource, and cannot be determined
988 : here. In any case there is no payload.
989 : */
990 14 : md.payload = payload::none;
991 14 : md.payload_size = 0;
992 14 : return;
993 : }
994 873 : if(md.content_length.count > 0)
995 : {
996 155 : if(md.content_length.value > 0)
997 : {
998 : // Content-Length > 0
999 142 : md.payload = payload::size;
1000 142 : md.payload_size = md.content_length.value;
1001 142 : return;
1002 : }
1003 : // Content-Length: 0
1004 13 : md.payload = payload::none;
1005 13 : md.payload_size = 0;
1006 13 : return;
1007 : }
1008 718 : if(md.transfer_encoding.is_chunked)
1009 : {
1010 : // chunked
1011 121 : md.payload = payload::chunked;
1012 121 : md.payload_size = 0;
1013 121 : return;
1014 : }
1015 :
1016 : // eof needed
1017 597 : md.payload = payload::to_eof;
1018 597 : md.payload_size = 0;
1019 : }
1020 :
1021 : //------------------------------------------------
1022 :
1023 : std::size_t
1024 534 : header::
1025 : count_crlf(
1026 : core::string_view s) noexcept
1027 : {
1028 534 : auto it = s.data();
1029 534 : auto len = s.size();
1030 534 : std::size_t n = 0;
1031 18789 : while(len >= 2)
1032 : {
1033 18255 : if( it[0] == '\r' &&
1034 1711 : it[1] != '\r')
1035 : {
1036 1711 : if(it[1] == '\n')
1037 1711 : n++;
1038 1711 : it += 2;
1039 1711 : len -= 2;
1040 : }
1041 : else
1042 : {
1043 16544 : it++;
1044 16544 : len--;
1045 : }
1046 : }
1047 534 : return n;
1048 : }
1049 :
1050 : static
1051 : void
1052 4048 : parse_start_line(
1053 : header& h,
1054 : header_limits const& lim,
1055 : std::size_t new_size,
1056 : system::error_code& ec) noexcept
1057 : {
1058 4048 : BOOST_ASSERT(h.size == 0);
1059 4048 : BOOST_ASSERT(h.prefix == 0);
1060 4048 : BOOST_ASSERT(h.cbuf != nullptr);
1061 4048 : BOOST_ASSERT(
1062 : h.kind != detail::kind::fields);
1063 :
1064 4048 : auto const it0 = h.cbuf;
1065 4048 : auto const end = it0 + new_size;
1066 4048 : char const* it = it0;
1067 4048 : if( new_size > lim.max_start_line)
1068 0 : new_size = lim.max_start_line;
1069 4048 : if(h.kind == detail::kind::request)
1070 : {
1071 : auto rv = grammar::parse(
1072 3356 : it, end, request_line_rule);
1073 3356 : if(! rv)
1074 : {
1075 1809 : ec = rv.error();
1076 3618 : if( ec == grammar::error::need_more &&
1077 1809 : new_size == lim.max_start_line)
1078 0 : ec = BOOST_HTTP_PROTO_ERR(
1079 : error::start_line_limit);
1080 1809 : return;
1081 : }
1082 : // method
1083 1547 : auto sm = std::get<0>(*rv);
1084 1547 : h.req.method = string_to_method(sm);
1085 1547 : h.req.method_len =
1086 1547 : static_cast<offset_type>(sm.size());
1087 : // target
1088 1547 : auto st = std::get<1>(*rv);
1089 1547 : h.req.target_len =
1090 1547 : static_cast<offset_type>(st.size());
1091 : // version
1092 1547 : switch(std::get<2>(*rv))
1093 : {
1094 20 : case 10:
1095 20 : h.version =
1096 : http_proto::version::http_1_0;
1097 20 : break;
1098 1527 : case 11:
1099 1527 : h.version =
1100 : http_proto::version::http_1_1;
1101 1527 : break;
1102 0 : default:
1103 : {
1104 0 : ec = BOOST_HTTP_PROTO_ERR(
1105 : error::bad_version);
1106 0 : return;
1107 : }
1108 : }
1109 : }
1110 : else
1111 : {
1112 : auto rv = grammar::parse(
1113 692 : it, end, status_line_rule);
1114 692 : if(! rv)
1115 : {
1116 151 : ec = rv.error();
1117 302 : if( ec == grammar::error::need_more &&
1118 151 : new_size == lim.max_start_line)
1119 0 : ec = BOOST_HTTP_PROTO_ERR(
1120 : error::start_line_limit);
1121 151 : return;
1122 : }
1123 : // version
1124 541 : switch(std::get<0>(*rv))
1125 : {
1126 5 : case 10:
1127 5 : h.version =
1128 : http_proto::version::http_1_0;
1129 5 : break;
1130 536 : case 11:
1131 536 : h.version =
1132 : http_proto::version::http_1_1;
1133 536 : break;
1134 0 : default:
1135 : {
1136 0 : ec = BOOST_HTTP_PROTO_ERR(
1137 : error::bad_version);
1138 0 : return;
1139 : }
1140 : }
1141 : // status-code
1142 541 : h.res.status_int =
1143 : static_cast<unsigned short>(
1144 541 : std::get<1>(*rv).v);
1145 541 : h.res.status = std::get<1>(*rv).st;
1146 : }
1147 2088 : h.prefix = static_cast<offset_type>(it - it0);
1148 2088 : h.size = h.prefix;
1149 2088 : h.on_start_line();
1150 : }
1151 :
1152 : // returns: true if we added a field
1153 : static
1154 : void
1155 6957 : parse_field(
1156 : header& h,
1157 : header_limits const& lim,
1158 : std::size_t new_size,
1159 : system::error_code& ec) noexcept
1160 : {
1161 6957 : if( new_size > lim.max_field)
1162 0 : new_size = lim.max_field;
1163 6957 : auto const it0 = h.cbuf + h.size;
1164 6957 : auto const end = h.cbuf + new_size;
1165 6957 : char const* it = it0;
1166 6957 : auto rv = grammar::parse(
1167 : it, end, field_rule);
1168 6957 : if(rv.has_error())
1169 : {
1170 4160 : ec = rv.error();
1171 4160 : if(ec == grammar::error::end_of_range)
1172 : {
1173 : // final CRLF
1174 2069 : h.size = static_cast<
1175 2069 : offset_type>(it - h.cbuf);
1176 4160 : return;
1177 : }
1178 3923 : if( ec == grammar::error::need_more &&
1179 1832 : new_size == lim.max_field)
1180 : {
1181 0 : ec = BOOST_HTTP_PROTO_ERR(
1182 : error::field_size_limit);
1183 : }
1184 2091 : return;
1185 : }
1186 2797 : if(h.count >= lim.max_fields)
1187 : {
1188 0 : ec = BOOST_HTTP_PROTO_ERR(
1189 : error::fields_limit);
1190 0 : return;
1191 : }
1192 2797 : if(rv->has_obs_fold)
1193 : {
1194 : // obs fold not allowed in test views
1195 210 : BOOST_ASSERT(h.buf != nullptr);
1196 210 : remove_obs_fold(h.buf + h.size, it);
1197 : }
1198 2797 : auto id = string_to_field(rv->name);
1199 2797 : h.size = static_cast<offset_type>(it - h.cbuf);
1200 :
1201 : // add field table entry
1202 2797 : if(h.buf != nullptr)
1203 : {
1204 5594 : auto& e = header::table(
1205 2797 : h.buf + h.cap)[h.count];
1206 2797 : auto const base =
1207 2797 : h.buf + h.prefix;
1208 2797 : e.np = static_cast<offset_type>(
1209 2797 : rv->name.data() - base);
1210 2797 : e.nn = static_cast<offset_type>(
1211 2797 : rv->name.size());
1212 2797 : e.vp = static_cast<offset_type>(
1213 2797 : rv->value.data() - base);
1214 2797 : e.vn = static_cast<offset_type>(
1215 2797 : rv->value.size());
1216 2797 : e.id = id;
1217 : }
1218 2797 : ++h.count;
1219 2797 : h.on_insert(id, rv->value);
1220 2797 : ec = {};
1221 : }
1222 :
1223 : void
1224 6120 : header::
1225 : parse(
1226 : std::size_t new_size,
1227 : header_limits const& lim,
1228 : system::error_code& ec) noexcept
1229 : {
1230 6120 : if( new_size > lim.max_size)
1231 0 : new_size = lim.max_size;
1232 6120 : if( this->prefix == 0 &&
1233 4288 : this->kind !=
1234 : detail::kind::fields)
1235 : {
1236 4048 : parse_start_line(
1237 : *this, lim, new_size, ec);
1238 4048 : if(ec.failed())
1239 : {
1240 3920 : if( ec == grammar::error::need_more &&
1241 1960 : new_size == lim.max_fields)
1242 : {
1243 0 : ec = BOOST_HTTP_PROTO_ERR(
1244 : error::headers_limit);
1245 : }
1246 1960 : return;
1247 : }
1248 : }
1249 : for(;;)
1250 : {
1251 6957 : parse_field(
1252 : *this, lim, new_size, ec);
1253 6957 : if(ec.failed())
1254 : {
1255 5992 : if( ec == grammar::error::need_more &&
1256 1832 : new_size == lim.max_size)
1257 : {
1258 0 : ec = BOOST_HTTP_PROTO_ERR(
1259 : error::headers_limit);
1260 0 : return;
1261 : }
1262 4160 : break;
1263 : }
1264 2797 : }
1265 4160 : if(ec == grammar::error::end_of_range)
1266 2069 : ec = {};
1267 : }
1268 :
1269 : } // detail
1270 : } // http_proto
1271 : } // boost
|