123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- //
- // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- // Official repository: https://github.com/boostorg/beast
- //
- #include "nodejs_parser.hpp"
- #include "test/beast/http/message_fuzz.hpp"
- #include <boost/beast/http.hpp>
- #include <boost/beast/core/buffer_traits.hpp>
- #include <boost/beast/core/buffers_suffix.hpp>
- #include <boost/beast/core/buffers_to_string.hpp>
- #include <boost/beast/core/ostream.hpp>
- #include <boost/beast/core/flat_buffer.hpp>
- #include <boost/beast/core/multi_buffer.hpp>
- #include <boost/beast/_experimental/unit_test/suite.hpp>
- #include <chrono>
- #include <iostream>
- #include <vector>
- namespace boost {
- namespace beast {
- namespace http {
- class parser_test : public beast::unit_test::suite
- {
- public:
- static std::size_t constexpr N = 2000;
- //using corpus = std::vector<multi_buffer>;
- using corpus = std::vector<flat_buffer>;
- corpus creq_;
- corpus cres_;
- std::size_t size_ = 0;
- corpus
- build_corpus(std::size_t n, std::true_type)
- {
- corpus v;
- v.resize(n);
- message_fuzz mg;
- for(std::size_t i = 0; i < n; ++i)
- {
- mg.request(v[i]);
- size_ += v[i].size();
- BEAST_EXPECT(v[i].size() > 0);
- }
- return v;
- }
- corpus
- build_corpus(std::size_t n, std::false_type)
- {
- corpus v;
- v.resize(n);
- message_fuzz mg;
- for(std::size_t i = 0; i < n; ++i)
- {
- mg.response(v[i]);
- size_ += v[i].size();
- BEAST_EXPECT(v[i].size() > 0);
- }
- return v;
- }
- template<class ConstBufferSequence,
- bool isRequest>
- static
- std::size_t
- feed(ConstBufferSequence const& buffers,
- basic_parser<isRequest>& parser,
- error_code& ec)
- {
- beast::buffers_suffix<
- ConstBufferSequence> cb{buffers};
- std::size_t used = 0;
- for(;;)
- {
- auto const n =
- parser.put(cb, ec);
- if(ec)
- return 0;
- if(n == 0)
- break;
- cb.consume(n);
- used += n;
- if(parser.is_done())
- break;
- if(buffer_bytes(cb) == 0)
- break;
- }
- return used;
- }
- template<class Parser>
- void
- testParser1(std::size_t repeat, corpus const& v)
- {
- while(repeat--)
- for(auto const& b : v)
- {
- Parser p;
- error_code ec;
- p.write(b.data(), ec);
- if(! BEAST_EXPECTS(! ec, ec.message()))
- log << buffers_to_string(b.data()) << std::endl;
- }
- }
- template<class Parser>
- void
- testParser2(std::size_t repeat, corpus const& v)
- {
- while(repeat--)
- for(auto const& b : v)
- {
- Parser p;
- p.header_limit((std::numeric_limits<std::uint32_t>::max)());
- error_code ec;
- feed(b.data(), p, ec);
- if(! BEAST_EXPECTS(! ec, ec.message()))
- log << buffers_to_string(b.data()) << std::endl;
- }
- }
- template<class Function>
- void
- timedTest(std::size_t repeat, std::string const& name, Function&& f)
- {
- using namespace std::chrono;
- using clock_type = std::chrono::high_resolution_clock;
- log << name << std::endl;
- for(std::size_t trial = 1; trial <= repeat; ++trial)
- {
- auto const t0 = clock_type::now();
- f();
- auto const elapsed = clock_type::now() - t0;
- log <<
- "Trial " << trial << ": " <<
- duration_cast<milliseconds>(elapsed).count() << " ms" << std::endl;
- }
- }
- template<bool isRequest>
- struct null_parser :
- basic_parser<isRequest>
- {
- void
- on_request_impl(
- verb, string_view, string_view,
- int, error_code&) override
- {
- }
- void
- on_response_impl(
- int, string_view, int,
- error_code&) override
- {
- }
- void
- on_field_impl(
- field, string_view, string_view,
- error_code&) override
- {
- }
- void
- on_header_impl(error_code&) override
- {
- }
- void
- on_body_init_impl(
- boost::optional<std::uint64_t> const&,
- error_code&) override
- {
- }
- std::size_t
- on_body_impl(
- string_view,
- error_code&) override
- {
- return 0;
- }
- void
- on_chunk_header_impl(
- std::uint64_t,
- string_view,
- error_code&) override
- {
- }
- std::size_t
- on_chunk_body_impl(
- std::uint64_t,
- string_view,
- error_code&) override
- {
- return 0;
- }
- void
- on_finish_impl(error_code&) override
- {
- }
- };
- template<bool isRequest, class Body, class Fields>
- struct bench_parser : basic_parser<isRequest>
- {
- using mutable_buffers_type =
- net::mutable_buffer;
- void
- on_request_impl(verb, string_view,
- string_view, int, error_code&) override
- {
- }
- void
- on_response_impl(int,
- string_view, int, error_code&) override
- {
- }
- void
- on_field_impl(field,
- string_view, string_view, error_code&) override
- {
- }
- void
- on_header_impl(error_code&) override
- {
- }
- void
- on_body_init_impl(
- boost::optional<std::uint64_t> const&,
- error_code&) override
- {
- }
- std::size_t
- on_body_impl(
- string_view s, error_code&) override
- {
- return s.size();
- }
- void
- on_chunk_header_impl(std::uint64_t,
- string_view, error_code&) override
- {
- }
- std::size_t
- on_chunk_body_impl(std::uint64_t,
- string_view s, error_code&) override
- {
- return s.size();
- }
- void
- on_finish_impl(error_code&) override
- {
- }
- };
- void
- testSpeed()
- {
- static std::size_t constexpr Trials = 5;
- static std::size_t constexpr Repeat = 500;
- creq_ = build_corpus(N/2, std::true_type{});
- cres_ = build_corpus(N/2, std::false_type{});
- log << "sizeof(request parser) == " <<
- sizeof(null_parser<true>) << '\n';
- log << "sizeof(response parser) == " <<
- sizeof(null_parser<false>)<< '\n';
- testcase << "Parser speed test, " <<
- ((Repeat * size_ + 512) / 1024) << "KB in " <<
- (Repeat * (creq_.size() + cres_.size())) << " messages";
- #if 0
- timedTest(Trials, "http::parser",
- [&]
- {
- testParser2<request_parser<dynamic_body>>(Repeat, creq_);
- testParser2<response_parser<dynamic_body>>(Repeat, cres_);
- });
- #endif
- #if 1
- timedTest(Trials, "http::basic_parser",
- [&]
- {
- testParser2<bench_parser<
- true, dynamic_body, fields> >(
- Repeat, creq_);
- testParser2<bench_parser<
- false, dynamic_body, fields>>(
- Repeat, cres_);
- });
- #if 1
- timedTest(Trials, "nodejs_parser",
- [&]
- {
- testParser1<nodejs_parser<
- true, dynamic_body, fields>>(
- Repeat, creq_);
- testParser1<nodejs_parser<
- false, dynamic_body, fields>>(
- Repeat, cres_);
- });
- #endif
- #endif
- pass();
- }
- void run() override
- {
- pass();
- testSpeed();
- }
- };
- BEAST_DEFINE_TESTSUITE(beast,benchmarks,parser);
- } // http
- } // beast
- } // boost
|