]> git.proxmox.com Git - ceph.git/blob - ceph/src/Beast/test/http/nodejs_parser.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / Beast / test / http / nodejs_parser.hpp
1 //
2 // Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot 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
8 #ifndef BEAST_HTTP_NODEJS_PARSER_HPP
9 #define BEAST_HTTP_NODEJS_PARSER_HPP
10
11 #include "nodejs-parser/http_parser.h"
12
13 #include <beast/http/message.hpp>
14 #include <beast/http/rfc7230.hpp>
15 #include <beast/core/buffer_concepts.hpp>
16 #include <beast/core/error.hpp>
17 #include <boost/asio/buffer.hpp>
18 #include <boost/system/error_code.hpp>
19 #include <cstdint>
20 #include <string>
21 #include <type_traits>
22 #include <utility>
23
24 namespace beast {
25 namespace http {
26
27 namespace detail {
28
29 class nodejs_message_category
30 : public boost::system::error_category
31 {
32 public:
33 const char*
34 name() const noexcept override
35 {
36 return "nodejs-http-error";
37 }
38
39 std::string
40 message(int ev) const override
41 {
42 return http_errno_description(
43 static_cast<http_errno>(ev));
44 }
45
46 boost::system::error_condition
47 default_error_condition(int ev) const noexcept override
48 {
49 return boost::system::error_condition{ev, *this};
50 }
51
52 bool
53 equivalent(int ev,
54 boost::system::error_condition const& condition
55 ) const noexcept override
56 {
57 return condition.value() == ev &&
58 &condition.category() == this;
59 }
60
61 bool
62 equivalent(boost::system::error_code const& error,
63 int ev) const noexcept override
64 {
65 return error.value() == ev &&
66 &error.category() == this;
67 }
68 };
69
70 template<class = void>
71 boost::system::error_code
72 make_nodejs_error(int http_errno)
73 {
74 static nodejs_message_category const mc{};
75 return boost::system::error_code{http_errno, mc};
76 }
77
78 inline
79 char const*
80 method_to_string(unsigned method)
81 {
82 using namespace beast;
83 switch(static_cast<http_method>(method))
84 {
85 case HTTP_DELETE: return "DELETE";
86 case HTTP_GET: return "GET";
87 case HTTP_HEAD: return "HEAD";
88 case HTTP_POST: return "POST";
89 case HTTP_PUT: return "PUT";
90
91 // pathological
92 case HTTP_CONNECT: return "CONNECT";
93 case HTTP_OPTIONS: return "OPTIONS";
94 case HTTP_TRACE: return "TRACE";
95
96 // webdav
97 case HTTP_COPY: return "COPY";
98 case HTTP_LOCK: return "LOCK";
99 case HTTP_MKCOL: return "MKCOL";
100 case HTTP_MOVE: return "MOVE";
101 case HTTP_PROPFIND: return "PROPFIND";
102 case HTTP_PROPPATCH: return "PROPPATCH";
103 case HTTP_SEARCH: return "SEARCH";
104 case HTTP_UNLOCK: return "UNLOCK";
105 case HTTP_BIND: return "BIND";
106 case HTTP_REBIND: return "REBIND";
107 case HTTP_UNBIND: return "UNBIND";
108 case HTTP_ACL: return "ACL";
109
110 // subversion
111 case HTTP_REPORT: return "REPORT";
112 case HTTP_MKACTIVITY: return "MKACTIVITY";
113 case HTTP_CHECKOUT: return "CHECKOUT";
114 case HTTP_MERGE: return "MERGE";
115
116 // upnp
117 case HTTP_MSEARCH: return "MSEARCH";
118 case HTTP_NOTIFY: return "NOTIFY";
119 case HTTP_SUBSCRIBE: return "SUBSCRIBE";
120 case HTTP_UNSUBSCRIBE: return "UNSUBSCRIBE";
121
122 // RFC-5789
123 case HTTP_PATCH: return "PATCH";
124 case HTTP_PURGE: return "PURGE";
125
126 // CalDav
127 case HTTP_MKCALENDAR: return "MKCALENDAR";
128
129 // RFC-2068, section 19.6.1.2
130 case HTTP_LINK: return "LINK";
131 case HTTP_UNLINK: return "UNLINK";
132 };
133
134 return "<unknown>";
135 }
136
137 } // detail
138
139 template<class Derived>
140 class nodejs_basic_parser
141 {
142 http_parser state_;
143 boost::system::error_code* ec_;
144 bool complete_ = false;
145 std::string url_;
146 std::string status_;
147 std::string field_;
148 std::string value_;
149
150 public:
151 using error_code = boost::system::error_code;
152
153 nodejs_basic_parser(nodejs_basic_parser&& other);
154
155 nodejs_basic_parser&
156 operator=(nodejs_basic_parser&& other);
157
158 nodejs_basic_parser(nodejs_basic_parser const& other);
159
160 nodejs_basic_parser& operator=(nodejs_basic_parser const& other);
161
162 explicit
163 nodejs_basic_parser(bool request) noexcept;
164
165 bool
166 complete() const noexcept
167 {
168 return complete_;
169 }
170
171 std::size_t
172 write(void const* data, std::size_t size)
173 {
174 error_code ec;
175 auto const used = write(data, size, ec);
176 if(ec)
177 throw system_error{ec};
178 return used;
179 }
180
181 std::size_t
182 write(void const* data, std::size_t size,
183 error_code& ec);
184
185 template<class ConstBufferSequence>
186 std::size_t
187 write(ConstBufferSequence const& buffers)
188 {
189 error_code ec;
190 auto const used = write(buffers, ec);
191 if(ec)
192 throw system_error{ec};
193 return used;
194 }
195
196 template<class ConstBufferSequence>
197 std::size_t
198 write(ConstBufferSequence const& buffers,
199 error_code& ec);
200
201 void
202 write_eof()
203 {
204 error_code ec;
205 write_eof(ec);
206 if(ec)
207 throw system_error{ec};
208 }
209
210 void
211 write_eof(error_code& ec);
212
213 private:
214 Derived&
215 impl()
216 {
217 return *static_cast<Derived*>(this);
218 }
219
220 template<class C>
221 class has_on_start_t
222 {
223 template<class T, class R =
224 decltype(std::declval<T>().on_start(), std::true_type{})>
225 static R check(int);
226 template<class>
227 static std::false_type check(...);
228 using type = decltype(check<C>(0));
229 public:
230 static bool const value = type::value;
231 };
232 template<class C>
233 using has_on_start =
234 std::integral_constant<bool, has_on_start_t<C>::value>;
235
236 void
237 call_on_start(std::true_type)
238 {
239 impl().on_start();
240 }
241
242 void
243 call_on_start(std::false_type)
244 {
245 }
246
247 template<class C>
248 class has_on_field_t
249 {
250 template<class T, class R =
251 decltype(std::declval<T>().on_field(
252 std::declval<std::string const&>(),
253 std::declval<std::string const&>()),
254 std::true_type{})>
255 static R check(int);
256 template<class>
257 static std::false_type check(...);
258 using type = decltype(check<C>(0));
259 public:
260 static bool const value = type::value;
261 };
262 template<class C>
263 using has_on_field =
264 std::integral_constant<bool, has_on_field_t<C>::value>;
265
266 void
267 call_on_field(std::string const& field,
268 std::string const& value, std::true_type)
269 {
270 impl().on_field(field, value);
271 }
272
273 void
274 call_on_field(std::string const&, std::string const&,
275 std::false_type)
276 {
277 }
278
279 template<class C>
280 class has_on_headers_complete_t
281 {
282 template<class T, class R =
283 decltype(std::declval<T>().on_headers_complete(
284 std::declval<error_code&>()), std::true_type{})>
285 static R check(int);
286 template<class>
287 static std::false_type check(...);
288 using type = decltype(check<C>(0));
289 public:
290 static bool const value = type::value;
291 };
292 template<class C>
293 using has_on_headers_complete =
294 std::integral_constant<bool, has_on_headers_complete_t<C>::value>;
295
296 void
297 call_on_headers_complete(error_code& ec, std::true_type)
298 {
299 impl().on_headers_complete(ec);
300 }
301
302 void
303 call_on_headers_complete(error_code&, std::false_type)
304 {
305 }
306
307 template<class C>
308 class has_on_request_t
309 {
310 template<class T, class R =
311 decltype(std::declval<T>().on_request(
312 std::declval<unsigned>(), std::declval<std::string>(),
313 std::declval<int>(), std::declval<int>(),
314 std::declval<bool>(), std::declval<bool>()),
315 std::true_type{})>
316 static R check(int);
317 template<class>
318 static std::false_type check(...);
319 using type = decltype(check<C>(0));
320 public:
321 static bool const value = type::value;
322 };
323 template<class C>
324 using has_on_request =
325 std::integral_constant<bool, has_on_request_t<C>::value>;
326
327 void
328 call_on_request(unsigned method, std::string url,
329 int major, int minor, bool keep_alive, bool upgrade,
330 std::true_type)
331 {
332 impl().on_request(
333 method, url, major, minor, keep_alive, upgrade);
334 }
335
336 void
337 call_on_request(unsigned, std::string, int, int, bool, bool,
338 std::false_type)
339 {
340 }
341
342 template<class C>
343 class has_on_response_t
344 {
345 template<class T, class R =
346 decltype(std::declval<T>().on_response(
347 std::declval<int>(), std::declval<std::string>,
348 std::declval<int>(), std::declval<int>(),
349 std::declval<bool>(), std::declval<bool>()),
350 std::true_type{})>
351 static R check(int);
352 template<class>
353 static std::false_type check(...);
354 #if 0
355 using type = decltype(check<C>(0));
356 #else
357 // VFALCO Trait seems broken for http::parser
358 using type = std::true_type;
359 #endif
360 public:
361 static bool const value = type::value;
362 };
363 template<class C>
364 using has_on_response =
365 std::integral_constant<bool, has_on_response_t<C>::value>;
366
367 bool
368 call_on_response(int status, std::string text,
369 int major, int minor, bool keep_alive, bool upgrade,
370 std::true_type)
371 {
372 return impl().on_response(
373 status, text, major, minor, keep_alive, upgrade);
374 }
375
376 bool
377 call_on_response(int, std::string, int, int, bool, bool,
378 std::false_type)
379 {
380 // VFALCO Certainly incorrect
381 return true;
382 }
383
384 template<class C>
385 class has_on_body_t
386 {
387 template<class T, class R =
388 decltype(std::declval<T>().on_body(
389 std::declval<void const*>(), std::declval<std::size_t>(),
390 std::declval<error_code&>()), std::true_type{})>
391 static R check(int);
392 template<class>
393 static std::false_type check(...);
394 using type = decltype(check<C>(0));
395 public:
396 static bool const value = type::value;
397 };
398 template<class C>
399 using has_on_body =
400 std::integral_constant<bool, has_on_body_t<C>::value>;
401
402 void
403 call_on_body(void const* data, std::size_t bytes,
404 error_code& ec, std::true_type)
405 {
406 impl().on_body(data, bytes, ec);
407 }
408
409 void
410 call_on_body(void const*, std::size_t,
411 error_code&, std::false_type)
412 {
413 }
414
415 template<class C>
416 class has_on_complete_t
417 {
418 template<class T, class R =
419 decltype(std::declval<T>().on_complete(), std::true_type{})>
420 static R check(int);
421 template<class>
422 static std::false_type check(...);
423 using type = decltype(check<C>(0));
424 public:
425 static bool const value = type::value;
426 };
427 template<class C>
428 using has_on_complete =
429 std::integral_constant<bool, has_on_complete_t<C>::value>;
430
431 void
432 call_on_complete(std::true_type)
433 {
434 impl().on_complete();
435 }
436
437 void
438 call_on_complete(std::false_type)
439 {
440 }
441
442 void
443 check_header();
444
445 static int cb_message_start(http_parser*);
446 static int cb_url(http_parser*, char const*, std::size_t);
447 static int cb_status(http_parser*, char const*, std::size_t);
448 static int cb_header_field(http_parser*, char const*, std::size_t);
449 static int cb_header_value(http_parser*, char const*, std::size_t);
450 static int cb_headers_complete(http_parser*);
451 static int cb_body(http_parser*, char const*, std::size_t);
452 static int cb_message_complete(http_parser*);
453 static int cb_chunk_header(http_parser*);
454 static int cb_chunk_complete(http_parser*);
455
456 struct hooks_t : http_parser_settings
457 {
458 hooks_t()
459 {
460 http_parser_settings_init(this);
461 on_message_begin = &nodejs_basic_parser::cb_message_start;
462 on_url = &nodejs_basic_parser::cb_url;
463 on_status = &nodejs_basic_parser::cb_status;
464 on_header_field = &nodejs_basic_parser::cb_header_field;
465 on_header_value = &nodejs_basic_parser::cb_header_value;
466 on_headers_complete = &nodejs_basic_parser::cb_headers_complete;
467 on_body = &nodejs_basic_parser::cb_body;
468 on_message_complete = &nodejs_basic_parser::cb_message_complete;
469 on_chunk_header = &nodejs_basic_parser::cb_chunk_header;
470 on_chunk_complete = &nodejs_basic_parser::cb_chunk_complete;
471 }
472 };
473
474 static
475 http_parser_settings const*
476 hooks();
477 };
478
479 template<class Derived>
480 template<class ConstBufferSequence>
481 std::size_t
482 nodejs_basic_parser<Derived>::write(
483 ConstBufferSequence const& buffers, error_code& ec)
484 {
485 static_assert(beast::is_ConstBufferSequence<
486 ConstBufferSequence>::value,
487 "ConstBufferSequence requirements not met");
488 using boost::asio::buffer_cast;
489 using boost::asio::buffer_size;
490 std::size_t bytes_used = 0;
491 for(auto const& buffer : buffers)
492 {
493 auto const n = write(
494 buffer_cast<void const*>(buffer),
495 buffer_size(buffer), ec);
496 if(ec)
497 return 0;
498 bytes_used += n;
499 if(complete())
500 break;
501 }
502 return bytes_used;
503 }
504
505 template<class Derived>
506 http_parser_settings const*
507 nodejs_basic_parser<Derived>::hooks()
508 {
509 static hooks_t const h;
510 return &h;
511 }
512
513 template<class Derived>
514 nodejs_basic_parser<Derived>::
515 nodejs_basic_parser(nodejs_basic_parser&& other)
516 {
517 state_ = other.state_;
518 state_.data = this;
519 complete_ = other.complete_;
520 url_ = std::move(other.url_);
521 status_ = std::move(other.status_);
522 field_ = std::move(other.field_);
523 value_ = std::move(other.value_);
524 }
525
526 template<class Derived>
527 auto
528 nodejs_basic_parser<Derived>::operator=(nodejs_basic_parser&& other) ->
529 nodejs_basic_parser&
530 {
531 state_ = other.state_;
532 state_.data = this;
533 complete_ = other.complete_;
534 url_ = std::move(other.url_);
535 status_ = std::move(other.status_);
536 field_ = std::move(other.field_);
537 value_ = std::move(other.value_);
538 return *this;
539 }
540
541 template<class Derived>
542 nodejs_basic_parser<Derived>::
543 nodejs_basic_parser(nodejs_basic_parser const& other)
544 {
545 state_ = other.state_;
546 state_.data = this;
547 complete_ = other.complete_;
548 url_ = other.url_;
549 status_ = other.status_;
550 field_ = other.field_;
551 value_ = other.value_;
552 }
553
554 template<class Derived>
555 auto
556 nodejs_basic_parser<Derived>::
557 operator=(nodejs_basic_parser const& other) ->
558 nodejs_basic_parser&
559 {
560 state_ = other.state_;
561 state_.data = this;
562 complete_ = other.complete_;
563 url_ = other.url_;
564 status_ = other.status_;
565 field_ = other.field_;
566 value_ = other.value_;
567 return *this;
568 }
569
570 template<class Derived>
571 nodejs_basic_parser<Derived>::nodejs_basic_parser(bool request) noexcept
572 {
573 state_.data = this;
574 http_parser_init(&state_, request
575 ? http_parser_type::HTTP_REQUEST
576 : http_parser_type::HTTP_RESPONSE);
577 }
578
579 template<class Derived>
580 std::size_t
581 nodejs_basic_parser<Derived>::write(void const* data,
582 std::size_t size, error_code& ec)
583 {
584 ec_ = &ec;
585 auto const n = http_parser_execute(
586 &state_, hooks(),
587 static_cast<const char*>(data), size);
588 if(! ec)
589 ec = detail::make_nodejs_error(
590 static_cast<int>(state_.http_errno));
591 if(ec)
592 return 0;
593 return n;
594 }
595
596 template<class Derived>
597 void
598 nodejs_basic_parser<Derived>::write_eof(error_code& ec)
599 {
600 ec_ = &ec;
601 http_parser_execute(
602 &state_, hooks(), nullptr, 0);
603 if(! ec)
604 ec = detail::make_nodejs_error(
605 static_cast<int>(state_.http_errno));
606 }
607
608 template<class Derived>
609 void
610 nodejs_basic_parser<Derived>::check_header()
611 {
612 if(! value_.empty())
613 {
614 //detail::trim(value_);
615 call_on_field(field_, value_,
616 has_on_field<Derived>{});
617 field_.clear();
618 value_.clear();
619 }
620 }
621
622 template<class Derived>
623 int
624 nodejs_basic_parser<Derived>::cb_message_start(http_parser* p)
625 {
626 auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
627 t.complete_ = false;
628 t.url_.clear();
629 t.status_.clear();
630 t.field_.clear();
631 t.value_.clear();
632 t.call_on_start(has_on_start<Derived>{});
633 return 0;
634 }
635
636 template<class Derived>
637 int
638 nodejs_basic_parser<Derived>::cb_url(http_parser* p,
639 char const* in, std::size_t bytes)
640 {
641 auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
642 t.url_.append(in, bytes);
643 return 0;
644 }
645
646 template<class Derived>
647 int
648 nodejs_basic_parser<Derived>::cb_status(http_parser* p,
649 char const* in, std::size_t bytes)
650 {
651 auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
652 t.status_.append(in, bytes);
653 return 0;
654 }
655
656 template<class Derived>
657 int
658 nodejs_basic_parser<Derived>::cb_header_field(http_parser* p,
659 char const* in, std::size_t bytes)
660 {
661 auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
662 t.check_header();
663 t.field_.append(in, bytes);
664 return 0;
665 }
666
667 template<class Derived>
668 int
669 nodejs_basic_parser<Derived>::cb_header_value(http_parser* p,
670 char const* in, std::size_t bytes)
671 {
672 auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
673 t.value_.append(in, bytes);
674 return 0;
675 }
676
677 template<class Derived>
678 int
679 nodejs_basic_parser<Derived>::cb_headers_complete(http_parser* p)
680 {
681 auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
682 t.check_header();
683 t.call_on_headers_complete(*t.ec_,
684 has_on_headers_complete<Derived>{});
685 if(*t.ec_)
686 return 1;
687 bool const keep_alive =
688 http_should_keep_alive(p) != 0;
689 if(p->type == http_parser_type::HTTP_REQUEST)
690 {
691 t.call_on_request(p->method, t.url_,
692 p->http_major, p->http_minor, keep_alive,
693 p->upgrade, has_on_request<Derived>{});
694 return 0;
695 }
696 return t.call_on_response(p->status_code, t.status_,
697 p->http_major, p->http_minor, keep_alive,
698 p->upgrade, has_on_response<Derived>{}) ? 0 : 1;
699 }
700
701 template<class Derived>
702 int
703 nodejs_basic_parser<Derived>::cb_body(http_parser* p,
704 char const* in, std::size_t bytes)
705 {
706 auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
707 t.call_on_body(in, bytes, *t.ec_, has_on_body<Derived>{});
708 return *t.ec_ ? 1 : 0;
709 }
710
711 template<class Derived>
712 int
713 nodejs_basic_parser<Derived>::cb_message_complete(http_parser* p)
714 {
715 auto& t = *reinterpret_cast<nodejs_basic_parser*>(p->data);
716 t.complete_ = true;
717 t.call_on_complete(has_on_complete<Derived>{});
718 return 0;
719 }
720
721 template<class Derived>
722 int
723 nodejs_basic_parser<Derived>::cb_chunk_header(http_parser*)
724 {
725 return 0;
726 }
727
728 template<class Derived>
729 int
730 nodejs_basic_parser<Derived>::cb_chunk_complete(http_parser*)
731 {
732 return 0;
733 }
734
735 /** A HTTP parser.
736
737 The parser may only be used once.
738 */
739 template<bool isRequest, class Body, class Fields>
740 class nodejs_parser
741 : public nodejs_basic_parser<nodejs_parser<isRequest, Body, Fields>>
742 {
743 bool started_ = false;
744
745 public:
746 nodejs_parser(nodejs_parser&&) = default;
747
748 nodejs_parser()
749 : http::nodejs_basic_parser<nodejs_parser>(isRequest)
750 {
751 }
752
753 /// Returns `true` if at least one byte has been processed
754 bool
755 started()
756 {
757 return started_;
758 }
759
760 private:
761 friend class http::nodejs_basic_parser<nodejs_parser>;
762
763 void
764 on_start()
765 {
766 started_ = true;
767 }
768
769 void
770 on_field(std::string const& field, std::string const& value)
771 {
772 }
773
774 void
775 on_headers_complete(error_code&)
776 {
777 // vFALCO TODO Decode the Content-Length and
778 // Transfer-Encoding, see if we can reserve the buffer.
779 //
780 // r_.reserve(content_length)
781 }
782
783 bool
784 on_request(unsigned method, std::string const& url,
785 int major, int minor, bool /*keep_alive*/, bool /*upgrade*/,
786 std::true_type)
787 {
788 return true;
789 }
790
791 bool
792 on_request(unsigned, std::string const&,
793 int, int, bool, bool,
794 std::false_type)
795 {
796 return true;
797 }
798
799 bool
800 on_request(unsigned method, std::string const& url,
801 int major, int minor, bool keep_alive, bool upgrade)
802 {
803 return on_request(method, url,
804 major, minor, keep_alive, upgrade,
805 std::integral_constant<
806 bool, isRequest>{});
807 }
808
809 bool
810 on_response(int status, std::string const& reason,
811 int major, int minor, bool keep_alive, bool upgrade,
812 std::true_type)
813 {
814 beast::detail::ignore_unused(keep_alive, upgrade);
815 return true;
816 }
817
818 bool
819 on_response(int, std::string const&, int, int, bool, bool,
820 std::false_type)
821 {
822 return true;
823 }
824
825 bool
826 on_response(int status, std::string const& reason,
827 int major, int minor, bool keep_alive, bool upgrade)
828 {
829 return on_response(
830 status, reason, major, minor, keep_alive, upgrade,
831 std::integral_constant<bool, ! isRequest>{});
832 }
833
834 void
835 on_body(void const* data,
836 std::size_t size, error_code& ec)
837 {
838 }
839
840 void
841 on_complete()
842 {
843 }
844 };
845
846 } // http
847 } // beast
848
849 #endif