From 14b439ce436d38fe1128c81852d933deeef4a015 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Wed, 29 Oct 2014 13:22:57 -0700 Subject: [PATCH] Separate beast::http::body from beast::http::message (RIPD-660): This changes the http::message object to no longer contain a body. It modifies the parser to store the body in a separate object, or to pass the body data to a functor. This allows the body to be stored in more flexible ways. For example, in HTTP responses the body can be generated procedurally instead of being required to exist entirely in memory at once. --- beast/http/body.h | 31 ++++++++++++++++++++++++------- beast/http/message.h | 20 ++++++++------------ beast/http/parser.h | 28 ++++++++++++++++++++++++---- beast/http/tests/parser.test.cpp | 10 +++++++--- 4 files changed, 63 insertions(+), 26 deletions(-) diff --git a/beast/http/body.h b/beast/http/body.h index 16bf77db0..69ac0b85a 100644 --- a/beast/http/body.h +++ b/beast/http/body.h @@ -50,17 +50,16 @@ public: body (body const&) = delete; body& operator= (body const&) = delete; + template + void + clear(); + void write (void const* data, std::size_t bytes); template void - write (ConstBufferSequence const& buffers) - { - for (auto const& buffer : buffers) - write (boost::asio::buffer_cast (buffer), - boost::asio::buffer_size (buffer)); - } + write (ConstBufferSequence const& buffers); std::size_t size() const; @@ -92,8 +91,9 @@ body::body() inline body::body (body&& other) + : buf_ (std::move(other.buf_)) { - buf_ = std::move(other.buf_); + other.clear(); } inline @@ -101,9 +101,17 @@ body& body::operator= (body&& other) { buf_ = std::move(other.buf_); + other.clear(); return *this; } +template +void +body::clear() +{ + buf_ = std::make_unique (); +} + inline void body::write (void const* data, std::size_t bytes) @@ -112,6 +120,15 @@ body::write (void const* data, std::size_t bytes) boost::asio::const_buffers_1 (data, bytes))); } +template +void +body::write (ConstBufferSequence const& buffers) +{ + for (auto const& buffer : buffers) + write (boost::asio::buffer_cast (buffer), + boost::asio::buffer_size (buffer)); +} + inline std::size_t body::size() const diff --git a/beast/http/message.h b/beast/http/message.h index 9f0ec6a66..66f398784 100644 --- a/beast/http/message.h +++ b/beast/http/message.h @@ -21,7 +21,6 @@ #define BEAST_HTTP_MESSAGE_H_INCLUDED #include -#include #include #include #include @@ -72,9 +71,8 @@ public: #endif - // Memberspaces + // Memberspace beast::http::headers headers; - beast::http::body body; bool request() const @@ -213,7 +211,6 @@ message::message (message&& other) , keep_alive_ (other.keep_alive_) , upgrade_ (other.upgrade_) , headers (std::move(other.headers)) - , body (std::move(other.body)) { } @@ -230,33 +227,32 @@ message::operator= (message&& other) keep_alive_ = other.keep_alive_; upgrade_ = other.upgrade_; headers = std::move(other.headers); - body = std::move(other.body); return *this; } #endif //------------------------------------------------------------------------------ -template +template void -write (AsioStreamBuf& stream, std::string const& s) +write (Streambuf& stream, std::string const& s) { stream.commit (boost::asio::buffer_copy ( stream.prepare (s.size()), boost::asio::buffer(s))); } -template +template void -write (AsioStreamBuf& stream, char const* s) +write (Streambuf& stream, char const* s) { auto const len (::strlen(s)); stream.commit (boost::asio::buffer_copy ( stream.prepare (len), boost::asio::buffer (s, len))); } -template +template void -write (AsioStreamBuf& stream, message const& m) +write (Streambuf& stream, message const& m) { if (m.request()) { @@ -311,4 +307,4 @@ to_string (message const& m) } // http } // beast -#endif \ No newline at end of file +#endif diff --git a/beast/http/parser.h b/beast/http/parser.h index 769f73d92..8d0e8ad81 100644 --- a/beast/http/parser.h +++ b/beast/http/parser.h @@ -21,6 +21,8 @@ #define BEAST_HTTP_PARSER_H_INCLUDED #include +#include +#include #include #include @@ -34,15 +36,33 @@ class parser : public beast::http::basic_parser { private: std::reference_wrapper message_; + std::function write_body_; public: /** Construct a parser for HTTP request or response. - The result is stored in the passed message. + The headers plus request or status line are stored in message. + The content-body, if any, is passed as a series of calls to + the write_body function. Transfer encodings are applied before + any data is passed to the write_body function. */ - parser (message& m, bool request) + parser (std::function write_body, + message& m, bool request) + : beast::http::basic_parser (request) + , message_(m) + , write_body_(std::move(write_body)) + { + message_.get().request(request); + } + + parser (message& m, body& b, bool request) : beast::http::basic_parser (request) , message_(m) { + write_body_ = [&b](void const* data, std::size_t size) + { + b.write(data, size); + }; + message_.get().request(request); } @@ -135,7 +155,7 @@ parser::operator= (parser&& other) template void -parser::do_start () +parser::do_start() { } @@ -176,7 +196,7 @@ template void parser::do_body (void const* data, std::size_t bytes) { - message_.get().body.write (data, bytes); + write_body_(data, bytes); } template diff --git a/beast/http/tests/parser.test.cpp b/beast/http/tests/parser.test.cpp index d81946383..c8e8ace4f 100644 --- a/beast/http/tests/parser.test.cpp +++ b/beast/http/tests/parser.test.cpp @@ -20,6 +20,7 @@ #include #include #include +#include namespace beast { namespace http { @@ -31,7 +32,8 @@ public: request (std::string const& text) { message m; - parser p (m, true); + body b; + parser p (m, b, true); auto result (p.write (boost::asio::buffer(text))); p.write_eof(); return std::make_pair (std::move(m), result.first); @@ -65,7 +67,8 @@ public: "\r\n" ; message m; - parser p (m, true); + body b; + parser p (m, b, true); auto result (p.write (boost::asio::buffer(text))); expect (! result.first); auto result2 (p.write_eof()); @@ -80,7 +83,8 @@ public: "\r\n" ; message m; - parser p (m, true); + body b; + parser p (m, b, true); auto result = p.write (boost::asio::buffer(text)); if (expect (result.first)) expect (result.first.message() == "invalid HTTP method");