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