diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2019-12-05 15:12:59 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2019-12-05 15:12:59 +0900 |
commit | b8cf34c691623e4ec329053cbbf68522a855882d (patch) | |
tree | 34da08632a99677f6b79ecb65e5b655a5b69a67f /boost/beast/http | |
parent | 3fdc3e5ee96dca5b11d1694975a65200787eab86 (diff) | |
download | boost-b8cf34c691623e4ec329053cbbf68522a855882d.tar.gz boost-b8cf34c691623e4ec329053cbbf68522a855882d.tar.bz2 boost-b8cf34c691623e4ec329053cbbf68522a855882d.zip |
Imported Upstream version 1.67.0upstream/1.67.0
Diffstat (limited to 'boost/beast/http')
28 files changed, 710 insertions, 448 deletions
diff --git a/boost/beast/http/basic_dynamic_body.hpp b/boost/beast/http/basic_dynamic_body.hpp index 76c499c554..7d850d76f3 100644 --- a/boost/beast/http/basic_dynamic_body.hpp +++ b/boost/beast/http/basic_dynamic_body.hpp @@ -70,9 +70,8 @@ struct basic_dynamic_body public: template<bool isRequest, class Fields> explicit - reader(message<isRequest, - basic_dynamic_body, Fields>& msg) - : body_(msg.body()) + reader(header<isRequest, Fields>&, value_type& b) + : body_(b) { } @@ -140,9 +139,8 @@ struct basic_dynamic_body template<bool isRequest, class Fields> explicit - writer(message<isRequest, - basic_dynamic_body, Fields> const& m) - : body_(m.body()) + writer(header<isRequest, Fields> const&, value_type const& b) + : body_(b) { } diff --git a/boost/beast/http/basic_file_body.hpp b/boost/beast/http/basic_file_body.hpp index cec72a8f54..6d1de9a3b8 100644 --- a/boost/beast/http/basic_file_body.hpp +++ b/boost/beast/http/basic_file_body.hpp @@ -239,8 +239,8 @@ public: // Constructor. // - // `m` holds the message we are serializing, which will - // always have the `basic_file_body` as the body type. + // `h` holds the headers of the message we are + // serializing, while `b` holds the body. // // Note that the message is passed by non-const reference. // This is intentional, because reading from the file @@ -262,8 +262,7 @@ public: // a time. // template<bool isRequest, class Fields> - writer(message< - isRequest, basic_file_body, Fields>& m); + writer(header<isRequest, Fields>& h, value_type& b); // Initializer // @@ -296,9 +295,11 @@ template<class File> template<bool isRequest, class Fields> basic_file_body<File>:: writer:: -writer(message<isRequest, basic_file_body, Fields>& m) - : body_(m.body()) +writer(header<isRequest, Fields>& h, value_type& b) + : body_(b) { + boost::ignore_unused(h); + // The file must already be open BOOST_ASSERT(body_.file_.is_open()); @@ -398,13 +399,12 @@ public: // // This is called after the header is parsed and // indicates that a non-zero sized body may be present. - // `m` holds the message we are receiving, which will - // always have the `basic_file_body` as the body type. + // `h` holds the received message headers. + // `b` is an instance of `basic_file_body`. // template<bool isRequest, class Fields> explicit - reader( - message<isRequest, basic_file_body, Fields>& m); + reader(header<isRequest, Fields>&h, value_type& b); // Initializer // @@ -447,9 +447,10 @@ template<class File> template<bool isRequest, class Fields> basic_file_body<File>:: reader:: -reader(message<isRequest, basic_file_body, Fields>& m) - : body_(m.body()) +reader(header<isRequest, Fields>& h, value_type& body) + : body_(body) { + boost::ignore_unused(h); } template<class File> diff --git a/boost/beast/http/buffer_body.hpp b/boost/beast/http/buffer_body.hpp index 675ea9475a..3ffe0a002a 100644 --- a/boost/beast/http/buffer_body.hpp +++ b/boost/beast/http/buffer_body.hpp @@ -105,8 +105,8 @@ struct buffer_body public: template<bool isRequest, class Fields> explicit - reader(message<isRequest, buffer_body, Fields>& m) - : body_(m.body()) + reader(header<isRequest, Fields>&, value_type& b) + : body_(b) { } @@ -167,9 +167,8 @@ struct buffer_body template<bool isRequest, class Fields> explicit - writer(message<isRequest, - buffer_body, Fields> const& msg) - : body_(msg.body()) + writer(header<isRequest, Fields> const&, value_type const& b) + : body_(b) { } diff --git a/boost/beast/http/detail/rfc7230.hpp b/boost/beast/http/detail/rfc7230.hpp index fdabc1a4d6..fac6790579 100644 --- a/boost/beast/http/detail/rfc7230.hpp +++ b/boost/beast/http/detail/rfc7230.hpp @@ -352,8 +352,8 @@ increment() { it = first; }; - v.first.clear(); - v.second.clear(); + v.first = {}; + v.second = {}; detail::skip_ows(it, last); first = it; if(it == last) diff --git a/boost/beast/http/detail/type_traits.hpp b/boost/beast/http/detail/type_traits.hpp index c9a06f9784..1d0c991826 100644 --- a/boost/beast/http/detail/type_traits.hpp +++ b/boost/beast/http/detail/type_traits.hpp @@ -194,6 +194,22 @@ struct is_fields_helper : T t10::value && t11::value && t12::value>; }; +template<class T> +using has_deprecated_body_writer = + std::integral_constant<bool, + std::is_constructible<typename T::writer, + message<true, T, detail::fields_model>&>::value && + std::is_constructible<typename T::writer, + message<false, T, detail::fields_model>&>::value>; + +template<class T> +using has_deprecated_body_reader = + std::integral_constant<bool, + std::is_constructible<typename T::reader, + message<true, T, detail::fields_model>&>::value && + std::is_constructible<typename T::reader, + message<false, T, detail::fields_model>&>::value>; + } // detail } // http } // beast diff --git a/boost/beast/http/empty_body.hpp b/boost/beast/http/empty_body.hpp index 1845a22992..d56c14b4ef 100644 --- a/boost/beast/http/empty_body.hpp +++ b/boost/beast/http/empty_body.hpp @@ -63,7 +63,7 @@ struct empty_body { template<bool isRequest, class Fields> explicit - reader(message<isRequest, empty_body, Fields>&) + reader(header<isRequest, Fields>&, value_type&) { } @@ -100,12 +100,11 @@ struct empty_body struct writer { using const_buffers_type = - boost::asio::null_buffers; + boost::asio::const_buffer; template<bool isRequest, class Fields> explicit - writer(message<isRequest, - empty_body, Fields> const&) + writer(header<isRequest, Fields> const&, value_type const&) { } diff --git a/boost/beast/http/error.hpp b/boost/beast/http/error.hpp index 841a99de25..b3d9fb1188 100644 --- a/boost/beast/http/error.hpp +++ b/boost/beast/http/error.hpp @@ -22,15 +22,10 @@ enum class error { /** The end of the stream was reached. - This error is returned under the following conditions: - - @li When attempting to read HTTP data from a stream and the stream - read returns the error `boost::asio::error::eof` before any new octets - have been received. - - @li When sending a complete HTTP message at once and the semantics of - the message are that the connection should be closed to indicate the - end of the message. + This error is returned when attempting to read HTTP data, + and the stream returns the error `boost::asio::error::eof` + before any octets corresponding to a new HTTP message have + been received. */ end_of_stream = 1, diff --git a/boost/beast/http/field.hpp b/boost/beast/http/field.hpp index 3d1446addc..09d9dfffdf 100644 --- a/boost/beast/http/field.hpp +++ b/boost/beast/http/field.hpp @@ -38,6 +38,7 @@ enum class field : unsigned short access_control_allow_headers, access_control_allow_methods, access_control_allow_origin, + access_control_expose_headers, access_control_max_age, access_control_request_headers, access_control_request_method, diff --git a/boost/beast/http/fields.hpp b/boost/beast/http/fields.hpp index 06c950ee5a..59cb338b83 100644 --- a/boost/beast/http/fields.hpp +++ b/boost/beast/http/fields.hpp @@ -14,6 +14,7 @@ #include <boost/beast/core/string_param.hpp> #include <boost/beast/core/string.hpp> #include <boost/beast/core/detail/allocator.hpp> +#include <boost/beast/core/detail/empty_base_optimization.hpp> #include <boost/beast/http/field.hpp> #include <boost/asio/buffer.hpp> #include <boost/intrusive/list.hpp> @@ -51,7 +52,15 @@ namespace http { */ template<class Allocator> class basic_fields +#ifndef BOOST_BEAST_DOXYGEN + : private beast::detail::empty_base_optimization<Allocator> +#endif { + // Fancy pointers are not supported + static_assert(std::is_pointer<typename + std::allocator_traits<Allocator>::pointer>::value, + "Allocator must use regular pointers"); + friend class fields_test; // for `header` static std::size_t constexpr max_static_buffer = 4096; @@ -93,7 +102,7 @@ public: value_type& operator=(value_type const&) = delete; /// Returns the field enum, which can be @ref field::unknown - field const + field name() const; /// Returns the field name as a string @@ -179,6 +188,19 @@ private: boost::intrusive::constant_time_size<true>, boost::intrusive::compare<key_compare>>::type; + using align_type = typename + boost::type_with_alignment<alignof(value_type)>::type; + + using rebind_type = typename + beast::detail::allocator_traits<Allocator>:: + template rebind_alloc<align_type>; + + using alloc_traits = + beast::detail::allocator_traits<rebind_type>; + + using size_type = typename + beast::detail::allocator_traits<Allocator>::size_type; + public: /// Destructor @@ -192,14 +214,14 @@ public: @param alloc The allocator to use. */ explicit - basic_fields(Allocator const& alloc); + basic_fields(Allocator const& alloc) noexcept; /** Move constructor. The state of the moved-from object is as if constructed using the same allocator. */ - basic_fields(basic_fields&&); + basic_fields(basic_fields&&) noexcept; /** Move constructor. @@ -236,7 +258,8 @@ public: The state of the moved-from object is as if constructed using the same allocator. */ - basic_fields& operator=(basic_fields&&); + basic_fields& operator=(basic_fields&&) noexcept( + alloc_traits::propagate_on_container_move_assignment::value); /// Copy assignment. basic_fields& operator=(basic_fields const&); @@ -260,7 +283,7 @@ public: allocator_type get_allocator() const { - return alloc_; + return this->member(); } //-------------------------------------------------------------------------- @@ -681,16 +704,6 @@ private: template<class OtherAlloc> friend class basic_fields; - using base_alloc_type = typename - beast::detail::allocator_traits<Allocator>:: - template rebind_alloc<value_type>; - - using alloc_traits = - beast::detail::allocator_traits<base_alloc_type>; - - using size_type = typename - beast::detail::allocator_traits<Allocator>::size_type; - value_type& new_element(field name, string_view sname, string_view value); @@ -736,7 +749,6 @@ private: void swap(basic_fields& other, std::false_type); - base_alloc_type alloc_; set_t set_; list_t list_; string_view method_; diff --git a/boost/beast/http/impl/basic_parser.ipp b/boost/beast/http/impl/basic_parser.ipp index 355a76fb16..39ad3cc68e 100644 --- a/boost/beast/http/impl/basic_parser.ipp +++ b/boost/beast/http/impl/basic_parser.ipp @@ -148,7 +148,7 @@ loop: return 0; } state_ = state::start_line; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; case state::start_line: { @@ -179,7 +179,7 @@ loop: ec = error::need_more; goto done; } - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; } case state::fields: @@ -212,7 +212,7 @@ loop: if(ec) goto done; state_ = state::body; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; case state::body: BOOST_ASSERT(! skip_); @@ -227,7 +227,7 @@ loop: if(ec) goto done; state_ = state::body_to_eof; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; case state::body_to_eof: BOOST_ASSERT(! skip_); @@ -241,7 +241,7 @@ loop: if(ec) goto done; state_ = state::chunk_header; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; case state::chunk_header: parse_chunk_header(p, n, ec); diff --git a/boost/beast/http/impl/field.ipp b/boost/beast/http/impl/field.ipp index 8da470ff24..467a40aeee 100644 --- a/boost/beast/http/impl/field.ipp +++ b/boost/beast/http/impl/field.ipp @@ -26,7 +26,7 @@ namespace detail { struct field_table { using array_type = - std::array<string_view, 352>; + std::array<string_view, 353>; struct hash { @@ -104,6 +104,7 @@ struct field_table "Access-Control-Allow-Headers", "Access-Control-Allow-Methods", "Access-Control-Allow-Origin", + "Access-Control-Expose-Headers", "Access-Control-Max-Age", "Access-Control-Request-Headers", "Access-Control-Request-Method", diff --git a/boost/beast/http/impl/fields.ipp b/boost/beast/http/impl/fields.ipp index 67d7cc45b4..a07fd0fa30 100644 --- a/boost/beast/http/impl/fields.ipp +++ b/boost/beast/http/impl/fields.ipp @@ -272,8 +272,10 @@ writer(basic_fields const& f, template<class Allocator> basic_fields<Allocator>:: value_type:: -value_type(field name, - string_view sname, string_view value) +value_type( + field name, + string_view sname, + string_view value) : off_(static_cast<off_t>(sname.size() + 2)) , len_(static_cast<off_t>(value.size())) , f_(name) @@ -285,13 +287,13 @@ value_type(field name, p[off_-1] = ' '; p[off_ + len_] = '\r'; p[off_ + len_ + 1] = '\n'; - std::memcpy(p, sname.data(), sname.size()); - std::memcpy(p + off_, value.data(), value.size()); + sname.copy(p, sname.size()); + value.copy(p + off_, value.size()); } template<class Allocator> inline -field const +field basic_fields<Allocator>:: value_type:: name() const @@ -349,30 +351,31 @@ basic_fields<Allocator>:: template<class Allocator> basic_fields<Allocator>:: -basic_fields(Allocator const& alloc) - : alloc_(alloc) +basic_fields(Allocator const& alloc) noexcept + : beast::detail::empty_base_optimization<Allocator>(alloc) { } template<class Allocator> basic_fields<Allocator>:: -basic_fields(basic_fields&& other) - : alloc_(std::move(other.alloc_)) +basic_fields(basic_fields&& other) noexcept + : beast::detail::empty_base_optimization<Allocator>( + std::move(other.member())) , set_(std::move(other.set_)) , list_(std::move(other.list_)) , method_(other.method_) , target_or_reason_(other.target_or_reason_) { - other.method_.clear(); - other.target_or_reason_.clear(); + other.method_ = {}; + other.target_or_reason_ = {}; } template<class Allocator> basic_fields<Allocator>:: basic_fields(basic_fields&& other, Allocator const& alloc) - : alloc_(alloc) + : beast::detail::empty_base_optimization<Allocator>(alloc) { - if(alloc_ != other.alloc_) + if(this->member() != other.member()) { copy_all(other); other.clear_all(); @@ -389,8 +392,8 @@ basic_fields(basic_fields&& other, Allocator const& alloc) template<class Allocator> basic_fields<Allocator>:: basic_fields(basic_fields const& other) - : alloc_(alloc_traits:: - select_on_container_copy_construction(other.alloc_)) + : beast::detail::empty_base_optimization<Allocator>(alloc_traits:: + select_on_container_copy_construction(other.member())) { copy_all(other); } @@ -399,7 +402,7 @@ template<class Allocator> basic_fields<Allocator>:: basic_fields(basic_fields const& other, Allocator const& alloc) - : alloc_(alloc) + : beast::detail::empty_base_optimization<Allocator>(alloc) { copy_all(other); } @@ -417,7 +420,7 @@ template<class OtherAlloc> basic_fields<Allocator>:: basic_fields(basic_fields<OtherAlloc> const& other, Allocator const& alloc) - : alloc_(alloc) + : beast::detail::empty_base_optimization<Allocator>(alloc) { copy_all(other); } @@ -425,9 +428,12 @@ basic_fields(basic_fields<OtherAlloc> const& other, template<class Allocator> auto basic_fields<Allocator>:: -operator=(basic_fields&& other) -> - basic_fields& +operator=(basic_fields&& other) noexcept( + alloc_traits::propagate_on_container_move_assignment::value) + -> basic_fields& { + static_assert(is_nothrow_move_assignable<Allocator>::value, + "Allocator must be noexcept assignable."); if(this == &other) return *this; move_assign(other, std::integral_constant<bool, @@ -605,11 +611,11 @@ basic_fields<Allocator>:: erase(const_iterator pos) -> const_iterator { - auto next = pos.iter(); + auto next = pos; auto& e = *next++; set_.erase(e); - list_.erase(e); - delete_element(e); + list_.erase(pos); + delete_element(const_cast<value_type&>(e)); return next; } @@ -1014,13 +1020,13 @@ set_chunked_impl(bool value) // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437 std::string s; #else - using rebind_type = + using A = typename beast::detail::allocator_traits< Allocator>::template rebind_alloc<char>; std::basic_string< char, std::char_traits<char>, - rebind_type> s{rebind_type{alloc_}}; + A> s{A{this->member()}}; #endif s.reserve(it->value().size() + 9); s.append(it->value().data(), it->value().size()); @@ -1051,13 +1057,13 @@ set_chunked_impl(bool value) // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437 std::string s; #else - using rebind_type = + using A = typename beast::detail::allocator_traits< Allocator>::template rebind_alloc<char>; std::basic_string< char, std::char_traits<char>, - rebind_type> s{rebind_type{alloc_}}; + A> s{A{this->member()}}; #endif s.reserve(it->value().size()); detail::filter_token_list_last(s, it->value(), @@ -1108,13 +1114,13 @@ set_keep_alive_impl( // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437 std::string s; #else - using rebind_type = + using A = typename beast::detail::allocator_traits< Allocator>::template rebind_alloc<char>; std::basic_string< char, std::char_traits<char>, - rebind_type> s{rebind_type{alloc_}}; + A> s{A{this->member()}}; #endif s.reserve(value.size()); detail::keep_alive_impl( @@ -1148,13 +1154,14 @@ new_element(field name, static_cast<off_t>(sname.size() + 2); std::uint16_t const len = static_cast<off_t>(value.size()); - auto const p = alloc_traits::allocate(alloc_, - 1 + (off + len + 2 + sizeof(value_type) - 1) / - sizeof(value_type)); + auto a = rebind_type{this->member()}; + auto const p = alloc_traits::allocate(a, + (sizeof(value_type) + off + len + 2 + sizeof(align_type) - 1) / + sizeof(align_type)); // VFALCO allocator can't call the constructor because its private - //alloc_traits::construct(alloc_, p, name, sname, value); + //alloc_traits::construct(a, p, name, sname, value); new(p) value_type{name, sname, value}; - return *p; + return *reinterpret_cast<value_type*>(p); } template<class Allocator> @@ -1162,10 +1169,14 @@ void basic_fields<Allocator>:: delete_element(value_type& e) { - auto const n = 1 + (e.off_ + e.len_ + 2 + - sizeof(value_type) - 1) / sizeof(value_type); - alloc_traits::destroy(alloc_, &e); - alloc_traits::deallocate(alloc_, &e, n); + auto a = rebind_type{this->member()}; + auto const n = + (sizeof(value_type) + e.off_ + e.len_ + 2 + sizeof(align_type) - 1) / + sizeof(align_type); + //alloc_traits::destroy(a, &e); + e.~value_type(); + alloc_traits::deallocate(a, + reinterpret_cast<align_type*>(&e), n); } template<class Allocator> @@ -1207,19 +1218,20 @@ realloc_string(string_view& dest, string_view s) return; auto a = typename beast::detail::allocator_traits< Allocator>::template rebind_alloc< - char>(alloc_); - if(! dest.empty()) + char>(this->member()); + char* p = nullptr; + if(! s.empty()) { + p = a.allocate(s.size()); + s.copy(p, s.size()); + } + if(! dest.empty()) a.deallocate(const_cast<char*>( dest.data()), dest.size()); - dest.clear(); - } - if(! s.empty()) - { - auto const p = a.allocate(s.size()); - std::memcpy(p, s.data(), s.size()); + if(p) dest = {p, s.size()}; - } + else + dest = {}; } template<class Allocator> @@ -1235,20 +1247,21 @@ realloc_target( return; auto a = typename beast::detail::allocator_traits< Allocator>::template rebind_alloc< - char>(alloc_); - if(! dest.empty()) - { - a.deallocate(const_cast<char*>( - dest.data()), dest.size()); - dest.clear(); - } + char>(this->member()); + char* p = nullptr; if(! s.empty()) { - auto const p = a.allocate(1 + s.size()); + p = a.allocate(1 + s.size()); p[0] = ' '; - std::memcpy(p + 1, s.data(), s.size()); - dest = {p, 1 + s.size()}; + s.copy(p + 1, s.size()); } + if(! dest.empty()) + a.deallocate(const_cast<char*>( + dest.data()), dest.size()); + if(p) + dest = {p, 1 + s.size()}; + else + dest = {}; } template<class Allocator> @@ -1296,9 +1309,9 @@ move_assign(basic_fields& other, std::true_type) list_ = std::move(other.list_); method_ = other.method_; target_or_reason_ = other.target_or_reason_; - other.method_.clear(); - other.target_or_reason_.clear(); - alloc_ = other.alloc_; + other.method_ = {}; + other.target_or_reason_ = {}; + this->member() = other.member(); } template<class Allocator> @@ -1308,7 +1321,7 @@ basic_fields<Allocator>:: move_assign(basic_fields& other, std::false_type) { clear_all(); - if(alloc_ != other.alloc_) + if(this->member() != other.member()) { copy_all(other); other.clear_all(); @@ -1319,8 +1332,8 @@ move_assign(basic_fields& other, std::false_type) list_ = std::move(other.list_); method_ = other.method_; target_or_reason_ = other.target_or_reason_; - other.method_.clear(); - other.target_or_reason_.clear(); + other.method_ = {}; + other.target_or_reason_ = {}; } } @@ -1331,7 +1344,7 @@ basic_fields<Allocator>:: copy_assign(basic_fields const& other, std::true_type) { clear_all(); - alloc_ = other.alloc_; + this->member() = other.member(); copy_all(other); } @@ -1352,7 +1365,7 @@ basic_fields<Allocator>:: swap(basic_fields& other, std::true_type) { using std::swap; - swap(alloc_, other.alloc_); + swap(this->member(), other.member()); swap(set_, other.set_); swap(list_, other.list_); swap(method_, other.method_); @@ -1365,7 +1378,7 @@ void basic_fields<Allocator>:: swap(basic_fields& other, std::false_type) { - BOOST_ASSERT(alloc_ == other.alloc_); + BOOST_ASSERT(this->member() == other.member()); using std::swap; swap(set_, other.set_); swap(list_, other.list_); diff --git a/boost/beast/http/impl/file_body_win32.ipp b/boost/beast/http/impl/file_body_win32.ipp index e11c443ed2..627401f531 100644 --- a/boost/beast/http/impl/file_body_win32.ipp +++ b/boost/beast/http/impl/file_body_win32.ipp @@ -21,10 +21,12 @@ #include <boost/asio/async_result.hpp> #include <boost/asio/basic_stream_socket.hpp> #include <boost/asio/handler_continuation_hook.hpp> +#include <boost/asio/handler_invoke_hook.hpp> #include <boost/asio/windows/overlapped_ptr.hpp> #include <boost/make_unique.hpp> #include <boost/smart_ptr/make_shared_array.hpp> #include <boost/winapi/basic_types.hpp> +#include <boost/winapi/get_last_error.hpp> #include <algorithm> #include <cstring> @@ -123,9 +125,8 @@ struct basic_file_body<file_win32> boost::asio::const_buffer; template<bool isRequest, class Fields> - writer(message<isRequest, - basic_file_body<file_win32>, Fields>& m) - : body_(m.body()) + writer(header<isRequest, Fields>&, value_type& b) + : body_(b) { } @@ -167,8 +168,8 @@ struct basic_file_body<file_win32> public: template<bool isRequest, class Fields> explicit - reader(message<isRequest, basic_file_body, Fields>& m) - : body_(m.body()) + reader(header<isRequest, Fields>&, value_type& b) + : body_(b) { } @@ -344,7 +345,7 @@ class write_some_win32_op public: write_some_win32_op(write_some_win32_op&&) = default; - write_some_win32_op(write_some_win32_op const&) = default; + write_some_win32_op(write_some_win32_op const&) = delete; template<class DeducedHandler> write_some_win32_op( @@ -364,7 +365,7 @@ public: allocator_type get_allocator() const noexcept { - return boost::asio::get_associated_allocator(h_); + return (boost::asio::get_associated_allocator)(h_); } using executor_type = @@ -374,7 +375,7 @@ public: executor_type get_executor() const noexcept { - return boost::asio::get_associated_executor( + return (boost::asio::get_associated_executor)( h_, sock_.get_executor()); } @@ -393,6 +394,14 @@ public: return asio_handler_is_continuation( std::addressof(op->h_)); } + + template<class Function> + friend + void asio_handler_invoke(Function&& f, write_some_win32_op* op) + { + using boost::asio::asio_handler_invoke; + asio_handler_invoke(f, std::addressof(op->h_)); + } }; template< @@ -407,25 +416,28 @@ operator()() { header_ = true; sr_.split(true); - return detail::async_write_some( + return detail::async_write_some_impl( sock_, sr_, std::move(*this)); } if(sr_.get().chunked()) { - return detail::async_write_some( + return detail::async_write_some_impl( sock_, sr_, std::move(*this)); } - auto& r = sr_.reader_impl(); + auto& w = sr_.writer_impl(); boost::winapi::DWORD_ const nNumberOfBytesToWrite = static_cast<boost::winapi::DWORD_>( (std::min<std::uint64_t>)( - (std::min<std::uint64_t>)(r.body_.last_ - r.pos_, sr_.limit()), + (std::min<std::uint64_t>)(w.body_.last_ - w.pos_, sr_.limit()), (std::numeric_limits<boost::winapi::DWORD_>::max)())); boost::asio::windows::overlapped_ptr overlapped{ - sock_.get_executor().context(), *this}; + sock_.get_executor().context(), std::move(*this)}; + // Note that we have moved *this, so we cannot access + // the handler since it is now moved-from. We can still + // access simple things like references and built-in types. auto& ov = *overlapped.get(); - ov.Offset = lowPart(r.pos_); - ov.OffsetHigh = highPart(r.pos_); + ov.Offset = lowPart(w.pos_); + ov.OffsetHigh = highPart(w.pos_); auto const bSuccess = ::TransmitFile( sock_.native_handle(), sr_.get().body().file_.native_handle(), @@ -434,14 +446,13 @@ operator()() overlapped.get(), nullptr, 0); - auto const dwError = ::GetLastError(); + auto const dwError = boost::winapi::GetLastError(); if(! bSuccess && dwError != boost::winapi::ERROR_IO_PENDING_) { // VFALCO This needs review, is 0 the right number? // completed immediately (with error?) - overlapped.complete(error_code{static_cast<int>( - boost::winapi::GetLastError()), + overlapped.complete(error_code{static_cast<int>(dwError), system_category()}, 0); return; } @@ -465,10 +476,10 @@ operator()( header_ = false; return (*this)(); } - auto& r = sr_.reader_impl(); - r.pos_ += bytes_transferred; - BOOST_ASSERT(r.pos_ <= r.body_.last_); - if(r.pos_ >= r.body_.last_) + auto& w = sr_.writer_impl(); + w.pos_ += bytes_transferred; + BOOST_ASSERT(w.pos_ <= w.body_.last_); + if(w.pos_ >= w.body_.last_) { sr_.next(ec, null_lambda{}); BOOST_ASSERT(! ec); @@ -496,7 +507,7 @@ write_some( { sr.split(true); auto const bytes_transferred = - detail::write_some(sock, sr, ec); + detail::write_some_impl(sock, sr, ec); if(ec) return bytes_transferred; return bytes_transferred; @@ -504,23 +515,23 @@ write_some( if(sr.get().chunked()) { auto const bytes_transferred = - detail::write_some(sock, sr, ec); + detail::write_some_impl(sock, sr, ec); if(ec) return bytes_transferred; return bytes_transferred; } - auto& r = sr.reader_impl(); - r.body_.file_.seek(r.pos_, ec); + auto& w = sr.writer_impl(); + w.body_.file_.seek(w.pos_, ec); if(ec) return 0; boost::winapi::DWORD_ const nNumberOfBytesToWrite = static_cast<boost::winapi::DWORD_>( (std::min<std::uint64_t>)( - (std::min<std::uint64_t>)(r.body_.last_ - r.pos_, sr.limit()), + (std::min<std::uint64_t>)(w.body_.last_ - w.pos_, sr.limit()), (std::numeric_limits<boost::winapi::DWORD_>::max)())); auto const bSuccess = ::TransmitFile( sock.native_handle(), - r.body_.file_.native_handle(), + w.body_.file_.native_handle(), nNumberOfBytesToWrite, 0, nullptr, @@ -533,9 +544,9 @@ write_some( system_category()); return 0; } - r.pos_ += nNumberOfBytesToWrite; - BOOST_ASSERT(r.pos_ <= r.body_.last_); - if(r.pos_ < r.body_.last_) + w.pos_ += nNumberOfBytesToWrite; + BOOST_ASSERT(w.pos_ <= w.body_.last_); + if(w.pos_ < w.body_.last_) { ec.assign(0, ec.category()); } @@ -562,14 +573,14 @@ async_write_some( basic_file_body<file_win32>, Fields>& sr, WriteHandler&& handler) { - boost::asio::async_completion<WriteHandler, - void(error_code)> init{handler}; + BOOST_BEAST_HANDLER_INIT( + WriteHandler, void(error_code, std::size_t)); detail::write_some_win32_op< Protocol, BOOST_ASIO_HANDLER_TYPE(WriteHandler, void(error_code, std::size_t)), isRequest, Fields>{ - init.completion_handler, sock, sr}(); + std::move(init.completion_handler), sock, sr}(); return init.result.get(); } diff --git a/boost/beast/http/impl/parser.ipp b/boost/beast/http/impl/parser.ipp index 99745da3f0..8a6cab30af 100644 --- a/boost/beast/http/impl/parser.ipp +++ b/boost/beast/http/impl/parser.ipp @@ -20,7 +20,26 @@ namespace http { template<bool isRequest, class Body, class Allocator> parser<isRequest, Body, Allocator>:: parser() - : wr_(m_) + : parser{detail::has_deprecated_body_reader<Body>{}} +{ +} + +template<bool isRequest, class Body, class Allocator> +parser<isRequest, Body, Allocator>:: +parser(std::true_type) + : rd_(m_) +{ +#ifndef BOOST_BEAST_ALLOW_DEPRECATED + // Deprecated BodyReader Concept (v1.66) + static_assert(sizeof(Body) == 0, + BOOST_BEAST_DEPRECATION_STRING); +#endif +} + +template<bool isRequest, class Body, class Allocator> +parser<isRequest, Body, Allocator>:: +parser(std::false_type) + : rd_(m_.base(), m_.body()) { } @@ -28,21 +47,82 @@ template<bool isRequest, class Body, class Allocator> template<class Arg1, class... ArgN, class> parser<isRequest, Body, Allocator>:: parser(Arg1&& arg1, ArgN&&... argn) + : parser(std::forward<Arg1>(arg1), + detail::has_deprecated_body_reader<Body>{}, + std::forward<ArgN>(argn)...) +{ +} + +// VFALCO arg1 comes before `true_type` to make +// the signature unambiguous. +template<bool isRequest, class Body, class Allocator> +template<class Arg1, class... ArgN, class> +parser<isRequest, Body, Allocator>:: +parser(Arg1&& arg1, std::true_type, ArgN&&... argn) : m_(std::forward<Arg1>(arg1), std::forward<ArgN>(argn)...) - , wr_(m_) + , rd_(m_) { m_.clear(); +#ifndef BOOST_BEAST_ALLOW_DEPRECATED + /* Deprecated BodyWriter Concept (v1.66) */ + static_assert(sizeof(Body) == 0, + BOOST_BEAST_DEPRECATION_STRING); +#endif // BOOST_BEAST_ALLOW_DEPRECATED +} + +// VFALCO arg1 comes before `false_type` to make +// the signature unambiguous. +template<bool isRequest, class Body, class Allocator> +template<class Arg1, class... ArgN, class> +parser<isRequest, Body, Allocator>:: +parser(Arg1&& arg1, std::false_type, ArgN&&... argn) + : m_(std::forward<Arg1>(arg1), + std::forward<ArgN>(argn)...) + , rd_(m_.base(), m_.body()) +{ + m_.clear(); +} + +template<bool isRequest, class Body, class Allocator> +template<class OtherBody, class... Args, class> +parser<isRequest, Body, Allocator>:: +parser( + parser<isRequest, OtherBody, Allocator>&& other, + Args&&... args) + : parser(detail::has_deprecated_body_reader<Body>{}, + std::move(other), std::forward<Args>(args)...) +{ +} + +template<bool isRequest, class Body, class Allocator> +template<class OtherBody, class... Args, class> +parser<isRequest, Body, Allocator>:: +parser(std::true_type, + parser<isRequest, OtherBody, Allocator>&& other, + Args&&... args) + : base_type(std::move(other)) + , m_(other.release(), std::forward<Args>(args)...) + , rd_(m_) +{ + if(other.rd_inited_) + BOOST_THROW_EXCEPTION(std::invalid_argument{ + "moved-from parser has a body"}); +#ifndef BOOST_BEAST_ALLOW_DEPRECATED + // Deprecated BodyReader Concept (v1.66) + static_assert(sizeof(Body) == 0, + BOOST_BEAST_DEPRECATION_STRING); +#endif } template<bool isRequest, class Body, class Allocator> template<class OtherBody, class... Args, class> parser<isRequest, Body, Allocator>:: -parser(parser<isRequest, OtherBody, Allocator>&& other, +parser(std::false_type, parser<isRequest, OtherBody, Allocator>&& other, Args&&... args) : base_type(std::move(other)) , m_(other.release(), std::forward<Args>(args)...) - , wr_(m_) + , rd_(m_.base(), m_.body()) { if(other.rd_inited_) BOOST_THROW_EXCEPTION(std::invalid_argument{ diff --git a/boost/beast/http/impl/read.ipp b/boost/beast/http/impl/read.ipp index 5ecfae7d8b..28ff0a3c44 100644 --- a/boost/beast/http/impl/read.ipp +++ b/boost/beast/http/impl/read.ipp @@ -20,7 +20,9 @@ #include <boost/beast/core/type_traits.hpp> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> +#include <boost/asio/coroutine.hpp> #include <boost/asio/handler_continuation_hook.hpp> +#include <boost/asio/handler_invoke_hook.hpp> #include <boost/asio/post.hpp> #include <boost/assert.hpp> #include <boost/config.hpp> @@ -38,19 +40,18 @@ namespace detail { template<class Stream, class DynamicBuffer, bool isRequest, class Derived, class Handler> class read_some_op + : public boost::asio::coroutine { - int state_ = 0; Stream& s_; DynamicBuffer& b_; basic_parser<isRequest, Derived>& p_; - boost::optional<typename - DynamicBuffer::mutable_buffers_type> mb_; std::size_t bytes_transferred_ = 0; Handler h_; + bool cont_ = false; public: read_some_op(read_some_op&&) = default; - read_some_op(read_some_op const&) = default; + read_some_op(read_some_op const&) = delete; template<class DeducedHandler> read_some_op(DeducedHandler&& h, Stream& s, @@ -68,7 +69,7 @@ public: allocator_type get_allocator() const noexcept { - return boost::asio::get_associated_allocator(h_); + return (boost::asio::get_associated_allocator)(h_); } using executor_type = boost::asio::associated_executor_t< @@ -77,23 +78,32 @@ public: executor_type get_executor() const noexcept { - return boost::asio::get_associated_executor( + return (boost::asio::get_associated_executor)( h_, s_.get_executor()); } void operator()( - error_code ec = {}, - std::size_t bytes_transferred = 0); + error_code ec, + std::size_t bytes_transferred = 0, + bool cont = true); friend bool asio_handler_is_continuation(read_some_op* op) { using boost::asio::asio_handler_is_continuation; - return op->state_ >= 2 ? true : + return op->cont_ ? true : asio_handler_is_continuation( std::addressof(op->h_)); } + + template<class Function> + friend + void asio_handler_invoke(Function&& f, read_some_op* op) + { + using boost::asio::asio_handler_invoke; + asio_handler_invoke(f, std::addressof(op->h_)); + } }; template<class Stream, class DynamicBuffer, @@ -103,75 +113,69 @@ read_some_op<Stream, DynamicBuffer, isRequest, Derived, Handler>:: operator()( error_code ec, - std::size_t bytes_transferred) + std::size_t bytes_transferred, + bool cont) { - switch(state_) + cont_ = cont; + boost::optional<typename + DynamicBuffer::mutable_buffers_type> mb; + BOOST_ASIO_CORO_REENTER(*this) { - case 0: - state_ = 1; if(b_.size() == 0) goto do_read; - goto do_parse; - - case 1: - state_ = 2; - case 2: - if(ec == boost::asio::error::eof) + for(;;) { - BOOST_ASSERT(bytes_transferred == 0); - if(p_.got_some()) + // parse { - // caller sees EOF on next read - ec.assign(0, ec.category()); - p_.put_eof(ec); - if(ec) - goto upcall; - BOOST_ASSERT(p_.is_done()); - goto upcall; + auto const used = p_.put(b_.data(), ec); + bytes_transferred_ += used; + b_.consume(used); } - ec = error::end_of_stream; - goto upcall; - } - if(ec) - goto upcall; - b_.commit(bytes_transferred); - - do_parse: - { - auto const used = p_.put(b_.data(), ec); - bytes_transferred_ += used; - b_.consume(used); - if(! ec || ec != http::error::need_more) - goto do_upcall; - ec.assign(0, ec.category()); - } + if(ec != http::error::need_more) + break; - do_read: - try - { - mb_.emplace(b_.prepare( - read_size_or_throw(b_, 65536))); - } - catch(std::length_error const&) - { - ec = error::buffer_overflow; - goto do_upcall; + do_read: + try + { + mb.emplace(b_.prepare( + read_size_or_throw(b_, 65536))); + } + catch(std::length_error const&) + { + ec = error::buffer_overflow; + break; + } + BOOST_ASIO_CORO_YIELD + s_.async_read_some(*mb, std::move(*this)); + if(ec == boost::asio::error::eof) + { + BOOST_ASSERT(bytes_transferred == 0); + if(p_.got_some()) + { + // caller sees EOF on next read + ec.assign(0, ec.category()); + p_.put_eof(ec); + if(ec) + goto upcall; + BOOST_ASSERT(p_.is_done()); + goto upcall; + } + ec = error::end_of_stream; + break; + } + if(ec) + break; + b_.commit(bytes_transferred); } - return s_.async_read_some(*mb_, std::move(*this)); - do_upcall: - if(state_ >= 2) - goto upcall; - state_ = 3; - return boost::asio::post( - s_.get_executor(), - bind_handler(std::move(*this), ec, 0)); - - case 3: - break; + upcall: + if(! cont_) + return boost::asio::post( + s_.get_executor(), + bind_handler(std::move(h_), + ec, bytes_transferred_)); + h_(ec, bytes_transferred_); } -upcall: - h_(ec, bytes_transferred_); } //------------------------------------------------------------------------------ @@ -202,17 +206,18 @@ template<class Stream, class DynamicBuffer, bool isRequest, class Derived, class Condition, class Handler> class read_op + : public boost::asio::coroutine { - int state_ = 0; Stream& s_; DynamicBuffer& b_; basic_parser<isRequest, Derived>& p_; std::size_t bytes_transferred_ = 0; Handler h_; + bool cont_ = false; public: read_op(read_op&&) = default; - read_op(read_op const&) = default; + read_op(read_op const&) = delete; template<class DeducedHandler> read_op(DeducedHandler&& h, Stream& s, @@ -231,7 +236,7 @@ public: allocator_type get_allocator() const noexcept { - return boost::asio::get_associated_allocator(h_); + return (boost::asio::get_associated_allocator)(h_); } using executor_type = boost::asio::associated_executor_t< @@ -240,23 +245,32 @@ public: executor_type get_executor() const noexcept { - return boost::asio::get_associated_executor( + return (boost::asio::get_associated_executor)( h_, s_.get_executor()); } void operator()( - error_code ec = {}, - std::size_t bytes_transferred = 0); + error_code ec, + std::size_t bytes_transferred = 0, + bool cont = true); friend bool asio_handler_is_continuation(read_op* op) { using boost::asio::asio_handler_is_continuation; - return op->state_ >= 3 ? true : + return op->cont_ ? true : asio_handler_is_continuation( std::addressof(op->h_)); } + + template<class Function> + friend + void asio_handler_invoke(Function&& f, read_op* op) + { + using boost::asio::asio_handler_invoke; + asio_handler_invoke(f, std::addressof(op->h_)); + } }; template<class Stream, class DynamicBuffer, @@ -267,39 +281,33 @@ read_op<Stream, DynamicBuffer, isRequest, Derived, Condition, Handler>:: operator()( error_code ec, - std::size_t bytes_transferred) + std::size_t bytes_transferred, + bool cont) { - switch(state_) + cont_ = cont; + BOOST_ASIO_CORO_REENTER(*this) { - case 0: if(Condition{}(p_)) { - state_ = 1; - return boost::asio::post( - s_.get_executor(), + BOOST_ASIO_CORO_YIELD + boost::asio::post(s_.get_executor(), bind_handler(std::move(*this), ec)); - } - state_ = 2; - - do_read: - return async_read_some( - s_, b_, p_, std::move(*this)); - - case 1: - goto upcall; - - case 2: - case 3: - if(ec) - goto upcall; - bytes_transferred_ += bytes_transferred; - if(Condition{}(p_)) goto upcall; - state_ = 3; - goto do_read; + } + for(;;) + { + BOOST_ASIO_CORO_YIELD + async_read_some( + s_, b_, p_, std::move(*this)); + if(ec) + goto upcall; + bytes_transferred_ += bytes_transferred; + if(Condition{}(p_)) + goto upcall; + } + upcall: + h_(ec, bytes_transferred_); } -upcall: - h_(ec, bytes_transferred_); } //------------------------------------------------------------------------------ @@ -308,6 +316,7 @@ template<class Stream, class DynamicBuffer, bool isRequest, class Body, class Allocator, class Handler> class read_msg_op + : public boost::asio::coroutine { using parser_type = parser<isRequest, Body, Allocator>; @@ -317,14 +326,14 @@ class read_msg_op struct data { - int state = 0; Stream& s; DynamicBuffer& b; message_type& m; parser_type p; std::size_t bytes_transferred = 0; + bool cont = false; - data(Handler&, Stream& s_, + data(Handler const&, Stream& s_, DynamicBuffer& b_, message_type& m_) : s(s_) , b(b_) @@ -339,7 +348,7 @@ class read_msg_op public: read_msg_op(read_msg_op&&) = default; - read_msg_op(read_msg_op const&) = default; + read_msg_op(read_msg_op const&) = delete; template<class DeducedHandler, class... Args> read_msg_op(DeducedHandler&& h, Stream& s, Args&&... args) @@ -354,7 +363,7 @@ public: allocator_type get_allocator() const noexcept { - return boost::asio::get_associated_allocator(d_.handler()); + return (boost::asio::get_associated_allocator)(d_.handler()); } using executor_type = boost::asio::associated_executor_t< @@ -363,23 +372,32 @@ public: executor_type get_executor() const noexcept { - return boost::asio::get_associated_executor( + return (boost::asio::get_associated_executor)( d_.handler(), d_->s.get_executor()); } void operator()( - error_code ec = {}, - std::size_t bytes_transferred = 0); + error_code ec, + std::size_t bytes_transferred = 0, + bool cont = true); friend bool asio_handler_is_continuation(read_msg_op* op) { using boost::asio::asio_handler_is_continuation; - return op->d_->state >= 2 ? true : + return op->d_->cont ? true : asio_handler_is_continuation( std::addressof(op->d_.handler())); } + + template<class Function> + friend + void asio_handler_invoke(Function&& f, read_msg_op* op) + { + using boost::asio::asio_handler_invoke; + asio_handler_invoke(f, std::addressof(op->d_.handler())); + } }; template<class Stream, class DynamicBuffer, @@ -390,35 +408,32 @@ read_msg_op<Stream, DynamicBuffer, isRequest, Body, Allocator, Handler>:: operator()( error_code ec, - std::size_t bytes_transferred) + std::size_t bytes_transferred, + bool cont) { auto& d = *d_; - switch(d.state) + d.cont = cont; + BOOST_ASIO_CORO_REENTER(*this) { - case 0: - d.state = 1; - - do_read: - return async_read_some( - d.s, d.b, d.p, std::move(*this)); - - case 1: - case 2: - if(ec) - goto upcall; - d.bytes_transferred += - bytes_transferred; - if(d.p.is_done()) + for(;;) { - d.m = d.p.release(); - goto upcall; + BOOST_ASIO_CORO_YIELD + async_read_some( + d.s, d.b, d.p, std::move(*this)); + if(ec) + goto upcall; + d.bytes_transferred += + bytes_transferred; + if(d.p.is_done()) + { + d.m = d.p.release(); + goto upcall; + } } - d.state = 2; - goto do_read; + upcall: + bytes_transferred = d.bytes_transferred; + d_.invoke(ec, bytes_transferred); } -upcall: - bytes_transferred = d.bytes_transferred; - d_.invoke(ec, bytes_transferred); } } // detail @@ -536,12 +551,13 @@ async_read_some( boost::asio::is_dynamic_buffer<DynamicBuffer>::value, "DynamicBuffer requirements not met"); BOOST_ASSERT(! parser.is_done()); - boost::asio::async_completion<ReadHandler, - void(error_code, std::size_t)> init{handler}; + BOOST_BEAST_HANDLER_INIT( + ReadHandler, void(error_code, std::size_t)); detail::read_some_op<AsyncReadStream, DynamicBuffer, isRequest, Derived, BOOST_ASIO_HANDLER_TYPE( ReadHandler, void(error_code, std::size_t))>{ - init.completion_handler, stream, buffer, parser}(); + std::move(init.completion_handler), stream, buffer, parser}( + {}, 0, false); return init.result.get(); } @@ -623,12 +639,13 @@ async_read_header( boost::asio::is_dynamic_buffer<DynamicBuffer>::value, "DynamicBuffer requirements not met"); parser.eager(false); - boost::asio::async_completion<ReadHandler, - void(error_code, std::size_t)> init{handler}; + BOOST_BEAST_HANDLER_INIT( + ReadHandler, void(error_code, std::size_t)); detail::read_op<AsyncReadStream, DynamicBuffer, isRequest, Derived, detail::parser_is_header_done, BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{ - init.completion_handler, stream, buffer, parser}(); + std::move(init.completion_handler), stream, + buffer, parser}({}, 0, false); return init.result.get(); } @@ -710,13 +727,13 @@ async_read( boost::asio::is_dynamic_buffer<DynamicBuffer>::value, "DynamicBuffer requirements not met"); parser.eager(true); - boost::asio::async_completion< - ReadHandler, - void(error_code, std::size_t)> init{handler}; + BOOST_BEAST_HANDLER_INIT( + ReadHandler, void(error_code, std::size_t)); detail::read_op<AsyncReadStream, DynamicBuffer, isRequest, Derived, detail::parser_is_done, BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{ - init.completion_handler, stream, buffer, parser}(); + std::move(init.completion_handler), stream, buffer, parser}( + {}, 0, false); return init.result.get(); } @@ -801,16 +818,16 @@ async_read( "Body requirements not met"); static_assert(is_body_reader<Body>::value, "BodyReader requirements not met"); - boost::asio::async_completion< - ReadHandler, - void(error_code, std::size_t)> init{handler}; + BOOST_BEAST_HANDLER_INIT( + ReadHandler, void(error_code, std::size_t)); detail::read_msg_op< AsyncReadStream, DynamicBuffer, isRequest, Body, Allocator, BOOST_ASIO_HANDLER_TYPE( ReadHandler, void(error_code, std::size_t))>{ - init.completion_handler, stream, buffer, msg}(); + std::move(init.completion_handler), stream, buffer, msg}( + {}, 0, false); return init.result.get(); } diff --git a/boost/beast/http/impl/serializer.ipp b/boost/beast/http/impl/serializer.ipp index 11cf857845..b37856567f 100644 --- a/boost/beast/http/impl/serializer.ipp +++ b/boost/beast/http/impl/serializer.ipp @@ -25,18 +25,18 @@ template< bool isRequest, class Body, class Fields> void serializer<isRequest, Body, Fields>:: -frdinit(std::true_type) +fwrinit(std::true_type) { - frd_.emplace(m_, m_.version(), m_.method()); + fwr_.emplace(m_, m_.version(), m_.method()); } template< bool isRequest, class Body, class Fields> void serializer<isRequest, Body, Fields>:: -frdinit(std::false_type) +fwrinit(std::false_type) { - frd_.emplace(m_, m_.version(), m_.result_int()); + fwr_.emplace(m_, m_.version(), m_.result_int()); } template< @@ -57,9 +57,31 @@ do_visit(error_code& ec, Visit& visit) template< bool isRequest, class Body, class Fields> serializer<isRequest, Body, Fields>:: -serializer(value_type& m) +serializer(value_type& m, std::true_type) + : m_(m) + , wr_(m_) +{ +#ifndef BOOST_BEAST_ALLOW_DEPRECATED + // Deprecated BodyWriter Concept (v1.66) + static_assert(sizeof(Body) == 0, + BOOST_BEAST_DEPRECATION_STRING); +#endif +} + +template< + bool isRequest, class Body, class Fields> +serializer<isRequest, Body, Fields>:: +serializer(value_type& m, std::false_type) : m_(m) - , rd_(m_) + , wr_(m_.base(), m_.body()) +{ +} + +template< + bool isRequest, class Body, class Fields> +serializer<isRequest, Body, Fields>:: +serializer(value_type& m) + : serializer(m, detail::has_deprecated_body_writer<Body>{}) { } @@ -75,22 +97,22 @@ next(error_code& ec, Visit&& visit) { case do_construct: { - frdinit(std::integral_constant<bool, + fwrinit(std::integral_constant<bool, isRequest>{}); if(m_.chunked()) goto go_init_c; s_ = do_init; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; } case do_init: { - rd_.init(ec); + wr_.init(ec); if(ec) return; if(split_) goto go_header_only; - auto result = rd_.get(ec); + auto result = wr_.get(ec); if(ec == error::need_more) goto go_header_only; if(ec) @@ -100,10 +122,10 @@ next(error_code& ec, Visit&& visit) more_ = result->second; v_.template emplace<2>( boost::in_place_init, - frd_->get(), + fwr_->get(), result->first); s_ = do_header; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; } case do_header: @@ -111,20 +133,20 @@ next(error_code& ec, Visit&& visit) break; go_header_only: - v_.template emplace<1>(frd_->get()); + v_.template emplace<1>(fwr_->get()); s_ = do_header_only; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; case do_header_only: do_visit<1>(ec, visit); break; case do_body: s_ = do_body + 1; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; case do_body + 1: { - auto result = rd_.get(ec); + auto result = wr_.get(ec); if(ec) return; if(! result) @@ -132,7 +154,7 @@ next(error_code& ec, Visit&& visit) more_ = result->second; v_.template emplace<3>(result->first); s_ = do_body + 2; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; } case do_body + 2: @@ -143,15 +165,15 @@ next(error_code& ec, Visit&& visit) go_init_c: s_ = do_init_c; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; case do_init_c: { - rd_.init(ec); + wr_.init(ec); if(ec) return; if(split_) goto go_header_only_c; - auto result = rd_.get(ec); + auto result = wr_.get(ec); if(ec == error::need_more) goto go_header_only_c; if(ec) @@ -164,7 +186,7 @@ next(error_code& ec, Visit&& visit) // do it all in one buffer v_.template emplace<7>( boost::in_place_init, - frd_->get(), + fwr_->get(), buffer_size(result->first), boost::asio::const_buffer{nullptr, 0}, chunk_crlf{}, @@ -177,14 +199,14 @@ next(error_code& ec, Visit&& visit) } v_.template emplace<4>( boost::in_place_init, - frd_->get(), + fwr_->get(), buffer_size(result->first), boost::asio::const_buffer{nullptr, 0}, chunk_crlf{}, result->first, chunk_crlf{}); s_ = do_header_c; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; } case do_header_c: @@ -192,19 +214,21 @@ next(error_code& ec, Visit&& visit) break; go_header_only_c: - v_.template emplace<1>(frd_->get()); + v_.template emplace<1>(fwr_->get()); s_ = do_header_only_c; + BOOST_FALLTHROUGH; + case do_header_only_c: do_visit<1>(ec, visit); break; case do_body_c: s_ = do_body_c + 1; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; case do_body_c + 1: { - auto result = rd_.get(ec); + auto result = wr_.get(ec); if(ec) return; if(! result) @@ -233,7 +257,7 @@ next(error_code& ec, Visit&& visit) result->first, chunk_crlf{}); s_ = do_body_c + 2; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; } case do_body_c + 2: @@ -242,14 +266,14 @@ next(error_code& ec, Visit&& visit) go_body_final_c: s_ = do_body_final_c; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; case do_body_final_c: do_visit<6>(ec, visit); break; go_all_c: s_ = do_all_c; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; case do_all_c: do_visit<7>(ec, visit); break; @@ -262,7 +286,7 @@ next(error_code& ec, Visit&& visit) boost::asio::const_buffer{nullptr, 0}, chunk_crlf{}); s_ = do_final_c + 1; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; case do_final_c + 1: do_visit<8>(ec, visit); @@ -309,7 +333,7 @@ consume(std::size_t n) v_.template get<1>().consume(n); if(buffer_size(v_.template get<1>()) > 0) break; - frd_ = boost::none; + fwr_ = boost::none; header_done_ = true; if(! split_) goto go_complete; @@ -353,7 +377,7 @@ consume(std::size_t n) v_.template get<1>().consume(n); if(buffer_size(v_.template get<1>()) > 0) break; - frd_ = boost::none; + fwr_ = boost::none; header_done_ = true; if(! split_) { diff --git a/boost/beast/http/impl/status.ipp b/boost/beast/http/impl/status.ipp index 1cc8f34b63..7d37919423 100644 --- a/boost/beast/http/impl/status.ipp +++ b/boost/beast/http/impl/status.ipp @@ -28,7 +28,7 @@ int_to_status(unsigned v) case status::continue_: case status::switching_protocols: case status::processing: - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; // 2xx case status::ok: @@ -41,7 +41,7 @@ int_to_status(unsigned v) case status::multi_status: case status::already_reported: case status::im_used: - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; // 3xx case status::multiple_choices: @@ -52,7 +52,7 @@ int_to_status(unsigned v) case status::use_proxy: case status::temporary_redirect: case status::permanent_redirect: - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; // 4xx case status::bad_request: @@ -84,7 +84,7 @@ int_to_status(unsigned v) case status::connection_closed_without_response: case status::unavailable_for_legal_reasons: case status::client_closed_request: - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; // 5xx case status::internal_server_error: diff --git a/boost/beast/http/impl/verb.ipp b/boost/beast/http/impl/verb.ipp index 820609165b..8f8b2e33bf 100644 --- a/boost/beast/http/impl/verb.ipp +++ b/boost/beast/http/impl/verb.ipp @@ -72,6 +72,10 @@ verb_to_string(verb v) } BOOST_THROW_EXCEPTION(std::invalid_argument{"unknown verb"}); + + // Help some compilers which don't know the next line is + // unreachable, otherwise spurious warnings are generated. + return "<unknown>"; } template<class = void> @@ -159,7 +163,7 @@ string_to_verb(string_view v) return verb::connect; if(eq(v, "PY")) return verb::copy; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; default: break; @@ -220,7 +224,7 @@ string_to_verb(string_view v) case 'O': if(eq(v, "VE")) return verb::move; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; default: break; @@ -264,7 +268,7 @@ string_to_verb(string_view v) return verb::purge; if(eq(v, "T")) return verb::put; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; default: break; diff --git a/boost/beast/http/impl/write.ipp b/boost/beast/http/impl/write.ipp index 9d5be277ec..af31cd9be9 100644 --- a/boost/beast/http/impl/write.ipp +++ b/boost/beast/http/impl/write.ipp @@ -19,6 +19,7 @@ #include <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/handler_continuation_hook.hpp> +#include <boost/asio/handler_invoke_hook.hpp> #include <boost/asio/post.hpp> #include <boost/asio/write.hpp> #include <boost/optional.hpp> @@ -67,7 +68,7 @@ class write_some_op public: write_some_op(write_some_op&&) = default; - write_some_op(write_some_op const&) = default; + write_some_op(write_some_op const&) = delete; template<class DeducedHandler> write_some_op(DeducedHandler&& h, Stream& s, @@ -84,7 +85,7 @@ public: allocator_type get_allocator() const noexcept { - return boost::asio::get_associated_allocator(h_); + return (boost::asio::get_associated_allocator)(h_); } using executor_type = boost::asio::associated_executor_t< @@ -93,7 +94,7 @@ public: executor_type get_executor() const noexcept { - return boost::asio::get_associated_executor( + return (boost::asio::get_associated_executor)( h_, s_.get_executor()); } @@ -112,6 +113,14 @@ public: return asio_handler_is_continuation( std::addressof(op->h_)); } + + template<class Function> + friend + void asio_handler_invoke(Function&& f, write_some_op* op) + { + using boost::asio::asio_handler_invoke; + asio_handler_invoke(f, std::addressof(op->h_)); + } }; template< @@ -203,7 +212,7 @@ class write_op public: write_op(write_op&&) = default; - write_op(write_op const&) = default; + write_op(write_op const&) = delete; template<class DeducedHandler> write_op(DeducedHandler&& h, Stream& s, @@ -220,7 +229,7 @@ public: allocator_type get_allocator() const noexcept { - return boost::asio::get_associated_allocator(h_); + return (boost::asio::get_associated_allocator)(h_); } using executor_type = boost::asio::associated_executor_t< @@ -229,7 +238,7 @@ public: executor_type get_executor() const noexcept { - return boost::asio::get_associated_executor( + return (boost::asio::get_associated_executor)( h_, s_.get_executor()); } @@ -246,6 +255,14 @@ public: asio_handler_is_continuation( std::addressof(op->h_)); } + + template<class Function> + friend + void asio_handler_invoke(Function&& f, write_op* op) + { + using boost::asio::asio_handler_invoke; + asio_handler_invoke(f, std::addressof(op->h_)); + } }; template< @@ -280,7 +297,7 @@ operator()( case 2: state_ = 3; - BOOST_BEAST_FALLTHROUGH; + BOOST_FALLTHROUGH; case 3: { @@ -306,7 +323,7 @@ class write_msg_op Stream& s; serializer<isRequest, Body, Fields> sr; - data(Handler&, Stream& s_, message< + data(Handler const&, Stream& s_, message< isRequest, Body, Fields>& m_) : s(s_) , sr(m_) @@ -318,7 +335,7 @@ class write_msg_op public: write_msg_op(write_msg_op&&) = default; - write_msg_op(write_msg_op const&) = default; + write_msg_op(write_msg_op const&) = delete; template<class DeducedHandler, class... Args> write_msg_op(DeducedHandler&& h, Stream& s, Args&&... args) @@ -333,7 +350,7 @@ public: allocator_type get_allocator() const noexcept { - return boost::asio::get_associated_allocator(d_.handler()); + return (boost::asio::get_associated_allocator)(d_.handler()); } using executor_type = boost::asio::associated_executor_t< @@ -342,7 +359,7 @@ public: executor_type get_executor() const noexcept { - return boost::asio::get_associated_executor( + return (boost::asio::get_associated_executor)( d_.handler(), d_->s.get_executor()); } @@ -360,6 +377,14 @@ public: return asio_handler_is_continuation( std::addressof(op->d_.handler())); } + + template<class Function> + friend + void asio_handler_invoke(Function&& f, write_msg_op* op) + { + using boost::asio::asio_handler_invoke; + asio_handler_invoke(f, std::addressof(op->d_.handler())); + } }; template<class Stream, class Handler, @@ -441,7 +466,7 @@ template< class SyncWriteStream, bool isRequest, class Body, class Fields> std::size_t -write_some( +write_some_impl( SyncWriteStream& stream, serializer<isRequest, Body, Fields>& sr, error_code& ec) @@ -466,20 +491,19 @@ template< class WriteHandler> BOOST_ASIO_INITFN_RESULT_TYPE( WriteHandler, void(error_code, std::size_t)) -async_write_some( +async_write_some_impl( AsyncWriteStream& stream, serializer<isRequest, Body, Fields>& sr, WriteHandler&& handler) { - boost::asio::async_completion< - WriteHandler, - void(error_code, std::size_t)> init{handler}; + BOOST_BEAST_HANDLER_INIT( + WriteHandler, void(error_code, std::size_t)); detail::write_some_op< AsyncWriteStream, BOOST_ASIO_HANDLER_TYPE(WriteHandler, void(error_code, std::size_t)), isRequest, Body, Fields>{ - init.completion_handler, stream, sr}(); + std::move(init.completion_handler), stream, sr}(); return init.result.get(); } @@ -524,7 +548,7 @@ write_some( "Body requirements not met"); static_assert(is_body_writer<Body>::value, "BodyWriter requirements not met"); - return detail::write_some(stream, sr, ec); + return detail::write_some_impl(stream, sr, ec); } template< @@ -545,7 +569,7 @@ async_write_some( "Body requirements not met"); static_assert(is_body_writer<Body>::value, "BodyWriter requirements not met"); - return detail::async_write_some(stream, sr, + return detail::async_write_some_impl(stream, sr, std::forward<WriteHandler>(handler)); } @@ -629,16 +653,15 @@ async_write_header( static_assert(is_body_writer<Body>::value, "BodyWriter requirements not met"); sr.split(true); - boost::asio::async_completion< - WriteHandler, - void(error_code, std::size_t)> init{handler}; + BOOST_BEAST_HANDLER_INIT( + WriteHandler, void(error_code, std::size_t)); detail::write_op< AsyncWriteStream, BOOST_ASIO_HANDLER_TYPE(WriteHandler, void(error_code, std::size_t)), detail::serializer_is_header_done, isRequest, Body, Fields>{ - init.completion_handler, stream, sr}(); + std::move(init.completion_handler), stream, sr}(); return init.result.get(); } @@ -706,16 +729,15 @@ async_write( static_assert(is_body_writer<Body>::value, "BodyWriter requirements not met"); sr.split(false); - boost::asio::async_completion< - WriteHandler, - void(error_code, std::size_t)> init{handler}; + BOOST_BEAST_HANDLER_INIT( + WriteHandler, void(error_code, std::size_t)); detail::write_op< AsyncWriteStream, BOOST_ASIO_HANDLER_TYPE(WriteHandler, void(error_code, std::size_t)), detail::serializer_is_done, isRequest, Body, Fields>{ - init.completion_handler, stream, sr}(); + std::move(init.completion_handler), stream, sr}(); return init.result.get(); } @@ -780,15 +802,14 @@ async_write( "Body requirements not met"); static_assert(is_body_writer<Body>::value, "BodyWriter requirements not met"); - boost::asio::async_completion< - WriteHandler, - void(error_code, std::size_t)> init{handler}; + BOOST_BEAST_HANDLER_INIT( + WriteHandler, void(error_code, std::size_t)); detail::write_msg_op< AsyncWriteStream, BOOST_ASIO_HANDLER_TYPE(WriteHandler, void(error_code, std::size_t)), isRequest, Body, Fields>{ - init.completion_handler, stream, msg}(); + std::move(init.completion_handler), stream, msg}(); return init.result.get(); } diff --git a/boost/beast/http/message.hpp b/boost/beast/http/message.hpp index 5cf5d94dc9..0455042786 100644 --- a/boost/beast/http/message.hpp +++ b/boost/beast/http/message.hpp @@ -862,7 +862,8 @@ struct message #endif body()& noexcept { - return this->member(); + return this->beast::detail::empty_base_optimization< + typename Body::value_type>::member(); } /// Returns the body @@ -873,7 +874,9 @@ struct message #endif body()&& noexcept { - return std::move(this->member()); + return std::move( + this->beast::detail::empty_base_optimization< + typename Body::value_type>::member()); } /// Returns the body @@ -884,7 +887,8 @@ struct message #endif body() const& noexcept { - return this->member(); + return this->beast::detail::empty_base_optimization< + typename Body::value_type>::member(); } private: diff --git a/boost/beast/http/parser.hpp b/boost/beast/http/parser.hpp index 47e1003533..69d93cf03c 100644 --- a/boost/beast/http/parser.hpp +++ b/boost/beast/http/parser.hpp @@ -63,7 +63,7 @@ class parser parser<isRequest, Body, Allocator>>; message<isRequest, Body, basic_fields<Allocator>> m_; - typename Body::reader wr_; + typename Body::reader rd_; bool rd_inited_ = false; std::function<void( @@ -84,21 +84,17 @@ public: /// Destructor ~parser() = default; - /// Constructor - parser(); - - /// Constructor + /// Constructor (disallowed) parser(parser const&) = delete; - /// Assignment + /// Assignment (disallowed) parser& operator=(parser const&) = delete; - /** Constructor + /// Constructor (disallowed) + parser(parser&& other) = delete; - After the move, the only valid operation - on the moved-from object is destruction. - */ - parser(parser&& other) = default; + /// Constructor + parser(); /** Constructor @@ -303,6 +299,39 @@ public: private: friend class basic_parser<isRequest, parser>; + parser(std::true_type); + parser(std::false_type); + + template<class OtherBody, class... Args, + class = typename std::enable_if< + ! std::is_same<Body, OtherBody>::value>::type> + parser( + std::true_type, + parser<isRequest, OtherBody, Allocator>&& parser, + Args&&... args); + + template<class OtherBody, class... Args, + class = typename std::enable_if< + ! std::is_same<Body, OtherBody>::value>::type> + parser( + std::false_type, + parser<isRequest, OtherBody, Allocator>&& parser, + Args&&... args); + + template<class Arg1, class... ArgN, + class = typename std::enable_if< + ! detail::is_parser<typename + std::decay<Arg1>::type>::value>::type> + explicit + parser(Arg1&& arg1, std::true_type, ArgN&&... argn); + + template<class Arg1, class... ArgN, + class = typename std::enable_if< + ! detail::is_parser<typename + std::decay<Arg1>::type>::value>::type> + explicit + parser(Arg1&& arg1, std::false_type, ArgN&&... argn); + void on_request_impl( verb method, @@ -376,7 +405,7 @@ private: boost::optional<std::uint64_t> const& content_length, error_code& ec) { - wr_.init(content_length, ec); + rd_.init(content_length, ec); rd_inited_ = true; } @@ -385,7 +414,7 @@ private: string_view body, error_code& ec) { - return wr_.put(boost::asio::buffer( + return rd_.put(boost::asio::buffer( body.data(), body.size()), ec); } @@ -408,14 +437,14 @@ private: { if(cb_b_) return cb_b_(remain, body, ec); - return wr_.put(boost::asio::buffer( + return rd_.put(boost::asio::buffer( body.data(), body.size()), ec); } void on_finish_impl(error_code& ec) { - wr_.finish(ec); + rd_.finish(ec); } }; diff --git a/boost/beast/http/read.hpp b/boost/beast/http/read.hpp index 4f159aec2b..a4f0efe400 100644 --- a/boost/beast/http/read.hpp +++ b/boost/beast/http/read.hpp @@ -175,8 +175,8 @@ read_some( The object must remain valid at least until the handler is called; ownership is not transferred. - @param handler The handler to be called when the request - completes. Copies will be made of the handler as required. + @param handler Invoked when the operation completes. + The handler may be moved or copied as needed. The equivalent function signature of the handler must be: @code void handler( error_code const& error, // result of operation @@ -361,8 +361,8 @@ read_header( The object must remain valid at least until the handler is called; ownership is not transferred. - @param handler The handler to be called when the request - completes. Copies will be made of the handler as required. + @param handler Invoked when the operation completes. + The handler may be moved or copied as needed. The equivalent function signature of the handler must be: @code void handler( error_code const& error, // result of operation, @@ -545,8 +545,8 @@ read( The object must remain valid at least until the handler is called; ownership is not transferred. - @param handler The handler to be called when the request - completes. Copies will be made of the handler as required. + @param handler Invoked when the operation completes. + The handler may be moved or copied as needed. The equivalent function signature of the handler must be: @code void handler( error_code const& error, // result of operation, @@ -731,8 +731,8 @@ read( The object must remain valid at least until the handler is called; ownership is not transferred. - @param handler The handler to be called when the operation - completes. Copies will be made of the handler as required. + @param handler Invoked when the operation completes. + The handler may be moved or copied as needed. The equivalent function signature of the handler must be: @code void handler( error_code const& error, // result of operation, diff --git a/boost/beast/http/serializer.hpp b/boost/beast/http/serializer.hpp index 50e58185a9..bbb562a620 100644 --- a/boost/beast/http/serializer.hpp +++ b/boost/beast/http/serializer.hpp @@ -71,14 +71,20 @@ public: #if BOOST_BEAST_DOXYGEN using value_type = implementation_defined; #else - using value_type = - typename std::conditional< - std::is_constructible<typename Body::writer, - message<isRequest, Body, Fields>&>::value && - ! std::is_constructible<typename Body::writer, - message<isRequest, Body, Fields> const&>::value, - message<isRequest, Body, Fields>, - message<isRequest, Body, Fields> const>::type; + using value_type = typename std::conditional< + (std::is_constructible<typename Body::writer, + header<isRequest, Fields>&, + typename Body::value_type&>::value && + ! std::is_constructible<typename Body::writer, + header<isRequest, Fields> const&, + typename Body::value_type const&>::value) || + // Deprecated BodyWriter Concept (v1.66) + (std::is_constructible<typename Body::writer, + message<isRequest, Body, Fields>&>::value && + ! std::is_constructible<typename Body::writer, + message<isRequest, Body, Fields> const&>::value), + message<isRequest, Body, Fields>, + message<isRequest, Body, Fields> const>::type; #endif private: @@ -104,8 +110,8 @@ private: do_complete = 120 }; - void frdinit(std::true_type); - void frdinit(std::false_type); + void fwrinit(std::true_type); + void fwrinit(std::false_type); template<std::size_t, class Visit> void @@ -173,8 +179,8 @@ private: using pcb8_t = buffers_prefix_view<cb8_t const&>; value_type& m_; - writer rd_; - boost::optional<typename Fields::writer> frd_; + writer wr_; + boost::optional<typename Fields::writer> fwr_; beast::detail::variant< cb1_t, cb2_t, cb3_t, cb4_t, cb5_t ,cb6_t, cb7_t, cb8_t> v_; @@ -188,6 +194,8 @@ private: bool header_done_ = false; bool more_; + serializer(value_type& msg, std::true_type); + serializer(value_type& msg, std::false_type); public: /// Constructor serializer(serializer&&) = default; @@ -336,7 +344,7 @@ public: void consume(std::size_t n); - /** Provides low-level access to the associated @b BodyWriter + /** Provides low-level access to the associated @b BodyWriter (DEPRECATED) This function provides access to the instance of the writer associated with the body and created by the serializer @@ -349,7 +357,27 @@ public: writer& reader_impl() { - return rd_; + #ifndef BOOST_BEAST_ALLOW_DEPRECATED + BOOST_STATIC_ASSERT_MSG(sizeof(Body) == 0, + BOOST_BEAST_DEPRECATION_STRING); + #endif + return wr_; + } + + /** Provides low-level access to the associated @b BodyWriter + + This function provides access to the instance of the writer + associated with the body and created by the serializer + upon construction. The behavior of accessing this object + is defined by the specification of the particular writer + and its associated body. + + @return A reference to the writer. + */ + writer& + writer_impl() + { + return wr_; } }; diff --git a/boost/beast/http/span_body.hpp b/boost/beast/http/span_body.hpp index 6282ecc6d9..4688dc8741 100644 --- a/boost/beast/http/span_body.hpp +++ b/boost/beast/http/span_body.hpp @@ -73,9 +73,8 @@ public: public: template<bool isRequest, class Fields> explicit - reader(message<isRequest, - span_body, Fields>& m) - : body_(m.body()) + reader(header<isRequest, Fields>&, value_type& b) + : body_(b) { } @@ -138,9 +137,8 @@ public: template<bool isRequest, class Fields> explicit - writer(message<isRequest, - span_body, Fields> const& msg) - : body_(msg.body()) + writer(header<isRequest, Fields> const&, value_type const& b) + : body_(b) { } diff --git a/boost/beast/http/string_body.hpp b/boost/beast/http/string_body.hpp index 18eda414e8..89447e50ff 100644 --- a/boost/beast/http/string_body.hpp +++ b/boost/beast/http/string_body.hpp @@ -81,9 +81,8 @@ public: public: template<bool isRequest, class Fields> explicit - reader(message<isRequest, - basic_string_body, Fields>& m) - : body_(m.body()) + reader(header<isRequest, Fields>&, value_type& b) + : body_(b) { } @@ -166,9 +165,8 @@ public: template<bool isRequest, class Fields> explicit - writer(message<isRequest, - basic_string_body, Fields> const& msg) - : body_(msg.body()) + writer(header<isRequest, Fields> const&, value_type const& b) + : body_(b) { } diff --git a/boost/beast/http/type_traits.hpp b/boost/beast/http/type_traits.hpp index f90f16ffef..0c8210443e 100644 --- a/boost/beast/http/type_traits.hpp +++ b/boost/beast/http/type_traits.hpp @@ -89,11 +89,19 @@ struct is_body_writer<T, beast::detail::void_t< std::declval<typename T::writer>().get(std::declval<error_code&>()), (void)0)>> : std::integral_constant<bool, boost::asio::is_const_buffer_sequence< - typename T::writer::const_buffers_type>::value && + typename T::writer::const_buffers_type>::value && ( + (std::is_constructible<typename T::writer, + header<true, detail::fields_model>&, + typename T::value_type&>::value && std::is_constructible<typename T::writer, + header<false, detail::fields_model>&, + typename T::value_type&>::value) || + // Deprecated BodyWriter Concept (v1.66) + (std::is_constructible<typename T::writer, message<true, T, detail::fields_model>&>::value && std::is_constructible<typename T::writer, - message<false, T, detail::fields_model>&>::value + message<false, T, detail::fields_model>&>::value) + ) > {}; #endif @@ -136,11 +144,18 @@ struct is_body_reader<T, beast::detail::void_t<decltype( std::declval<typename T::reader&>().finish( std::declval<error_code&>()), (void)0)>> : std::integral_constant<bool, + (std::is_constructible<typename T::reader, + header<true, detail::fields_model>&, + typename T::value_type&>::value && std::is_constructible<typename T::reader, + header<false,detail::fields_model>&, + typename T::value_type&>::value) || + // Deprecated BodyReader Concept (v1.66) + (std::is_constructible<typename T::reader, message<true, T, detail::fields_model>&>::value && std::is_constructible<typename T::reader, - message<false, T, detail::fields_model>&>::value - > + message<false, T, detail::fields_model>&>::value) + > { }; #endif diff --git a/boost/beast/http/vector_body.hpp b/boost/beast/http/vector_body.hpp index eb37145d61..40c885e43e 100644 --- a/boost/beast/http/vector_body.hpp +++ b/boost/beast/http/vector_body.hpp @@ -76,9 +76,8 @@ public: public: template<bool isRequest, class Fields> explicit - reader(message<isRequest, - vector_body, Fields>& m) - : body_(m.body()) + reader(header<isRequest, Fields>&, value_type& b) + : body_(b) { } @@ -155,9 +154,8 @@ public: template<bool isRequest, class Fields> explicit - writer(message<isRequest, - vector_body, Fields> const& msg) - : body_(msg.body()) + writer(header<isRequest, Fields> const&, value_type const& b) + : body_(b) { } diff --git a/boost/beast/http/write.hpp b/boost/beast/http/write.hpp index 755ed0b94b..3b916b1d7b 100644 --- a/boost/beast/http/write.hpp +++ b/boost/beast/http/write.hpp @@ -148,8 +148,8 @@ write_some( The object must remain valid at least until the handler is called; ownership is not transferred. - @param handler The handler to be called when the operation - completes. Copies will be made of the handler as required. + @param handler Invoked when the operation completes. + The handler may be moved or copied as needed. The equivalent function signature of the handler must be: @code void handler( error_code const& error, // result of operation @@ -269,8 +269,8 @@ write_header( The object must remain valid at least until the handler is called; ownership is not transferred. - @param handler The handler to be called when the operation - completes. Copies will be made of the handler as required. + @param handler Invoked when the operation completes. + The handler may be moved or copied as needed. The equivalent function signature of the handler must be: @code void handler( error_code const& error, // result of operation @@ -387,8 +387,8 @@ write( The object must remain valid at least until the handler is called; ownership is not transferred. - @param handler The handler to be called when the operation - completes. Copies will be made of the handler as required. + @param handler Invoked when the operation completes. + The handler may be moved or copied as needed. The equivalent function signature of the handler must be: @code void handler( error_code const& error, // result of operation @@ -502,8 +502,8 @@ write( The object must remain valid at least until the handler is called; ownership is not transferred. - @param handler The handler to be called when the operation - completes. Copies will be made of the handler as required. + @param handler Invoked when the operation completes. + The handler may be moved or copied as needed. The equivalent function signature of the handler must be: @code void handler( error_code const& error, // result of operation |