diff --git a/doc/beast.dox b/doc/beast.dox index 976ff2c1..ef29bbdf 100644 --- a/doc/beast.dox +++ b/doc/beast.dox @@ -122,12 +122,14 @@ INPUT = \ ../include/beast/write_streambuf.hpp \ ../include/beast/http/basic_headers.hpp \ ../include/beast/http/basic_parser.hpp \ + ../include/beast/http/body_writer.hpp \ ../include/beast/http/chunk_encode.hpp \ ../include/beast/http/empty_body.hpp \ ../include/beast/http/error.hpp \ ../include/beast/http/fields.hpp \ ../include/beast/http/headers.hpp \ ../include/beast/http/message.hpp \ + ../include/beast/http/message_v1.hpp \ ../include/beast/http/method.hpp \ ../include/beast/http/parse_error.hpp \ ../include/beast/http/parser.hpp \ diff --git a/examples/file_body.hpp b/examples/file_body.hpp index 0a3eed17..b28371bb 100644 --- a/examples/file_body.hpp +++ b/examples/file_body.hpp @@ -20,8 +20,7 @@ #ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED #define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED -#include -#include +#include #include #include #include @@ -44,7 +43,8 @@ struct file_body std::size_t buf_len_; public: - static bool constexpr is_single_pass = false; + writer(writer const&) = delete; + writer& operator=(writer const&) = delete; template writer(message const& m) noexcept diff --git a/examples/http_async_server.hpp b/examples/http_async_server.hpp index b409a1eb..d0610f71 100644 --- a/examples/http_async_server.hpp +++ b/examples/http_async_server.hpp @@ -41,8 +41,8 @@ class http_async_server using address_type = boost::asio::ip::address; using socket_type = boost::asio::ip::tcp::socket; - using req_type = request; - using resp_type = response; + using req_type = request_v1; + using resp_type = response_v1; boost::asio::io_service ios_; socket_type sock_; @@ -127,7 +127,7 @@ private: path = root_ + path; if(! boost::filesystem::exists(path)) { - response resp( + response_v1 resp( {404, "Not Found", req_.version}); resp.headers.replace("Server", "http_async_server"); resp.body = "The file '" + path + "' was not found"; @@ -137,7 +137,7 @@ private: asio::placeholders::error)); return; } - response resp( + resp_type resp( {200, "OK", req_.version}); resp.headers.replace("Server", "http_async_server"); resp.headers.replace("Content-Type", "text/html"); diff --git a/examples/http_crawl.cpp b/examples/http_crawl.cpp index 876b9af7..28a93013 100644 --- a/examples/http_crawl.cpp +++ b/examples/http_crawl.cpp @@ -46,13 +46,13 @@ int main(int, char const*[]) stream hs(ios); connect(hs.lowest_layer(), it); auto ep = hs.lowest_layer().remote_endpoint(); - request req({"GET", "/", 11}); + request_v1 req({"GET", "/", 11}); req.headers.insert("Host", host + std::string(":") + std::to_string(ep.port())); req.headers.insert("User-Agent", "beast/http"); prepare(req); hs.write(req); - response resp; + response_v1 resp; hs.read(resp); std::cout << resp; } diff --git a/examples/http_example.cpp b/examples/http_example.cpp index 3e4fb2c9..b308f0a7 100644 --- a/examples/http_example.cpp +++ b/examples/http_example.cpp @@ -23,7 +23,7 @@ int main() using namespace beast::http; // Send HTTP request using beast - request req({"GET", "/", 11}); + request_v1 req({"GET", "/", 11}); req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port())); req.headers.replace("User-Agent", "Beast"); prepare(req); @@ -31,7 +31,7 @@ int main() // Receive and print HTTP response using beast beast::streambuf sb; - response resp; + response_v1 resp; read(sock, sb, resp); std::cout << resp; } diff --git a/examples/http_stream.hpp b/examples/http_stream.hpp index cb3bdb6b..526ae4da 100644 --- a/examples/http_stream.hpp +++ b/examples/http_stream.hpp @@ -268,7 +268,7 @@ public: */ template void - read(message& msg) + read(message_v1& msg) { error_code ec; read(msg, ec); @@ -295,7 +295,7 @@ public: */ template void - read(message& msg, + read(message_v1& msg, error_code& ec); /** Start reading a HTTP message from the stream asynchronously. @@ -339,7 +339,7 @@ public: typename async_completion< ReadHandler, void(error_code)>::result_type #endif - async_read(message& msg, + async_read(message_v1& msg, ReadHandler&& handler); /** Write a HTTP message to the stream. @@ -365,7 +365,7 @@ public: */ template void - write(message const& msg) + write(message_v1 const& msg) { error_code ec; write(msg, ec); @@ -396,7 +396,7 @@ public: */ template void - write(message const& msg, + write(message_v1 const& msg, error_code& ec); /** Start pipelining a HTTP message to the stream asynchronously. @@ -434,7 +434,7 @@ public: typename async_completion< WriteHandler, void(error_code)>::result_type #endif - async_write(message const& msg, + async_write(message_v1 const& msg, WriteHandler&& handler); /** Start pipelining a HTTP message to the stream asynchronously. @@ -473,7 +473,7 @@ public: typename async_completion< WriteHandler, void(error_code)>::result_type #endif - async_write(message&& msg, + async_write(message_v1&& msg, WriteHandler&& handler); private: diff --git a/examples/http_stream.ipp b/examples/http_stream.ipp index 6a952b41..860d17a0 100644 --- a/examples/http_stream.ipp +++ b/examples/http_stream.ipp @@ -20,10 +20,11 @@ #ifndef BEAST_HTTP_STREAM_IPP_INCLUDED #define BEAST_HTTP_STREAM_IPP_INCLUDED -#include -#include +#include #include #include +#include +#include #include namespace beast { @@ -40,14 +41,14 @@ class stream::read_op struct data { stream& s; - message& m; + message_v1& m; Handler h; bool cont; int state = 0; template data(DeducedHandler&& h_, stream& s_, - message& m_) + message_v1& m_) : s(s_) , m(m_) , h(std::forward(h_)) @@ -142,14 +143,14 @@ class stream::write_op : public op struct data { stream& s; - message m; + message_v1 m; Handler h; bool cont; int state = 0; template data(DeducedHandler&& h_, stream& s_, - message const& m_, + message_v1 const& m_, bool cont_) : s(s_) , m(m_) @@ -160,7 +161,7 @@ class stream::write_op : public op template data(DeducedHandler&& h_, stream& s_, - message&& m_, + message_v1&& m_, bool cont_) : s(s_) , m(std::move(m_)) @@ -305,7 +306,7 @@ template template void stream:: -read(message& msg, +read(message_v1& msg, error_code& ec) { beast::http::read(next_layer_, rd_buf_, msg, ec); @@ -316,7 +317,7 @@ template auto stream:: -async_read(message& msg, +async_read(message_v1& msg, ReadHandler&& handler) -> typename async_completion< ReadHandler, void(error_code)>::result_type @@ -334,7 +335,7 @@ template template void stream:: -write(message const& msg, +write(message_v1 const& msg, error_code& ec) { beast::http::write(next_layer_, msg, ec); @@ -345,7 +346,7 @@ template auto stream:: -async_write(message const& msg, +async_write(message_v1 const& msg, WriteHandler&& handler) -> typename async_completion< WriteHandler, void(error_code)>::result_type @@ -376,7 +377,7 @@ template auto stream:: -async_write(message&& msg, +async_write(message_v1&& msg, WriteHandler&& handler) -> typename async_completion< WriteHandler, void(error_code)>::result_type diff --git a/examples/http_sync_server.hpp b/examples/http_sync_server.hpp index 6343e36e..dbfdc52e 100644 --- a/examples/http_sync_server.hpp +++ b/examples/http_sync_server.hpp @@ -43,8 +43,8 @@ class http_sync_server using address_type = boost::asio::ip::address; using socket_type = boost::asio::ip::tcp::socket; - using req_type = request; - using resp_type = response; + using req_type = request_v1; + using resp_type = response_v1; boost::asio::io_service ios_; socket_type sock_; @@ -155,7 +155,7 @@ public: path = root_ + path; if(! boost::filesystem::exists(path)) { - response resp( + response_v1 resp( {404, "Not Found", req.version}); resp.headers.replace("Server", "http_sync_server"); resp.body = "The file '" + path + "' was not found"; @@ -164,7 +164,7 @@ public: if(ec) break; } - response resp( + resp_type resp( {200, "OK", req.version}); resp.headers.replace("Server", "http_sync_server"); resp.headers.replace("Content-Type", "text/html"); diff --git a/include/beast/http.hpp b/include/beast/http.hpp index 7fb9c3fd..7d6483a8 100644 --- a/include/beast/http.hpp +++ b/include/beast/http.hpp @@ -9,13 +9,15 @@ #define BEAST_HTTP_HPP_INCLUDED #include -#include +#include +#include #include #include #include #include +#include #include -#include +#include #include #include #include diff --git a/include/beast/http/basic_parser.hpp b/include/beast/http/basic_parser_v1.hpp similarity index 97% rename from include/beast/http/basic_parser.hpp rename to include/beast/http/basic_parser_v1.hpp index 734da661..c98d11ef 100644 --- a/include/beast/http/basic_parser.hpp +++ b/include/beast/http/basic_parser_v1.hpp @@ -5,13 +5,13 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_HTTP_BASIC_PARSER_HPP -#define BEAST_HTTP_BASIC_PARSER_HPP +#ifndef BEAST_HTTP_BASIC_PARSER_v1_HPP +#define BEAST_HTTP_BASIC_PARSER_v1_HPP #include #include #include -#include +#include #include #include #include @@ -37,7 +37,7 @@ enum values }; } // parse_flag -/** Parser for producing HTTP requests and responses. +/** Base class for parsing HTTP/1 requests and responses. During parsing, callbacks will be made to the derived class if those members are present (detected through SFINAE). The @@ -84,7 +84,7 @@ enum values @li `void on_complete(error_code& ec)` Called when the entire message has been parsed successfully. - At this point, basic_parser::complete() returns `true`, and + At this point, basic_parser_v1::complete() returns `true`, and the parser is ready to parse another message if keep_alive() would return `true`. @@ -109,10 +109,10 @@ enum values and the error is returned to the caller. */ template -class basic_parser +class basic_parser_v1 { private: - using self = basic_parser; + using self = basic_parser_v1; typedef void(self::*pmf_t)(error_code&, boost::string_ref const&); static std::uint64_t constexpr no_content_length = @@ -237,13 +237,13 @@ private: public: /// Copy constructor. - basic_parser(basic_parser const&) = default; + basic_parser_v1(basic_parser_v1 const&) = default; /// Copy assignment. - basic_parser& operator=(basic_parser const&) = default; + basic_parser_v1& operator=(basic_parser_v1 const&) = default; /// Constructor - basic_parser() + basic_parser_v1() { init(std::integral_constant{}); } @@ -759,6 +759,6 @@ private: } // http } // beast -#include +#include #endif diff --git a/include/beast/http/body_writer.hpp b/include/beast/http/body_writer.hpp new file mode 100644 index 00000000..a976bea5 --- /dev/null +++ b/include/beast/http/body_writer.hpp @@ -0,0 +1,19 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_HTTP_BODY_WRITER_HPP +#define BEAST_HTTP_BODY_WRITER_HPP + +// Convenience header to include everything necessary for +// declaring an object meeting the BodyWriter requirements. + +#include +#include +#include +#include + +#endif diff --git a/include/beast/http/detail/basic_parser.hpp b/include/beast/http/detail/basic_parser_v1.hpp similarity index 98% rename from include/beast/http/detail/basic_parser.hpp rename to include/beast/http/detail/basic_parser_v1.hpp index 27ee8e26..665cb93d 100644 --- a/include/beast/http/detail/basic_parser.hpp +++ b/include/beast/http/detail/basic_parser_v1.hpp @@ -5,8 +5,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_HTTP_DETAIL_BASIC_PARSER_HPP -#define BEAST_HTTP_DETAIL_BASIC_PARSER_HPP +#ifndef BEAST_HTTP_DETAIL_BASIC_PARSER_V1_HPP +#define BEAST_HTTP_DETAIL_BASIC_PARSER_V1_HPP #include #include diff --git a/include/beast/http/detail/has_content_length.hpp b/include/beast/http/detail/has_content_length.hpp new file mode 100644 index 00000000..6ec167c9 --- /dev/null +++ b/include/beast/http/detail/has_content_length.hpp @@ -0,0 +1,43 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_HTTP_DETAIL_HAS_CONTENT_LENGTH_HPP +#define BEAST_HTTP_DETAIL_HAS_CONTENT_LENGTH_HPP + +#include +#include + +namespace beast { +namespace http { +namespace detail { + +template +class has_content_length_value +{ + template().content_length()), + std::uint64_t>> + static R check(int); + template + static std::false_type check(...); + using type = decltype(check(0)); +public: + // `true` if `T` meets the requirements. + static bool const value = type::value; +}; + +// Determines if the writer can provide the content length +template +using has_content_length = + std::integral_constant::value>; + +} // detail +} // http +} // beast + +#endif diff --git a/include/beast/http/detail/write_preparation.hpp b/include/beast/http/detail/write_preparation.hpp deleted file mode 100644 index e957cba6..00000000 --- a/include/beast/http/detail/write_preparation.hpp +++ /dev/null @@ -1,83 +0,0 @@ -// -// Copyright (c) 2013-2016 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) -// - -#ifndef BEAST_HTTP_DETAIL_WRITE_PREPARATION_HPP -#define BEAST_HTTP_DETAIL_WRITE_PREPARATION_HPP - -#include -#include -#include -#include - -namespace beast { -namespace http { -namespace detail { - -template -class has_content_length_value -{ - template().content_length()), - std::size_t>> - static R check(int); - template - static std::false_type check(...); - using type = decltype(check(0)); -public: - // `true` if `T` meets the requirements. - static bool const value = type::value; -}; - -// Determines if the writer can provide the content length -template -using has_content_length = - std::integral_constant::value>; - -template -struct write_preparation -{ - using headers_type = - basic_headers>; - - message const& msg; - typename Body::writer w; - streambuf sb; - bool chunked; - bool close; - - explicit - write_preparation( - message const& msg_) - : msg(msg_) - , w(msg) - , chunked(rfc2616::token_in_list( - msg.headers["Transfer-Encoding"], "chunked")) - , close(rfc2616::token_in_list( - msg.headers["Connection"], "close") || - (msg.version < 11 && ! msg.headers.exists( - "Content-Length"))) - { - } - - void - init(error_code& ec) - { - w.init(ec); - if(ec) - return; - msg.write_firstline(sb); - write_fields(sb, msg.headers); - beast::write(sb, "\r\n"); - } -}; - -} // detail -} // http -} // beast - -#endif diff --git a/include/beast/http/empty_body.hpp b/include/beast/http/empty_body.hpp index 72ba9099..defe548b 100644 --- a/include/beast/http/empty_body.hpp +++ b/include/beast/http/empty_body.hpp @@ -8,8 +8,7 @@ #ifndef BEAST_HTTP_EMPTY_BODY_HPP #define BEAST_HTTP_EMPTY_BODY_HPP -#include -#include +#include #include #include #include @@ -35,9 +34,9 @@ private: struct reader { - template + template explicit - reader(message&) + reader(message&) { } @@ -49,9 +48,12 @@ private: struct writer { - template + writer(writer const&) = delete; + writer& operator=(writer const&) = delete; + + template explicit - writer(message const& m) + writer(message const& m) { } diff --git a/include/beast/http/impl/basic_parser.ipp b/include/beast/http/impl/basic_parser_v1.ipp similarity index 99% rename from include/beast/http/impl/basic_parser.ipp rename to include/beast/http/impl/basic_parser_v1.ipp index b8395578..4a17e780 100644 --- a/include/beast/http/impl/basic_parser.ipp +++ b/include/beast/http/impl/basic_parser_v1.ipp @@ -5,15 +5,15 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_IPP -#define BEAST_HTTP_IMPL_BASIC_PARSER_IPP +#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP +#define BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP namespace beast { namespace http { template bool -basic_parser:: +basic_parser_v1:: keep_alive() const { if(http_major_ > 0 && http_minor_ > 0) @@ -34,7 +34,7 @@ keep_alive() const template template std::size_t -basic_parser:: +basic_parser_v1:: write(ConstBufferSequence const& buffers, error_code& ec) { static_assert(is_ConstBufferSequence::value, @@ -51,7 +51,7 @@ write(ConstBufferSequence const& buffers, error_code& ec) template std::size_t -basic_parser:: +basic_parser_v1:: write(boost::asio::const_buffer const& buffer, error_code& ec) { using beast::http::detail::is_digit; @@ -1022,7 +1022,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec) template void -basic_parser:: +basic_parser_v1:: write_eof(error_code& ec) { switch(s_) @@ -1042,7 +1042,7 @@ write_eof(error_code& ec) template bool -basic_parser:: +basic_parser_v1:: needs_eof(std::true_type) const { return false; @@ -1050,7 +1050,7 @@ needs_eof(std::true_type) const template bool -basic_parser:: +basic_parser_v1:: needs_eof(std::false_type) const { // See RFC 2616 section 4.4 diff --git a/include/beast/http/impl/message.ipp b/include/beast/http/impl/message_v1.ipp similarity index 60% rename from include/beast/http/impl/message.ipp rename to include/beast/http/impl/message_v1.ipp index 31635d3b..8a939592 100644 --- a/include/beast/http/impl/message.ipp +++ b/include/beast/http/impl/message_v1.ipp @@ -5,33 +5,21 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_HTTP_IMPL_MESSAGE_IPP -#define BEAST_HTTP_IMPL_MESSAGE_IPP +#ifndef BEAST_HTTP_IMPL_MESSAGE_V1_IPP +#define BEAST_HTTP_IMPL_MESSAGE_V1_IPP -#include #include -#include +#include #include -#include -#include -#include #include -#include -#include #include namespace beast { namespace http { template -message:: -message() -{ -} - -template -message:: -message(request_params params) +message_v1:: +message_v1(request_params params) { static_assert(isRequest, "message is not a request"); this->method = params.method; @@ -40,8 +28,8 @@ message(request_params params) } template -message:: -message(response_params params) +message_v1:: +message_v1(response_params params) { static_assert(! isRequest, "message is not a response"); this->status = params.status; @@ -49,126 +37,11 @@ message(response_params params) version = params.version; } -template -template -void -message:: -write_firstline(Streambuf& streambuf, - std::true_type) const -{ - write(streambuf, this->method); - write(streambuf, " "); - write(streambuf, this->url); - switch(version) - { - case 10: - write(streambuf, " HTTP/1.0\r\n"); - break; - case 11: - write(streambuf, " HTTP/1.1\r\n"); - break; - default: - write(streambuf, " HTTP/"); - write(streambuf, version / 10); - write(streambuf, "."); - write(streambuf, version % 10); - write(streambuf, "\r\n"); - break; - } -} - -template -template -void -message:: -write_firstline(Streambuf& streambuf, - std::false_type) const -{ - switch(version) - { - case 10: - write(streambuf, "HTTP/1.0 "); - break; - case 11: - write(streambuf, "HTTP/1.1 "); - break; - default: - write(streambuf, " HTTP/"); - write(streambuf, version / 10); - write(streambuf, "."); - write(streambuf, version % 10); - write(streambuf, " "); - break; - } - write(streambuf, this->status); - write(streambuf, " "); - write(streambuf, this->reason); - write(streambuf, "\r\n"); -} - //------------------------------------------------------------------------------ -template -void -set_connection(bool keep_alive, - message& req) -{ - if(req.version >= 11) - { - if(! keep_alive) - req.headers.replace("Connection", "close"); - else - req.headers.erase("Connection"); - } - else - { - if(keep_alive) - req.headers.replace("Connection", "keep-alive"); - else - req.headers.erase("Connection"); - } -} - -template -void -set_connection(bool keep_alive, - message& resp, - message const& req) -{ - if(req.version >= 11) - { - if(rfc2616::token_in_list(req["Connection"], "close")) - keep_alive = false; - } - else - { - if(! rfc2616::token_in_list(req["Connection"], "keep-alive")) - keep_alive = false; - } - set_connection(keep_alive, resp); -} - -template -void -write_fields(Streambuf& streambuf, FieldSequence const& fields) -{ - static_assert(is_Streambuf::value, - "Streambuf requirements not met"); - //static_assert(is_FieldSequence::value, - // "FieldSequence requirements not met"); - for(auto const& field : fields) - { - write(streambuf, field.name()); - write(streambuf, ": "); - write(streambuf, field.value()); - write(streambuf, "\r\n"); - } -} - template bool -is_keep_alive(message const& msg) +is_keep_alive(message_v1 const& msg) { if(msg.version >= 11) { @@ -185,7 +58,7 @@ is_keep_alive(message const& msg) template bool -is_upgrade(message const& msg) +is_upgrade(message_v1 const& msg) { if(msg.version < 11) return false; @@ -207,14 +80,14 @@ template inline void prepare_options(prepare_info& pi, - message& msg) + message_v1& msg) { } template void prepare_option(prepare_info& pi, - message& msg, + message_v1& msg, connection value) { pi.connection_value = value; @@ -225,7 +98,7 @@ template< class Opt, class... Opts> void prepare_options(prepare_info& pi, - message& msg, + message_v1& msg, Opt&& opt, Opts&&... opts) { prepare_option(pi, msg, opt); @@ -236,7 +109,7 @@ prepare_options(prepare_info& pi, template void prepare_content_length(prepare_info& pi, - message const& msg, + message_v1 const& msg, std::true_type) { typename Body::writer w(msg); @@ -247,7 +120,7 @@ prepare_content_length(prepare_info& pi, template void prepare_content_length(prepare_info& pi, - message const& msg, + message_v1 const& msg, std::false_type) { pi.content_length = boost::none; @@ -258,7 +131,7 @@ prepare_content_length(prepare_info& pi, template void prepare_connection( - message& msg) + message_v1& msg) { if(msg.version >= 11) { @@ -286,7 +159,7 @@ template< bool isRequest, class Body, class Headers, class... Options> void -prepare(message& msg, +prepare(message_v1& msg, Options&&... options) { // VFALCO TODO diff --git a/include/beast/http/impl/read.ipp b/include/beast/http/impl/read.ipp index 19191ac4..ff036712 100644 --- a/include/beast/http/impl/read.ipp +++ b/include/beast/http/impl/read.ipp @@ -8,6 +8,7 @@ #ifndef BEAST_HTTP_IMPL_READ_IPP_HPP #define BEAST_HTTP_IMPL_READ_IPP_HPP +#include #include #include #include @@ -26,10 +27,10 @@ class read_op handler_alloc; using parser_type = - parser; + parser_v1; using message_type = - message; + message_v1; struct data { @@ -214,14 +215,14 @@ template void read(SyncReadStream& stream, Streambuf& streambuf, - message& m, + message_v1& m, error_code& ec) { static_assert(is_SyncReadStream::value, "SyncReadStream requirements not met"); static_assert(is_Streambuf::value, "Streambuf requirements not met"); - parser p; + parser_v1 p; bool started = false; for(;;) { @@ -264,7 +265,7 @@ template::result_type async_read(AsyncReadStream& stream, Streambuf& streambuf, - message& m, + message_v1& m, ReadHandler&& handler) { static_assert(is_AsyncReadStream::value, diff --git a/include/beast/http/impl/write.ipp b/include/beast/http/impl/write.ipp index 3b6d0ecb..57fe6a12 100644 --- a/include/beast/http/impl/write.ipp +++ b/include/beast/http/impl/write.ipp @@ -10,12 +10,13 @@ #include #include -#include +#include #include #include #include #include #include +#include #include #include #include @@ -29,6 +30,114 @@ namespace http { namespace detail { +template +void +write_firstline(Streambuf& streambuf, + message_v1 const& msg) +{ + write(streambuf, msg.method); + write(streambuf, " "); + write(streambuf, msg.url); + switch(msg.version) + { + case 10: + write(streambuf, " HTTP/1.0\r\n"); + break; + case 11: + write(streambuf, " HTTP/1.1\r\n"); + break; + default: + write(streambuf, " HTTP/"); + write(streambuf, msg.version / 10); + write(streambuf, "."); + write(streambuf, msg.version % 10); + write(streambuf, "\r\n"); + break; + } +} + +template +void +write_firstline(Streambuf& streambuf, + message_v1 const& msg) +{ + switch(msg.version) + { + case 10: + write(streambuf, "HTTP/1.0 "); + break; + case 11: + write(streambuf, "HTTP/1.1 "); + break; + default: + write(streambuf, " HTTP/"); + write(streambuf, msg.version / 10); + write(streambuf, "."); + write(streambuf, msg.version % 10); + write(streambuf, " "); + break; + } + write(streambuf, msg.status); + write(streambuf, " "); + write(streambuf, msg.reason); + write(streambuf, "\r\n"); +} + +template +void +write_fields(Streambuf& streambuf, FieldSequence const& fields) +{ + static_assert(is_Streambuf::value, + "Streambuf requirements not met"); + //static_assert(is_FieldSequence::value, + // "FieldSequence requirements not met"); + for(auto const& field : fields) + { + write(streambuf, field.name()); + write(streambuf, ": "); + write(streambuf, field.value()); + write(streambuf, "\r\n"); + } +} + +template +struct write_preparation +{ + using headers_type = + basic_headers>; + + message_v1 const& msg; + typename Body::writer w; + streambuf sb; + bool chunked; + bool close; + + explicit + write_preparation( + message_v1 const& msg_) + : msg(msg_) + , w(msg) + , chunked(rfc2616::token_in_list( + msg.headers["Transfer-Encoding"], "chunked")) + , close(rfc2616::token_in_list( + msg.headers["Connection"], "close") || + (msg.version < 11 && ! msg.headers.exists( + "Content-Length"))) + { + } + + void + init(error_code& ec) + { + w.init(ec); + if(ec) + return; + write_firstline(sb, msg); + write_fields(sb, msg.headers); + beast::write(sb, "\r\n"); + } +}; + template class write_op @@ -50,7 +159,7 @@ class write_op template data(DeducedHandler&& h_, Stream& s_, - message const& m_) + message_v1 const& m_) : s(s_) , wp(m_) , h(std::forward(h_)) @@ -356,7 +465,21 @@ template void write(SyncWriteStream& stream, - message const& msg, + message_v1 const& msg) +{ + static_assert(is_SyncWriteStream::value, + "SyncWriteStream requirements not met"); + error_code ec; + write(stream, msg, ec); + if(ec) + throw boost::system::system_error{ec}; +} + +template +void +write(SyncWriteStream& stream, + message_v1 const& msg, boost::system::error_code& ec) { static_assert(is_SyncWriteStream::value, @@ -441,7 +564,7 @@ template::result_type async_write(AsyncWriteStream& stream, - message const& msg, + message_v1 const& msg, WriteHandler&& handler) { static_assert( @@ -506,7 +629,7 @@ public: template std::ostream& operator<<(std::ostream& os, - message const& msg) + message_v1 const& msg) { detail::ostream_SyncStream oss(os); error_code ec; diff --git a/include/beast/http/message.hpp b/include/beast/http/message.hpp index 1c0c0c81..bb0ab957 100644 --- a/include/beast/http/message.hpp +++ b/include/beast/http/message.hpp @@ -32,24 +32,6 @@ struct response_fields } // detail -#if ! GENERATING_DOCS - -struct request_params -{ - std::string method; - std::string url; - int version; -}; - -struct response_params -{ - int status; - std::string reason; - int version; -}; - -#endif - /** A HTTP message. A message can be a request or response, depending on the `isRequest` @@ -70,62 +52,24 @@ struct message : std::conditional::type { - /** The trait type characterizing the body. + /** The type controlling the body traits. - The body member will be of type body_type::value_type. + The body member will be of type `body_type::value_type`. */ using body_type = Body; + + /// The type representing the headers. using headers_type = Headers; + /// Indicates if the message is a request. using is_request = std::integral_constant; - int version; // 10 or 11 + /// The container holding the headers. headers_type headers; + + /// A container representing the body. typename Body::value_type body; - - message(); - message(message&&) = default; - message(message const&) = default; - message& operator=(message&&) = default; - message& operator=(message const&) = default; - - /** Construct a HTTP request. - */ - explicit - message(request_params params); - - /** Construct a HTTP response. - */ - explicit - message(response_params params); - - /// Serialize the request or response line to a Streambuf. - template - void - write_firstline(Streambuf& streambuf) const - { - write_firstline(streambuf, - std::integral_constant{}); - } - - /// Diagnostics only - template - friend - std::ostream& - operator<<(std::ostream& os, - message const& m); - -private: - template - void - write_firstline(Streambuf& streambuf, - std::true_type) const; - - template - void - write_firstline(Streambuf& streambuf, - std::false_type) const; }; #if ! GENERATING_DOCS @@ -142,53 +86,7 @@ using response = message; #endif -/// Write a FieldSequence to a Streambuf. -template -void -write_fields(Streambuf& streambuf, FieldSequence const& fields); - -/// Returns `true` if a message indicates a keep alive -template -bool -is_keep_alive(message const& msg); - -/// Returns `true` if a message indicates a HTTP Upgrade request or response -template -bool -is_upgrade(message const& msg); - -/** Connection prepare options. - - These values are used with prepare(). -*/ -enum class connection -{ - /// Indicates the message should specify Connection: close semantics - close, - - /// Indicates the message should specify Connection: keep-alive semantics if possible - keep_alive, - - /// Indicates the message should specify a Connection: upgrade - upgrade -}; - -/** Prepare a message. - - This function will adjust the Content-Length, Transfer-Encoding, - and Connection headers of the message based on the properties of - the body and the options passed in. -*/ -template< - bool isRequest, class Body, class Headers, - class... Options> -void -prepare(message& msg, - Options&&... options); - } // http } // beast -#include - #endif diff --git a/include/beast/http/message_v1.hpp b/include/beast/http/message_v1.hpp new file mode 100644 index 00000000..3f33ddfa --- /dev/null +++ b/include/beast/http/message_v1.hpp @@ -0,0 +1,131 @@ +// +// Copyright (c) 2013-2016 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) +// + +#ifndef BEAST_HTTP_MESSAGE_V1_HPP +#define BEAST_HTTP_MESSAGE_V1_HPP + +#include +#include +#include +#include + +namespace beast { +namespace http { + +#if ! GENERATING_DOCS + +struct request_params +{ + std::string method; + std::string url; + int version; +}; + +struct response_params +{ + int status; + std::string reason; + int version; +}; + +#endif + +/** A HTTP/1 message. + + A message can be a request or response, depending on the `isRequest` + template argument value. Requests and responses have different types, + so functions may be overloaded on them if desired. + + The `Body` template argument type determines the model used + to read or write the content body of the message. + + @tparam isRequest `true` if this is a request. + + @tparam Body A type meeting the requirements of Body. + + @tparam Headers A type meeting the requirements of Headers. +*/ +template +struct message_v1 : message +{ + /// HTTP/1 version (10 or 11) + int version; + + message_v1() = default; + + /// Construct a HTTP/1 request. + explicit + message_v1(request_params params); + + /// Construct a HTTP/1 response. + explicit + message_v1(response_params params); +}; + +#if ! GENERATING_DOCS + +/// A typical HTTP/1 request +template>> +using request_v1 = message_v1; + +/// A typical HTTP/1 response +template>> +using response_v1 = message_v1; + +#endif + +/// Returns `true` if a HTTP/1 message indicates a keep alive +template +bool +is_keep_alive(message_v1 const& msg); + +/// Returns `true` if a HTTP/1 message indicates an Upgrade request or response +template +bool +is_upgrade(message_v1 const& msg); + +/** HTTP/1 connection prepare options. + + @note These values are used with `prepare`. +*/ +enum class connection +{ + /// Specify Connection: close. + close, + + /// Specify Connection: keep-alive where possible. + keep_alive, + + /// Specify Connection: upgrade. + upgrade +}; + +/** Prepare a HTTP/1 message. + + This function will adjust the Content-Length, Transfer-Encoding, + and Connection headers of the message based on the properties of + the body and the options passed in. + + @param msg The message to prepare. The headers may be modified. + + @param options A list of prepare options. +*/ +template< + bool isRequest, class Body, class Headers, + class... Options> +void +prepare(message_v1& msg, + Options&&... options); + +} // http +} // beast + +#include + +#endif diff --git a/include/beast/http/parser.hpp b/include/beast/http/parser_v1.hpp similarity index 82% rename from include/beast/http/parser.hpp rename to include/beast/http/parser_v1.hpp index 4161a877..3dc692c5 100644 --- a/include/beast/http/parser.hpp +++ b/include/beast/http/parser_v1.hpp @@ -5,12 +5,12 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_HTTP_PARSER_HPP -#define BEAST_HTTP_PARSER_HPP +#ifndef BEAST_HTTP_PARSER_V1_HPP +#define BEAST_HTTP_PARSER_V1_HPP -#include +#include #include -#include +#include #include #include #include @@ -35,15 +35,20 @@ struct parser_response } // detail +/** A parser for producing HTTP/1 messages. + + This class uses the basic HTTP/1 wire format parser to convert + a series of octets into a `message_v1`. +*/ template -class parser - : public basic_parser> +class parser_v1 + : public basic_parser_v1> , private std::conditional::type { using message_type = - message; + message_v1; std::string field_; std::string value_; @@ -51,9 +56,9 @@ class parser typename message_type::body_type::reader r_; public: - parser(parser&&) = default; + parser_v1(parser_v1&&) = default; - parser() + parser_v1() : r_(m_) { } @@ -65,7 +70,7 @@ public: } private: - friend class basic_parser; + friend class basic_parser_v1; void flush() { diff --git a/include/beast/http/read.hpp b/include/beast/http/read.hpp index 78cfa5a3..e792961a 100644 --- a/include/beast/http/read.hpp +++ b/include/beast/http/read.hpp @@ -8,16 +8,16 @@ #ifndef BEAST_HTTP_READ_HPP #define BEAST_HTTP_READ_HPP -#include #include -#include +#include +#include #include #include namespace beast { namespace http { -/** Read a HTTP message from a stream. +/** Read a HTTP/1 message from a stream. @param stream The stream to read the message from. @@ -35,7 +35,7 @@ template void read(SyncReadStream& stream, Streambuf& streambuf, - message& msg) + message_v1& msg) { error_code ec; read(stream, streambuf, msg, ec); @@ -61,7 +61,7 @@ template void read(SyncReadStream& stream, Streambuf& streambuf, - message& msg, + message_v1& msg, error_code& ec); /** Start reading a HTTP message from a stream asynchronously. @@ -97,7 +97,7 @@ typename async_completion< ReadHandler, void(error_code)>::result_type #endif async_read(AsyncReadStream& stream, Streambuf& streambuf, - message& msg, + message_v1& msg, ReadHandler&& handler); } // http diff --git a/include/beast/http/streambuf_body.hpp b/include/beast/http/streambuf_body.hpp index 02238ec1..4644e61b 100644 --- a/include/beast/http/streambuf_body.hpp +++ b/include/beast/http/streambuf_body.hpp @@ -8,8 +8,7 @@ #ifndef BEAST_HTTP_STREAMBUF_BODY_HPP #define BEAST_HTTP_STREAMBUF_BODY_HPP -#include -#include +#include #include #include #include @@ -59,10 +58,13 @@ private: Streambuf const& body_; public: - template + writer(writer const&) = delete; + writer& operator=(writer const&) = delete; + + template explicit - writer(message const& m) + writer(message< + isRequest, basic_streambuf_body, Headers> const& m) : body_(m.body) { } diff --git a/include/beast/http/string_body.hpp b/include/beast/http/string_body.hpp index 81b07044..f852bbd0 100644 --- a/include/beast/http/string_body.hpp +++ b/include/beast/http/string_body.hpp @@ -8,9 +8,7 @@ #ifndef BEAST_HTTP_STRING_BODY_HPP #define BEAST_HTTP_STRING_BODY_HPP -#include -#include -#include +#include #include #include #include @@ -58,9 +56,13 @@ private: value_type const& body_; public: - template + writer(writer const&) = delete; + writer& operator=(writer const&) = delete; + + template explicit - writer(message const& msg) + writer(message< + isRequest, string_body, Headers> const& msg) : body_(msg.body) { } diff --git a/include/beast/http/write.hpp b/include/beast/http/write.hpp index ae71b486..22aa2e76 100644 --- a/include/beast/http/write.hpp +++ b/include/beast/http/write.hpp @@ -9,9 +9,8 @@ #define BEAST_HTTP_WRITE_HPP #include -#include +#include #include -#include #include #include #include @@ -19,7 +18,7 @@ namespace beast { namespace http { -/** Write a HTTP message to a stream. +/** Write a HTTP/1 message to a stream. @param stream The stream to send the message on. @@ -31,15 +30,9 @@ template void write(SyncWriteStream& stream, - message const& msg) -{ - error_code ec; - write(stream, msg, ec); - if(ec) - throw boost::system::system_error{ec}; -} + message_v1 const& msg); -/** Write a HTTP message to a stream. +/** Write a HTTP/1 message to a stream. @param stream The stream to send the message on. @@ -51,10 +44,10 @@ template void write(SyncWriteStream& stream, - message const& msg, + message_v1 const& msg, error_code& ec); -/** Start writing a HTTP message to a stream asynchronously. +/** Start writing a HTTP/1 message to a stream asynchronously. @param stream The stream to send the message on. @@ -84,12 +77,12 @@ typename async_completion< WriteHandler, void(error_code)>::result_type #endif async_write(AsyncWriteStream& stream, - message const& msg, + message_v1 const& msg, WriteHandler&& handler); -/** Serialize a message to an ostream. +/** Serialize a HTTP/1 message to an ostream. - The function converts the message to its HTTP/1.* serialized + The function converts the message to its HTTP/1 serialized representation and stores the result in the output stream. @param os The ostream to write to. @@ -99,7 +92,7 @@ async_write(AsyncWriteStream& stream, template std::ostream& operator<<(std::ostream& os, - message const& msg); + message_v1 const& msg); } // http } // beast diff --git a/include/beast/websocket/impl/accept_op.ipp b/include/beast/websocket/impl/accept_op.ipp index a171d2df..87b3f223 100644 --- a/include/beast/websocket/impl/accept_op.ipp +++ b/include/beast/websocket/impl/accept_op.ipp @@ -9,10 +9,11 @@ #define BEAST_WEBSOCKET_IMPL_ACCEPT_OP_HPP #include +#include +#include +#include #include #include -#include -#include #include #include #include @@ -32,7 +33,7 @@ class stream::accept_op struct data { stream& ws; - http::request req; + http::request_v1 req; Handler h; bool cont; int state = 0; diff --git a/include/beast/websocket/impl/handshake_op.ipp b/include/beast/websocket/impl/handshake_op.ipp index 544b5970..64725166 100644 --- a/include/beast/websocket/impl/handshake_op.ipp +++ b/include/beast/websocket/impl/handshake_op.ipp @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include @@ -33,8 +33,8 @@ class stream::handshake_op stream& ws; Handler h; std::string key; - http::request req; - http::response resp; + http::request_v1 req; + http::response_v1 resp; bool cont; int state = 0; diff --git a/include/beast/websocket/impl/response_op.ipp b/include/beast/websocket/impl/response_op.ipp index 0d11bee6..578cdb67 100644 --- a/include/beast/websocket/impl/response_op.ipp +++ b/include/beast/websocket/impl/response_op.ipp @@ -9,6 +9,7 @@ #define BEAST_WEBSOCKET_IMPL_RESPONSE_OP_HPP #include +#include #include #include #include @@ -27,7 +28,7 @@ class stream::response_op struct data { stream& ws; - http::response resp; + http::response_v1 resp; Handler h; error_code final_ec; bool cont; @@ -36,7 +37,7 @@ class stream::response_op template data(DeducedHandler&& h_, stream& ws_, - http::message const& req, + http::request_v1 const& req, bool cont_) : ws(ws_) , resp(ws_.build_response(req)) diff --git a/include/beast/websocket/impl/stream.ipp b/include/beast/websocket/impl/stream.ipp index 4d875b79..2b544c02 100644 --- a/include/beast/websocket/impl/stream.ipp +++ b/include/beast/websocket/impl/stream.ipp @@ -241,7 +241,7 @@ accept(ConstBufferSequence const& buffers, error_code& ec) stream_.buffer().commit(buffer_copy( stream_.buffer().prepare( buffer_size(buffers)), buffers)); - http::request m; + http::request_v1 m; http::read(next_layer(), stream_.buffer(), m, ec); if(ec) return; @@ -272,7 +272,7 @@ template template void stream:: -accept(http::message const& request) +accept(http::request_v1 const& request) { static_assert(is_SyncStream::value, "SyncStream requirements not met"); @@ -285,12 +285,12 @@ template template void stream:: -accept(http::message const& req, +accept(http::request_v1 const& req, error_code& ec) { static_assert(is_SyncStream::value, "SyncStream requirements not met"); - auto resp = build_response(req); + auto const resp = build_response(req); http::write(stream_, resp, ec); if(resp.status != 101) { @@ -307,7 +307,7 @@ template typename async_completion< AcceptHandler, void(error_code)>::result_type stream:: -async_accept(http::message const& req, +async_accept(http::request_v1 const& req, AcceptHandler&& handler) { static_assert(is_AsyncStream::value, @@ -348,7 +348,7 @@ handshake(boost::string_ref const& host, build_request(host, resource, key), ec); if(ec) return; - http::response resp; + http::response_v1 resp; http::read(next_layer(), stream_.buffer(), resp, ec); if(ec) return; @@ -826,12 +826,12 @@ async_write_frame(bool fin, //------------------------------------------------------------------------------ template -http::request +http::request_v1 stream:: build_request(boost::string_ref const& host, boost::string_ref const& resource, std::string& key) { - http::request req; + http::request_v1 req; req.url = "/"; req.version = 11; req.method = "GET"; @@ -847,14 +847,14 @@ build_request(boost::string_ref const& host, template template -http::response +http::response_v1 stream:: -build_response(http::message const& req) +build_response(http::request_v1 const& req) { auto err = [&](std::string const& text) { - http::response resp( + http::response_v1 resp( {400, http::reason_string(400), req.version}); resp.body = text; // VFALCO TODO respect keep-alive here @@ -881,7 +881,7 @@ build_response(http::message const& req) if(! rfc2616::token_in_list( req.headers["Upgrade"], "websocket")) return err("Missing websocket Upgrade token"); - http::response resp( + http::response_v1 resp( {101, http::reason_string(101), req.version}); resp.headers.insert("Upgrade", "websocket"); { @@ -901,7 +901,7 @@ template template void stream:: -do_response(http::message const& resp, +do_response(http::response_v1 const& resp, boost::string_ref const& key, error_code& ec) { // VFALCO Review these error codes diff --git a/include/beast/websocket/stream.hpp b/include/beast/websocket/stream.hpp index 2fa82fa4..0f98ae93 100644 --- a/include/beast/websocket/stream.hpp +++ b/include/beast/websocket/stream.hpp @@ -10,11 +10,11 @@ #include #include +#include +#include #include #include #include -#include -#include #include #include #include @@ -495,8 +495,7 @@ public: // VFALCO TODO This should also take a streambuf with any leftover bytes. template void - accept(http::message const& request); + accept(http::request_v1 const& request); /** Respond to a WebSocket HTTP Upgrade request @@ -525,8 +524,8 @@ public: */ template void - accept(http::message const& request, error_code& ec); + accept(http::request_v1 const& request, + error_code& ec); /** Start reading and responding to a WebSocket HTTP Upgrade request. @@ -560,8 +559,8 @@ public: template typename async_completion< AcceptHandler, void(error_code)>::result_type - async_accept(http::message const& request, AcceptHandler&& handler); + async_accept(http::request_v1 const& request, + AcceptHandler&& handler); /** Send a WebSocket Upgrade request. @@ -1129,18 +1128,18 @@ private: template class write_op; template class write_frame_op; - http::request + http::request_v1 build_request(boost::string_ref const& host, boost::string_ref const& resource, std::string& key); template - http::response - build_response(http::message const& req); + http::response_v1 + build_response(http::request_v1 const& req); template void - do_response(http::message const& resp, + do_response(http::response_v1 const& resp, boost::string_ref const& key, error_code& ec); void diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0bc7277b..796a890a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -33,11 +33,12 @@ add_executable (http-tests ${BEAST_INCLUDES} main.cpp http/basic_headers.cpp - http/basic_parser.cpp + http/basic_parser_v1.cpp http/empty_body.cpp http/error.cpp http/headers.cpp http/message.cpp + http/message_v1.cpp http/parse_error.cpp http/parser.cpp http/read.cpp diff --git a/test/Jamfile b/test/Jamfile index afb02389..fe441cd2 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -31,11 +31,12 @@ unit-test core-tests : unit-test http-tests : main.cpp http/basic_headers.cpp - http/basic_parser.cpp + http/basic_parser_v1.cpp http/empty_body.cpp http/error.cpp http/headers.cpp http/message.cpp + http/message_v1.cpp http/parse_error.cpp http/parser.cpp http/read.cpp diff --git a/test/http/basic_parser.cpp b/test/http/basic_parser_v1.cpp similarity index 97% rename from test/http/basic_parser.cpp rename to test/http/basic_parser_v1.cpp index 1892b4cc..887b7570 100644 --- a/test/http/basic_parser.cpp +++ b/test/http/basic_parser_v1.cpp @@ -6,7 +6,7 @@ // // Test that header file is self-contained. -#include +#include #include "message_fuzz.hpp" @@ -27,7 +27,7 @@ namespace beast { namespace http { -class basic_parser_test : public beast::detail::unit_test::suite +class basic_parser_v1_test : public beast::detail::unit_test::suite { std::mt19937 rng_; @@ -47,9 +47,9 @@ public: template struct cb_checker - : public basic_parser> + : public basic_parser_v1> , std::conditional::type + cb_req_checker, cb_res_checker>::type { bool field = false; @@ -59,7 +59,7 @@ public: bool complete = false; private: - friend class basic_parser>; + friend class basic_parser_v1>; void on_method(boost::string_ref const&, error_code&) { @@ -129,13 +129,13 @@ public: } template - struct null_parser : basic_parser> + struct null_parser : basic_parser_v1> { }; template class test_parser : - public basic_parser> + public basic_parser_v1> { std::string field_; std::string value_; @@ -635,7 +635,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(basic_parser,http,beast); +BEAST_DEFINE_TESTSUITE(basic_parser_v1,http,beast); } // http } // beast diff --git a/test/http/message.cpp b/test/http/message.cpp index f559f49d..c9ebd0de 100644 --- a/test/http/message.cpp +++ b/test/http/message.cpp @@ -19,168 +19,3 @@ // Test that header file is self-contained. #include - -#include -#include -#include -#include -#include -#include - -namespace beast { -namespace http { -namespace test { - -class sync_echo_http_server -{ -public: - using error_code = boost::system::error_code; - using endpoint_type = boost::asio::ip::tcp::endpoint; - using address_type = boost::asio::ip::address; - using socket_type = boost::asio::ip::tcp::socket; - -private: - beast::detail::unit_test::suite& suite_; - boost::asio::io_service ios_; - socket_type sock_; - boost::asio::ip::tcp::acceptor acceptor_; - beast::detail::unit_test::thread thread_; - -public: - sync_echo_http_server( - endpoint_type ep, beast::detail::unit_test::suite& suite) - : suite_(suite) - , sock_(ios_) - , acceptor_(ios_) - { - error_code ec; - acceptor_.open(ep.protocol(), ec); - maybe_throw(ec, "open"); - acceptor_.bind(ep, ec); - maybe_throw(ec, "bind"); - acceptor_.listen( - boost::asio::socket_base::max_connections, ec); - maybe_throw(ec, "listen"); - acceptor_.async_accept(sock_, - std::bind(&sync_echo_http_server::on_accept, this, - beast::asio::placeholders::error)); - thread_ = beast::detail::unit_test::thread(suite_, - [&] - { - ios_.run(); - }); - } - - ~sync_echo_http_server() - { - error_code ec; - ios_.dispatch( - [&]{ acceptor_.close(ec); }); - thread_.join(); - } - -private: - void - fail(error_code ec, std::string what) - { - suite_.log << - what << ": " << ec.message(); - } - - void - maybe_throw(error_code ec, std::string what) - { - if(ec && - ec != boost::asio::error::operation_aborted) - { - fail(ec, what); - throw ec; - } - } - - void - on_accept(error_code ec) - { - if(ec == boost::asio::error::operation_aborted) - return; - maybe_throw(ec, "accept"); - std::thread{&sync_echo_http_server::do_client, this, - std::move(sock_), boost::asio::io_service::work{ - sock_.get_io_service()}}.detach(); - acceptor_.async_accept(sock_, - std::bind(&sync_echo_http_server::on_accept, this, - beast::asio::placeholders::error)); - } - - void - do_client(socket_type sock, boost::asio::io_service::work) - { - error_code ec; - streambuf rb; - for(;;) - { - request req; - read(sock, rb, req, ec); - if(ec) - break; - response resp( - {100, "OK", req.version}); - resp.body = "Completed successfully."; - write(sock, resp, ec); - if(ec) - break; - } - } -}; - -class message_test : public beast::detail::unit_test::suite -{ -public: - using error_code = boost::system::error_code; - using endpoint_type = boost::asio::ip::tcp::endpoint; - using address_type = boost::asio::ip::address; - using socket_type = boost::asio::ip::tcp::socket; - - void - syncEcho(endpoint_type ep) - { - boost::asio::io_service ios; - socket_type sock(ios); - sock.connect(ep); - - streambuf rb; - { - request req({"GET", "/", 11}); - req.body = "Beast.HTTP"; - req.headers.replace("Host", - ep.address().to_string() + ":" + - std::to_string(ep.port())); - write(sock, req); - } - { - response m; - read(sock, rb, m); - } - } - - void - testAsio() - { - endpoint_type ep{ - address_type::from_string("127.0.0.1"), 6000}; - sync_echo_http_server s(ep, *this); - syncEcho(ep); - } - - void run() override - { - testAsio(); - pass(); - } -}; - -BEAST_DEFINE_TESTSUITE(message,http,beast); - -} // test -} // http -} // beast diff --git a/test/http/message_fuzz.hpp b/test/http/message_fuzz.hpp index 7d0254ee..bf5f3296 100644 --- a/test/http/message_fuzz.hpp +++ b/test/http/message_fuzz.hpp @@ -8,7 +8,7 @@ #ifndef BEAST_HTTP_TEST_MESSAGE_FUZZ_HPP #define BEAST_HTTP_TEST_MESSAGE_FUZZ_HPP -#include +#include #include #include #include diff --git a/test/http/message_v1.cpp b/test/http/message_v1.cpp new file mode 100644 index 00000000..8aec50bd --- /dev/null +++ b/test/http/message_v1.cpp @@ -0,0 +1,186 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +// Test that header file is self-contained. +#include + +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace http { +namespace test { + +class sync_echo_http_server +{ +public: + using error_code = boost::system::error_code; + using endpoint_type = boost::asio::ip::tcp::endpoint; + using address_type = boost::asio::ip::address; + using socket_type = boost::asio::ip::tcp::socket; + +private: + beast::detail::unit_test::suite& suite_; + boost::asio::io_service ios_; + socket_type sock_; + boost::asio::ip::tcp::acceptor acceptor_; + beast::detail::unit_test::thread thread_; + +public: + sync_echo_http_server( + endpoint_type ep, beast::detail::unit_test::suite& suite) + : suite_(suite) + , sock_(ios_) + , acceptor_(ios_) + { + error_code ec; + acceptor_.open(ep.protocol(), ec); + maybe_throw(ec, "open"); + acceptor_.bind(ep, ec); + maybe_throw(ec, "bind"); + acceptor_.listen( + boost::asio::socket_base::max_connections, ec); + maybe_throw(ec, "listen"); + acceptor_.async_accept(sock_, + std::bind(&sync_echo_http_server::on_accept, this, + beast::asio::placeholders::error)); + thread_ = beast::detail::unit_test::thread(suite_, + [&] + { + ios_.run(); + }); + } + + ~sync_echo_http_server() + { + error_code ec; + ios_.dispatch( + [&]{ acceptor_.close(ec); }); + thread_.join(); + } + +private: + void + fail(error_code ec, std::string what) + { + suite_.log << + what << ": " << ec.message(); + } + + void + maybe_throw(error_code ec, std::string what) + { + if(ec && + ec != boost::asio::error::operation_aborted) + { + fail(ec, what); + throw ec; + } + } + + void + on_accept(error_code ec) + { + if(ec == boost::asio::error::operation_aborted) + return; + maybe_throw(ec, "accept"); + std::thread{&sync_echo_http_server::do_client, this, + std::move(sock_), boost::asio::io_service::work{ + sock_.get_io_service()}}.detach(); + acceptor_.async_accept(sock_, + std::bind(&sync_echo_http_server::on_accept, this, + beast::asio::placeholders::error)); + } + + void + do_client(socket_type sock, boost::asio::io_service::work) + { + error_code ec; + streambuf rb; + for(;;) + { + request_v1 req; + read(sock, rb, req, ec); + if(ec) + break; + response_v1 resp( + {100, "OK", req.version}); + resp.body = "Completed successfully."; + write(sock, resp, ec); + if(ec) + break; + } + } +}; + +class message_test : public beast::detail::unit_test::suite +{ +public: + using error_code = boost::system::error_code; + using endpoint_type = boost::asio::ip::tcp::endpoint; + using address_type = boost::asio::ip::address; + using socket_type = boost::asio::ip::tcp::socket; + + void + syncEcho(endpoint_type ep) + { + boost::asio::io_service ios; + socket_type sock(ios); + sock.connect(ep); + + streambuf rb; + { + request_v1 req({"GET", "/", 11}); + req.body = "Beast.HTTP"; + req.headers.replace("Host", + ep.address().to_string() + ":" + + std::to_string(ep.port())); + write(sock, req); + } + { + response_v1 m; + read(sock, rb, m); + } + } + + void + testAsio() + { + endpoint_type ep{ + address_type::from_string("127.0.0.1"), 6000}; + sync_echo_http_server s(ep, *this); + syncEcho(ep); + } + + void run() override + { + testAsio(); + pass(); + } +}; + +BEAST_DEFINE_TESTSUITE(message,http,beast); + +} // test +} // http +} // beast diff --git a/test/http/nodejs_parser.hpp b/test/http/nodejs_parser.hpp index 4820a067..65419850 100644 --- a/test/http/nodejs_parser.hpp +++ b/test/http/nodejs_parser.hpp @@ -10,7 +10,8 @@ #include "nodejs-parser/http_parser.h" -#include +#include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include namespace beast { namespace http { @@ -730,19 +732,6 @@ nodejs_basic_parser::cb_chunk_complete(http_parser*) return 0; } -} // http -} // beast - -#include -#include -#include -#include -#include -#include - -namespace beast { -namespace http { - /** A HTTP parser. The parser may only be used once. @@ -752,7 +741,7 @@ class nodejs_parser : public nodejs_basic_parser> { using message_type = - message; + message_v1; message_type m_; typename message_type::body_type::reader r_; diff --git a/test/http/parser.cpp b/test/http/parser.cpp index 895ef73e..7e090a8e 100644 --- a/test/http/parser.cpp +++ b/test/http/parser.cpp @@ -6,7 +6,7 @@ // // Test that header file is self-contained. -#include +#include #include #include @@ -23,7 +23,7 @@ public: using boost::asio::buffer; { error_code ec; - parser>> p; std::string const s = "GET / HTTP/1.1\r\n" @@ -43,7 +43,7 @@ public: } { error_code ec; - parser>> p; std::string const s = "HTTP/1.1 200 OK\r\n" diff --git a/test/http/parser_bench.cpp b/test/http/parser_bench.cpp index d7e5577f..c78acee1 100644 --- a/test/http/parser_bench.cpp +++ b/test/http/parser_bench.cpp @@ -97,7 +97,7 @@ public: } template - struct null_parser : basic_parser> + struct null_parser : basic_parser_v1> { }; @@ -108,10 +108,10 @@ public: static std::size_t constexpr Repeat = 50; log << "sizeof(request parser) == " << - sizeof(basic_parser>); + sizeof(basic_parser_v1>); log << "sizeof(response parser) == " << - sizeof(basic_parser>); + sizeof(basic_parser_v1>); testcase << "Parser speed test, " << ((Repeat * size_ + 512) / 1024) << "KB in " << @@ -127,13 +127,13 @@ public: false, streambuf_body, headers>>( Repeat, cres_); }); - timedTest(Trials, "http::basic_parser", + timedTest(Trials, "http::basic_parser_v1", [&] { - testParser>( Repeat, creq_); - testParser>( Repeat, cres_); }); diff --git a/test/http/write.cpp b/test/http/write.cpp index 9e4b9e41..8dd9c119 100644 --- a/test/http/write.cpp +++ b/test/http/write.cpp @@ -89,7 +89,7 @@ public: template std::string - str(message const& m) + str(message_v1 const& m) { string_SyncStream ss; write(ss, m); @@ -101,7 +101,7 @@ public: { // auto content-length HTTP/1.0 { - message m{{ + message_v1 m{{ "GET", "/", 10}}; m.headers.insert("User-Agent", "test"); m.body = "*"; @@ -116,7 +116,7 @@ public: } // keep-alive HTTP/1.0 { - message m{{ + message_v1 m{{ "GET", "/", 10}}; m.headers.insert("User-Agent", "test"); m.body = "*"; @@ -132,7 +132,7 @@ public: } // upgrade HTTP/1.0 { - message m{{ + message_v1 m{{ "GET", "/", 10}}; m.headers.insert("User-Agent", "test"); m.body = "*"; @@ -148,7 +148,7 @@ public: } // no content-length HTTP/1.0 { - message m{{ + message_v1 m{{ "GET", "/", 10}}; m.headers.insert("User-Agent", "test"); m.body = "*"; @@ -166,7 +166,7 @@ public: } // auto content-length HTTP/1.1 { - message m{{ + message_v1 m{{ "GET", "/", 11}}; m.headers.insert("User-Agent", "test"); m.body = "*"; @@ -181,7 +181,7 @@ public: } // close HTTP/1.1 { - message m{{ + message_v1 m{{ "GET", "/", 11}}; m.headers.insert("User-Agent", "test"); m.body = "*"; @@ -201,7 +201,7 @@ public: } // upgrade HTTP/1.1 { - message m{{ + message_v1 m{{ "GET", "/", 11}}; m.headers.insert("User-Agent", "test"); prepare(m, connection::upgrade); @@ -214,7 +214,7 @@ public: } // no content-length HTTP/1.1 { - message m{{ + message_v1 m{{ "GET", "/", 11}}; m.headers.insert("User-Agent", "test"); m.body = "*"; @@ -236,7 +236,7 @@ public: void testConvert() { - message m{{ + message_v1 m{{ "GET", "/", 11}}; m.headers.insert("User-Agent", "test"); m.body = "*"; diff --git a/test/websocket/stream.cpp b/test/websocket/stream.cpp index 39e12289..3bbe0b4d 100644 --- a/test/websocket/stream.cpp +++ b/test/websocket/stream.cpp @@ -22,7 +22,7 @@ #include #include -#include +#include namespace beast { namespace websocket {