Files
beast/test/http/read.cpp
T

334 lines
9.2 KiB
C++
Raw Normal View History

2016-04-20 10:15:02 -04:00
//
2017-02-06 20:07:03 -05:00
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
2016-04-20 10:15:02 -04:00
//
// 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>
2016-05-04 17:27:50 -04:00
2016-11-20 07:32:41 -05:00
#include "test_parser.hpp"
#include <beast/http/fields.hpp>
2016-11-20 07:32:41 -05:00
#include <beast/http/header_parser.hpp>
2016-05-04 17:27:50 -04:00
#include <beast/http/streambuf_body.hpp>
2016-11-20 07:32:41 -05:00
#include <beast/http/string_body.hpp>
2016-05-07 07:08:21 -04:00
#include <beast/test/fail_stream.hpp>
2017-01-09 11:13:19 -05:00
#include <beast/test/string_istream.hpp>
2016-05-07 07:08:21 -04:00
#include <beast/test/yield_to.hpp>
2016-05-06 19:14:17 -04:00
#include <beast/unit_test/suite.hpp>
2016-05-04 17:27:50 -04:00
#include <boost/asio/spawn.hpp>
2017-03-31 10:12:58 -04:00
#include <atomic>
2016-05-04 17:27:50 -04:00
namespace beast {
namespace http {
class read_test
2016-05-06 19:14:17 -04:00
: public beast::unit_test::suite
2016-05-04 17:27:50 -04:00
, public test::enable_yield_to
{
public:
2016-04-30 10:29:39 -04:00
template<bool isRequest>
2016-11-20 07:32:41 -05:00
void
failMatrix(char const* s, yield_context do_yield)
2016-04-30 10:29:39 -04:00
{
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<
2017-01-09 11:13:19 -05:00
test::string_istream> fs{fc, ios_, ""};
2016-11-20 07:32:41 -05:00
test_parser<isRequest> p(fc);
2016-04-30 10:29:39 -04:00
error_code ec;
2016-11-20 07:32:41 -05:00
read(fs, sb, p, ec);
2016-04-30 10:29:39 -04:00
if(! ec)
break;
}
2016-08-03 15:34:23 -04:00
BEAST_EXPECT(n < limit);
2016-04-30 10:29:39 -04:00
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);
2017-01-09 11:13:19 -05:00
test::fail_stream<test::string_istream> fs{
2016-04-30 10:29:39 -04:00
fc, ios_, std::string{s + pre, len - pre}};
2016-11-20 07:32:41 -05:00
test_parser<isRequest> p(fc);
2016-04-30 10:29:39 -04:00
error_code ec;
2016-11-20 07:32:41 -05:00
read(fs, sb, p, ec);
2016-04-30 10:29:39 -04:00
if(! ec)
break;
}
2016-08-03 15:34:23 -04:00
BEAST_EXPECT(n < limit);
2016-04-30 10:29:39 -04:00
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<
2017-01-09 11:13:19 -05:00
test::string_istream> fs{fc, ios_, ""};
2016-11-20 07:32:41 -05:00
test_parser<isRequest> p(fc);
2016-04-30 10:29:39 -04:00
error_code ec;
2016-11-20 07:32:41 -05:00
async_read(fs, sb, p, do_yield[ec]);
2016-04-30 10:29:39 -04:00
if(! ec)
break;
}
2016-08-03 15:34:23 -04:00
BEAST_EXPECT(n < limit);
2016-04-30 10:29:39 -04:00
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);
2017-01-09 11:13:19 -05:00
test::fail_stream<test::string_istream> fs{
2016-04-30 10:29:39 -04:00
fc, ios_, std::string{s + pre, len - pre}};
2016-11-20 07:32:41 -05:00
test_parser<isRequest> p(fc);
2016-04-30 10:29:39 -04:00
error_code ec;
2016-11-20 07:32:41 -05:00
async_read(fs, sb, p, do_yield[ec]);
2016-10-15 09:29:14 -04:00
if(! ec)
break;
}
BEAST_EXPECT(n < limit);
2016-04-30 10:29:39 -04:00
}
void testThrow()
{
try
{
streambuf sb;
2017-01-09 11:13:19 -05:00
test::string_istream ss(ios_, "GET / X");
2016-11-20 07:32:41 -05:00
message_parser<true, streambuf_body, fields> p;
read(ss, sb, p);
2016-04-30 10:29:39 -04:00
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);
}
2016-05-04 17:27:50 -04:00
void testRead(yield_context do_yield)
{
static std::size_t constexpr limit = 100;
std::size_t n;
2016-05-07 17:06:46 -04:00
for(n = 0; n < limit; ++n)
2016-05-04 17:27:50 -04:00
{
2017-01-09 11:13:19 -05:00
test::fail_stream<test::string_istream> fs(n, ios_,
2016-05-04 17:27:50 -04:00
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"User-Agent: test\r\n"
"Content-Length: 0\r\n"
"\r\n"
);
2016-10-09 06:34:35 -04:00
request<streambuf_body> m;
2016-05-04 17:27:50 -04:00
try
{
2016-04-30 10:29:39 -04:00
streambuf sb;
2016-05-04 17:27:50 -04:00
read(fs, sb, m);
break;
}
catch(std::exception const&)
{
}
}
2016-08-03 15:34:23 -04:00
BEAST_EXPECT(n < limit);
2016-05-07 17:06:46 -04:00
for(n = 0; n < limit; ++n)
2016-05-04 17:27:50 -04:00
{
2017-01-09 11:13:19 -05:00
test::fail_stream<test::string_istream> fs(n, ios_,
2016-05-04 17:27:50 -04:00
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"User-Agent: test\r\n"
"Content-Length: 0\r\n"
"\r\n"
);
2016-10-09 06:34:35 -04:00
request<streambuf_body> m;
2016-05-04 17:27:50 -04:00
error_code ec;
2016-04-30 10:29:39 -04:00
streambuf sb;
2016-05-04 17:27:50 -04:00
read(fs, sb, m, ec);
if(! ec)
break;
}
2016-08-03 15:34:23 -04:00
BEAST_EXPECT(n < limit);
2016-05-07 17:06:46 -04:00
for(n = 0; n < limit; ++n)
2016-05-04 17:27:50 -04:00
{
2017-01-09 11:13:19 -05:00
test::fail_stream<test::string_istream> fs(n, ios_,
2016-05-04 17:27:50 -04:00
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"User-Agent: test\r\n"
"Content-Length: 0\r\n"
"\r\n"
);
2016-10-09 06:34:35 -04:00
request<streambuf_body> m;
2016-05-04 17:27:50 -04:00
error_code ec;
2016-04-30 10:29:39 -04:00
streambuf sb;
2016-05-04 17:27:50 -04:00
async_read(fs, sb, m, do_yield[ec]);
if(! ec)
break;
}
2016-08-03 15:34:23 -04:00
BEAST_EXPECT(n < limit);
2016-05-04 17:27:50 -04:00
}
2016-11-20 07:32:41 -05:00
void
testEof(yield_context do_yield)
2016-04-30 10:29:39 -04:00
{
{
streambuf sb;
2017-01-09 11:13:19 -05:00
test::string_istream ss(ios_, "");
2016-11-20 07:32:41 -05:00
message_parser<true, streambuf_body, fields> p;
2016-04-30 10:29:39 -04:00
error_code ec;
2016-11-20 07:32:41 -05:00
read(ss, sb, p, ec);
2016-08-03 15:34:23 -04:00
BEAST_EXPECT(ec == boost::asio::error::eof);
2016-04-30 10:29:39 -04:00
}
{
streambuf sb;
2017-01-09 11:13:19 -05:00
test::string_istream ss(ios_, "");
2016-11-20 07:32:41 -05:00
message_parser<true, streambuf_body, fields> p;
2016-04-30 10:29:39 -04:00
error_code ec;
2016-11-20 07:32:41 -05:00
async_read(ss, sb, p, do_yield[ec]);
2016-08-03 15:34:23 -04:00
BEAST_EXPECT(ec == boost::asio::error::eof);
2016-04-30 10:29:39 -04:00
}
}
2017-03-31 10:12:58 -04:00
// 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);
}
}
2016-11-20 07:32:41 -05:00
void
run() override
2016-05-04 17:27:50 -04:00
{
2016-04-30 10:29:39 -04:00
testThrow();
2017-01-19 12:05:56 -05:00
yield_to(&read_test::testFailures, this);
yield_to(&read_test::testRead, this);
yield_to(&read_test::testEof, this);
2017-03-31 10:12:58 -04:00
testIoService();
2016-05-04 17:27:50 -04:00
}
};
BEAST_DEFINE_TESTSUITE(read,http,beast);
} // http
} // beast