]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/Beast/test/http/read.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / Beast / test / http / read.cpp
diff --git a/ceph/src/Beast/test/http/read.cpp b/ceph/src/Beast/test/http/read.cpp
new file mode 100644 (file)
index 0000000..3e80b8e
--- /dev/null
@@ -0,0 +1,333 @@
+//
+// Copyright (c) 2013-2017 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)
+//
+
+// Test that header file is self-contained.
+#include <beast/http/read.hpp>
+
+#include "test_parser.hpp"
+
+#include <beast/http/fields.hpp>
+#include <beast/http/header_parser.hpp>
+#include <beast/http/streambuf_body.hpp>
+#include <beast/http/string_body.hpp>
+#include <beast/test/fail_stream.hpp>
+#include <beast/test/string_istream.hpp>
+#include <beast/test/yield_to.hpp>
+#include <beast/unit_test/suite.hpp>
+#include <boost/asio/spawn.hpp>
+#include <atomic>
+
+namespace beast {
+namespace http {
+
+class read_test
+    : public beast::unit_test::suite
+    , public test::enable_yield_to
+{
+public:
+    template<bool isRequest>
+    void
+    failMatrix(char const* s, yield_context do_yield)
+    {
+        using boost::asio::buffer;
+        using boost::asio::buffer_copy;
+        static std::size_t constexpr limit = 100;
+        std::size_t n;
+        auto const len = strlen(s);
+        for(n = 0; n < limit; ++n)
+        {
+            streambuf sb;
+            sb.commit(buffer_copy(
+                sb.prepare(len), buffer(s, len)));
+            test::fail_counter fc(n);
+            test::fail_stream<
+                test::string_istream> fs{fc, ios_, ""};
+            test_parser<isRequest> p(fc);
+            error_code ec;
+            read(fs, sb, p, ec);
+            if(! ec)
+                break;
+        }
+        BEAST_EXPECT(n < limit);
+        for(n = 0; n < limit; ++n)
+        {
+            static std::size_t constexpr pre = 10;
+            streambuf sb;
+            sb.commit(buffer_copy(
+                sb.prepare(pre), buffer(s, pre)));
+            test::fail_counter fc(n);
+            test::fail_stream<test::string_istream> fs{
+                fc, ios_, std::string{s + pre, len - pre}};
+            test_parser<isRequest> p(fc);
+            error_code ec;
+            read(fs, sb, p, ec);
+            if(! ec)
+                break;
+        }
+        BEAST_EXPECT(n < limit);
+        for(n = 0; n < limit; ++n)
+        {
+            streambuf sb;
+            sb.commit(buffer_copy(
+                sb.prepare(len), buffer(s, len)));
+            test::fail_counter fc(n);
+            test::fail_stream<
+                test::string_istream> fs{fc, ios_, ""};
+            test_parser<isRequest> p(fc);
+            error_code ec;
+            async_read(fs, sb, p, do_yield[ec]);
+            if(! ec)
+                break;
+        }
+        BEAST_EXPECT(n < limit);
+        for(n = 0; n < limit; ++n)
+        {
+            static std::size_t constexpr pre = 10;
+            streambuf sb;
+            sb.commit(buffer_copy(
+                sb.prepare(pre), buffer(s, pre)));
+            test::fail_counter fc(n);
+            test::fail_stream<test::string_istream> fs{
+                fc, ios_, std::string{s + pre, len - pre}};
+            test_parser<isRequest> p(fc);
+            error_code ec;
+            async_read(fs, sb, p, do_yield[ec]);
+            if(! ec)
+                break;
+        }
+        BEAST_EXPECT(n < limit);
+    }
+
+    void testThrow()
+    {
+        try
+        {
+            streambuf sb;
+            test::string_istream ss(ios_, "GET / X");
+            message_parser<true, streambuf_body, fields> p;
+            read(ss, sb, p);
+            fail();
+        }
+        catch(std::exception const&)
+        {
+            pass();
+        }
+    }
+
+    void testFailures(yield_context do_yield)
+    {
+        char const* req[] = {
+            "GET / HTTP/1.0\r\n"
+            "Host: localhost\r\n"
+            "User-Agent: test\r\n"
+            "Empty:\r\n"
+            "\r\n"
+            ,
+            "GET / HTTP/1.1\r\n"
+            "Host: localhost\r\n"
+            "User-Agent: test\r\n"
+            "Content-Length: 2\r\n"
+            "\r\n"
+            "**"
+            ,
+            "GET / HTTP/1.1\r\n"
+            "Host: localhost\r\n"
+            "User-Agent: test\r\n"
+            "Transfer-Encoding: chunked\r\n"
+            "\r\n"
+            "10\r\n"
+            "****************\r\n"
+            "0\r\n\r\n"
+            ,
+            nullptr
+        };
+
+        char const* res[] = {
+            "HTTP/1.0 200 OK\r\n"
+            "Server: test\r\n"
+            "\r\n"
+            ,
+            "HTTP/1.0 200 OK\r\n"
+            "Server: test\r\n"
+            "\r\n"
+            "***"
+            ,
+            "HTTP/1.1 200 OK\r\n"
+            "Server: test\r\n"
+            "Content-Length: 3\r\n"
+            "\r\n"
+            "***"
+            ,
+            "HTTP/1.1 200 OK\r\n"
+            "Server: test\r\n"
+            "Transfer-Encoding: chunked\r\n"
+            "\r\n"
+            "10\r\n"
+            "****************\r\n"
+            "0\r\n\r\n"
+            ,
+            nullptr
+        };
+
+        for(std::size_t i = 0; req[i]; ++i)
+            failMatrix<true>(req[i], do_yield);
+
+        for(std::size_t i = 0; res[i]; ++i)
+            failMatrix<false>(res[i], do_yield);
+    }
+
+    void testRead(yield_context do_yield)
+    {
+        static std::size_t constexpr limit = 100;
+        std::size_t n;
+
+        for(n = 0; n < limit; ++n)
+        {
+            test::fail_stream<test::string_istream> fs(n, ios_,
+                "GET / HTTP/1.1\r\n"
+                "Host: localhost\r\n"
+                "User-Agent: test\r\n"
+                "Content-Length: 0\r\n"
+                "\r\n"
+            );
+            request<streambuf_body> m;
+            try
+            {
+                streambuf sb;
+                read(fs, sb, m);
+                break;
+            }
+            catch(std::exception const&)
+            {
+            }
+        }
+        BEAST_EXPECT(n < limit);
+
+        for(n = 0; n < limit; ++n)
+        {
+            test::fail_stream<test::string_istream> fs(n, ios_,
+                "GET / HTTP/1.1\r\n"
+                "Host: localhost\r\n"
+                "User-Agent: test\r\n"
+                "Content-Length: 0\r\n"
+                "\r\n"
+            );
+            request<streambuf_body> m;
+            error_code ec;
+            streambuf sb;
+            read(fs, sb, m, ec);
+            if(! ec)
+                break;
+        }
+        BEAST_EXPECT(n < limit);
+
+        for(n = 0; n < limit; ++n)
+        {
+            test::fail_stream<test::string_istream> fs(n, ios_,
+                "GET / HTTP/1.1\r\n"
+                "Host: localhost\r\n"
+                "User-Agent: test\r\n"
+                "Content-Length: 0\r\n"
+                "\r\n"
+            );
+            request<streambuf_body> m;
+            error_code ec;
+            streambuf sb;
+            async_read(fs, sb, m, do_yield[ec]);
+            if(! ec)
+                break;
+        }
+        BEAST_EXPECT(n < limit);
+    }
+
+    void
+    testEof(yield_context do_yield)
+    {
+        {
+            streambuf sb;
+            test::string_istream ss(ios_, "");
+            message_parser<true, streambuf_body, fields> p;
+            error_code ec;
+            read(ss, sb, p, ec);
+            BEAST_EXPECT(ec == boost::asio::error::eof);
+        }
+        {
+            streambuf sb;
+            test::string_istream ss(ios_, "");
+            message_parser<true, streambuf_body, fields> p;
+            error_code ec;
+            async_read(ss, sb, p, do_yield[ec]);
+            BEAST_EXPECT(ec == boost::asio::error::eof);
+        }
+    }
+
+    // Ensure completion handlers are not leaked
+    struct handler
+    {
+        static std::atomic<std::size_t>&
+        count() { static std::atomic<std::size_t> n; return n; }
+        handler() { ++count(); }
+        ~handler() { --count(); }
+        handler(handler const&) { ++count(); }
+        void operator()(error_code const&) const {}
+    };
+
+    void
+    testIoService()
+    {
+        {
+            // Make sure handlers are not destroyed
+            // after calling io_service::stop
+            boost::asio::io_service ios;
+            test::string_istream is{ios,
+                "GET / HTTP/1.1\r\n\r\n"};
+            BEAST_EXPECT(handler::count() == 0);
+            streambuf sb;
+            message<true, streambuf_body, fields> m;
+            async_read(is, sb, m, handler{});
+            BEAST_EXPECT(handler::count() > 0);
+            ios.stop();
+            BEAST_EXPECT(handler::count() > 0);
+            ios.reset();
+            BEAST_EXPECT(handler::count() > 0);
+            ios.run_one();
+            BEAST_EXPECT(handler::count() == 0);
+        }
+        {
+            // Make sure uninvoked handlers are
+            // destroyed when calling ~io_service
+            {
+                boost::asio::io_service ios;
+                test::string_istream is{ios,
+                    "GET / HTTP/1.1\r\n\r\n"};
+                BEAST_EXPECT(handler::count() == 0);
+                streambuf sb;
+                message<true, streambuf_body, fields> m;
+                async_read(is, sb, m, handler{});
+                BEAST_EXPECT(handler::count() > 0);
+            }
+            BEAST_EXPECT(handler::count() == 0);
+        }
+    }
+
+    void
+    run() override
+    {
+        testThrow();
+
+        yield_to(&read_test::testFailures, this);
+        yield_to(&read_test::testRead, this);
+        yield_to(&read_test::testEof, this);
+
+        testIoService();
+    }
+};
+
+BEAST_DEFINE_TESTSUITE(read,http,beast);
+
+} // http
+} // beast