diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2019-12-05 15:22:41 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2019-12-05 15:22:41 +0900 |
commit | 3c1df2168531ad5580076ae08d529054689aeedd (patch) | |
tree | 941aff6f86393eecacddfec252a8508c7e8351c9 /boost/beast/http/impl | |
parent | d6a306e745acfee00e81ccaf3324a2a03516db41 (diff) | |
download | boost-3c1df2168531ad5580076ae08d529054689aeedd.tar.gz boost-3c1df2168531ad5580076ae08d529054689aeedd.tar.bz2 boost-3c1df2168531ad5580076ae08d529054689aeedd.zip |
Imported Upstream version 1.70.0upstream/1.70.0
Diffstat (limited to 'boost/beast/http/impl')
18 files changed, 1869 insertions, 2235 deletions
diff --git a/boost/beast/http/impl/basic_parser.hpp b/boost/beast/http/impl/basic_parser.hpp new file mode 100644 index 0000000000..e25be7ce08 --- /dev/null +++ b/boost/beast/http/impl/basic_parser.hpp @@ -0,0 +1,78 @@ +// +// Copyright (c) 2016-2019 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) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_HTTP_IMPL_BASIC_PARSER_HPP +#define BOOST_BEAST_HTTP_IMPL_BASIC_PARSER_HPP + +#include <boost/beast/core/buffer_traits.hpp> +#include <boost/asio/buffer.hpp> +#include <boost/make_unique.hpp> + +namespace boost { +namespace beast { +namespace http { + +template<bool isRequest> +template<class ConstBufferSequence> +std::size_t +basic_parser<isRequest>:: +put(ConstBufferSequence const& buffers, + error_code& ec) +{ + static_assert(net::is_const_buffer_sequence< + ConstBufferSequence>::value, + "ConstBufferSequence type requirements not met"); + auto const p = net::buffer_sequence_begin(buffers); + auto const last = net::buffer_sequence_end(buffers); + if(p == last) + { + ec = {}; + return 0; + } + if(std::next(p) == last) + { + // single buffer + return put(net::const_buffer(*p), ec); + } + auto const size = buffer_bytes(buffers); + if(size <= max_stack_buffer) + return put_from_stack(size, buffers, ec); + if(size > buf_len_) + { + // reallocate + buf_ = boost::make_unique_noinit<char[]>(size); + buf_len_ = size; + } + // flatten + net::buffer_copy(net::buffer( + buf_.get(), buf_len_), buffers); + return put(net::const_buffer{ + buf_.get(), buf_len_}, ec); +} + +template<bool isRequest> +template<class ConstBufferSequence> +std::size_t +basic_parser<isRequest>:: +put_from_stack(std::size_t size, + ConstBufferSequence const& buffers, + error_code& ec) +{ + char buf[max_stack_buffer]; + net::buffer_copy(net::mutable_buffer( + buf, sizeof(buf)), buffers); + return put(net::const_buffer{ + buf, size}, ec); +} + +} // http +} // beast +} // boost + +#endif diff --git a/boost/beast/http/impl/basic_parser.ipp b/boost/beast/http/impl/basic_parser.ipp index 7a46092861..99947ae1f2 100644 --- a/boost/beast/http/impl/basic_parser.ipp +++ b/boost/beast/http/impl/basic_parser.ipp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2016-2019 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) @@ -10,14 +10,14 @@ #ifndef BOOST_BEAST_HTTP_IMPL_BASIC_PARSER_IPP #define BOOST_BEAST_HTTP_IMPL_BASIC_PARSER_IPP +#include <boost/beast/http/basic_parser.hpp> +#include <boost/beast/http/error.hpp> +#include <boost/beast/http/rfc7230.hpp> +#include <boost/beast/core/buffer_traits.hpp> #include <boost/beast/core/static_string.hpp> -#include <boost/beast/core/type_traits.hpp> #include <boost/beast/core/detail/clamp.hpp> #include <boost/beast/core/detail/config.hpp> -#include <boost/beast/http/error.hpp> -#include <boost/beast/http/rfc7230.hpp> #include <boost/asio/buffer.hpp> -#include <boost/make_unique.hpp> #include <algorithm> #include <utility> @@ -25,26 +25,9 @@ namespace boost { namespace beast { namespace http { -template<bool isRequest, class Derived> -template<class OtherDerived> -basic_parser<isRequest, Derived>:: -basic_parser(basic_parser< - isRequest, OtherDerived>&& other) - : body_limit_(other.body_limit_) - , len_(other.len_) - , buf_(std::move(other.buf_)) - , buf_len_(other.buf_len_) - , skip_(other.skip_) - , header_limit_(other.header_limit_) - , status_(other.status_) - , state_(other.state_) - , f_(other.f_) -{ -} - -template<bool isRequest, class Derived> +template<bool isRequest> bool -basic_parser<isRequest, Derived>:: +basic_parser<isRequest>:: keep_alive() const { BOOST_ASSERT(is_header_done()); @@ -61,20 +44,31 @@ keep_alive() const return (f_ & flagNeedEOF) == 0; } -template<bool isRequest, class Derived> +template<bool isRequest> boost::optional<std::uint64_t> -basic_parser<isRequest, Derived>:: +basic_parser<isRequest>:: content_length() const { BOOST_ASSERT(is_header_done()); if(! (f_ & flagContentLength)) return boost::none; + return len0_; +} + +template<bool isRequest> +boost::optional<std::uint64_t> +basic_parser<isRequest>:: +content_length_remaining() const +{ + BOOST_ASSERT(is_header_done()); + if(! (f_ & flagContentLength)) + return boost::none; return len_; } -template<bool isRequest, class Derived> +template<bool isRequest> void -basic_parser<isRequest, Derived>:: +basic_parser<isRequest>:: skip(bool v) { BOOST_ASSERT(! got_some()); @@ -84,59 +78,18 @@ skip(bool v) f_ &= ~flagSkipBody; } -template<bool isRequest, class Derived> -template<class ConstBufferSequence> +template<bool isRequest> std::size_t -basic_parser<isRequest, Derived>:: -put(ConstBufferSequence const& buffers, - error_code& ec) -{ - static_assert(boost::asio::is_const_buffer_sequence< - ConstBufferSequence>::value, - "ConstBufferSequence requirements not met"); - using boost::asio::buffer_copy; - using boost::asio::buffer_size; - auto const p = boost::asio::buffer_sequence_begin(buffers); - auto const last = boost::asio::buffer_sequence_end(buffers); - if(p == last) - { - ec.assign(0, ec.category()); - return 0; - } - if(std::next(p) == last) - { - // single buffer - return put(boost::asio::const_buffer(*p), ec); - } - auto const size = buffer_size(buffers); - if(size <= max_stack_buffer) - return put_from_stack(size, buffers, ec); - if(size > buf_len_) - { - // reallocate - buf_ = boost::make_unique_noinit<char[]>(size); - buf_len_ = size; - } - // flatten - buffer_copy(boost::asio::buffer( - buf_.get(), buf_len_), buffers); - return put(boost::asio::const_buffer{ - buf_.get(), buf_len_}, ec); -} - -template<bool isRequest, class Derived> -std::size_t -basic_parser<isRequest, Derived>:: -put(boost::asio::const_buffer const& buffer, +basic_parser<isRequest>:: +put(net::const_buffer buffer, error_code& ec) { BOOST_ASSERT(state_ != state::complete); - using boost::asio::buffer_size; auto p = static_cast<char const*>(buffer.data()); auto n = buffer.size(); auto const p0 = p; auto const p1 = p0 + n; - ec.assign(0, ec.category()); + ec = {}; loop: switch(state_) { @@ -207,7 +160,7 @@ loop: case state::body0: BOOST_ASSERT(! skip_); - impl().on_body_init_impl(content_length(), ec); + this->on_body_init_impl(content_length(), ec); if(ec) goto done; state_ = state::body; @@ -222,7 +175,7 @@ loop: case state::body_to_eof0: BOOST_ASSERT(! skip_); - impl().on_body_init_impl(content_length(), ec); + this->on_body_init_impl(content_length(), ec); if(ec) goto done; state_ = state::body_to_eof; @@ -236,7 +189,7 @@ loop: break; case state::chunk_header0: - impl().on_body_init_impl(content_length(), ec); + this->on_body_init_impl(content_length(), ec); if(ec) goto done; state_ = state::chunk_header; @@ -255,7 +208,7 @@ loop: break; case state::complete: - ec.assign(0, ec.category()); + ec = {}; goto done; } if(p < p1 && ! is_done() && eager()) @@ -267,9 +220,9 @@ done: return static_cast<std::size_t>(p - p0); } -template<bool isRequest, class Derived> +template<bool isRequest> void -basic_parser<isRequest, Derived>:: +basic_parser<isRequest>:: put_eof(error_code& ec) { BOOST_ASSERT(got_some()); @@ -286,35 +239,19 @@ put_eof(error_code& ec) ec = error::partial_message; return; } - ec.assign(0, ec.category()); + ec = {}; return; } - impl().on_finish_impl(ec); + ec = {}; + this->on_finish_impl(ec); if(ec) return; state_ = state::complete; } -template<bool isRequest, class Derived> -template<class ConstBufferSequence> -std::size_t -basic_parser<isRequest, Derived>:: -put_from_stack(std::size_t size, - ConstBufferSequence const& buffers, - error_code& ec) -{ - char buf[max_stack_buffer]; - using boost::asio::buffer; - using boost::asio::buffer_copy; - buffer_copy(buffer(buf, sizeof(buf)), buffers); - return put(boost::asio::const_buffer{ - buf, size}, ec); -} - -template<bool isRequest, class Derived> -inline +template<bool isRequest> void -basic_parser<isRequest, Derived>:: +basic_parser<isRequest>:: maybe_need_more( char const* p, std::size_t n, error_code& ec) @@ -344,10 +281,9 @@ maybe_need_more( skip_ = 0; } -template<bool isRequest, class Derived> -inline +template<bool isRequest> void -basic_parser<isRequest, Derived>:: +basic_parser<isRequest>:: parse_start_line( char const*& in, char const* last, error_code& ec, std::true_type) @@ -393,7 +329,7 @@ parse_start_line( if(version >= 11) f_ |= flagHTTP11; - impl().on_request_impl(string_to_verb(method), + this->on_request_impl(string_to_verb(method), method, target, version, ec); if(ec) return; @@ -402,10 +338,9 @@ parse_start_line( state_ = state::fields; } -template<bool isRequest, class Derived> -inline +template<bool isRequest> void -basic_parser<isRequest, Derived>:: +basic_parser<isRequest>:: parse_start_line( char const*& in, char const* last, error_code& ec, std::false_type) @@ -452,7 +387,7 @@ parse_start_line( if(version >= 11) f_ |= flagHTTP11; - impl().on_response_impl( + this->on_response_impl( status_, reason, version, ec); if(ec) return; @@ -461,9 +396,9 @@ parse_start_line( state_ = state::fields; } -template<bool isRequest, class Derived> +template<bool isRequest> void -basic_parser<isRequest, Derived>:: +basic_parser<isRequest>:: parse_fields(char const*& in, char const* last, error_code& ec) { @@ -493,17 +428,16 @@ parse_fields(char const*& in, do_field(f, value, ec); if(ec) return; - impl().on_field_impl(f, name, value, ec); + this->on_field_impl(f, name, value, ec); if(ec) return; in = p; } } -template<bool isRequest, class Derived> -inline +template<bool isRequest> void -basic_parser<isRequest, Derived>:: +basic_parser<isRequest>:: finish_header(error_code& ec, std::true_type) { // RFC 7230 section 3.3 @@ -538,24 +472,25 @@ finish_header(error_code& ec, std::true_type) else { len_ = 0; + len0_ = 0; state_ = state::complete; } - impl().on_header_impl(ec); + ec = {}; + this->on_header_impl(ec); if(ec) return; if(state_ == state::complete) { - impl().on_finish_impl(ec); + this->on_finish_impl(ec); if(ec) return; } } -template<bool isRequest, class Derived> -inline +template<bool isRequest> void -basic_parser<isRequest, Derived>:: +basic_parser<isRequest>:: finish_header(error_code& ec, std::false_type) { // RFC 7230 section 3.3 @@ -600,25 +535,26 @@ finish_header(error_code& ec, std::false_type) state_ = state::body_to_eof0; } - impl().on_header_impl(ec); + ec = {}; + this->on_header_impl(ec); if(ec) return; if(state_ == state::complete) { - impl().on_finish_impl(ec); + this->on_finish_impl(ec); if(ec) return; } } -template<bool isRequest, class Derived> -inline +template<bool isRequest> void -basic_parser<isRequest, Derived>:: +basic_parser<isRequest>:: parse_body(char const*& p, std::size_t n, error_code& ec) { - n = impl().on_body_impl(string_view{p, + ec = {}; + n = this->on_body_impl(string_view{p, beast::detail::clamp(len_, n)}, ec); p += n; len_ -= n; @@ -626,16 +562,15 @@ parse_body(char const*& p, return; if(len_ > 0) return; - impl().on_finish_impl(ec); + this->on_finish_impl(ec); if(ec) return; state_ = state::complete; } -template<bool isRequest, class Derived> -inline +template<bool isRequest> void -basic_parser<isRequest, Derived>:: +basic_parser<isRequest>:: parse_body_to_eof(char const*& p, std::size_t n, error_code& ec) { @@ -645,15 +580,16 @@ parse_body_to_eof(char const*& p, return; } body_limit_ = body_limit_ - n; - n = impl().on_body_impl(string_view{p, n}, ec); + ec = {}; + n = this->on_body_impl(string_view{p, n}, ec); p += n; if(ec) return; } -template<bool isRequest, class Derived> +template<bool isRequest> void -basic_parser<isRequest, Derived>:: +basic_parser<isRequest>:: parse_chunk_header(char const*& p0, std::size_t n, error_code& ec) { @@ -729,7 +665,7 @@ parse_chunk_header(char const*& p0, return; } auto const ext = make_string(start, p); - impl().on_chunk_header_impl(size, ext, ec); + this->on_chunk_header_impl(size, ext, ec); if(ec) return; len_ = size; @@ -772,7 +708,7 @@ parse_chunk_header(char const*& p0, return; } auto const ext = make_string(start, p); - impl().on_chunk_header_impl(0, ext, ec); + this->on_chunk_header_impl(0, ext, ec); if(ec) return; p = eol; @@ -782,20 +718,20 @@ parse_chunk_header(char const*& p0, BOOST_ASSERT(p == eom); p0 = eom; - impl().on_finish_impl(ec); + this->on_finish_impl(ec); if(ec) return; state_ = state::complete; } -template<bool isRequest, class Derived> -inline +template<bool isRequest> void -basic_parser<isRequest, Derived>:: +basic_parser<isRequest>:: parse_chunk_body(char const*& p, std::size_t n, error_code& ec) { - n = impl().on_chunk_body_impl( + ec = {}; + n = this->on_chunk_body_impl( len_, string_view{p, beast::detail::clamp(len_, n)}, ec); p += n; @@ -804,9 +740,9 @@ parse_chunk_body(char const*& p, state_ = state::chunk_header; } -template<bool isRequest, class Derived> +template<bool isRequest> void -basic_parser<isRequest, Derived>:: +basic_parser<isRequest>:: do_field(field f, string_view value, error_code& ec) { @@ -841,7 +777,7 @@ do_field(field f, continue; } } - ec.assign(0, ec.category()); + ec = {}; return; } @@ -870,8 +806,9 @@ do_field(field f, return; } - ec.assign(0, ec.category()); + ec = {}; len_ = v; + len0_ = v; f_ |= flagContentLength; return; } @@ -893,7 +830,7 @@ do_field(field f, return; } - ec.assign(0, ec.category()); + ec = {}; auto const v = token_list{value}; auto const p = std::find_if(v.begin(), v.end(), [&](typename token_list::value_type const& s) @@ -912,14 +849,19 @@ do_field(field f, // Upgrade if(f == field::upgrade) { - ec.assign(0, ec.category()); + ec = {}; f_ |= flagUpgrade; return; } - ec.assign(0, ec.category()); + ec = {}; } +#ifdef BOOST_BEAST_SOURCE +template class http::basic_parser<true>; +template class http::basic_parser<false>; +#endif + } // http } // beast } // boost diff --git a/boost/beast/http/impl/chunk_encode.ipp b/boost/beast/http/impl/chunk_encode.hpp index 51296041f7..0272e3abb3 100644 --- a/boost/beast/http/impl/chunk_encode.ipp +++ b/boost/beast/http/impl/chunk_encode.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2016-2019 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) @@ -7,9 +7,10 @@ // Official repository: https://github.com/boostorg/beast // -#ifndef BOOST_BEAST_HTTP_IMPL_CHUNK_ENCODE_IPP -#define BOOST_BEAST_HTTP_IMPL_CHUNK_ENCODE_IPP +#ifndef BOOST_BEAST_HTTP_IMPL_CHUNK_ENCODE_HPP +#define BOOST_BEAST_HTTP_IMPL_CHUNK_ENCODE_HPP +#include <boost/beast/core/buffer_traits.hpp> #include <boost/beast/core/detail/varint.hpp> #include <boost/beast/http/error.hpp> #include <boost/beast/http/detail/rfc7230.hpp> @@ -24,7 +25,7 @@ chunk_header:: chunk_header(std::size_t size) : view_( size, - boost::asio::const_buffer{nullptr, 0}, + net::const_buffer{nullptr, 0}, chunk_crlf{}) { BOOST_ASSERT(size > 0); @@ -37,7 +38,7 @@ chunk_header( string_view extensions) : view_( size, - boost::asio::const_buffer{ + net::const_buffer{ extensions.data(), extensions.size()}, chunk_crlf{}) { @@ -89,8 +90,8 @@ template<class ConstBufferSequence> chunk_body<ConstBufferSequence>:: chunk_body(ConstBufferSequence const& buffers) : view_( - boost::asio::buffer_size(buffers), - boost::asio::const_buffer{nullptr, 0}, + buffer_bytes(buffers), + net::const_buffer{nullptr, 0}, chunk_crlf{}, buffers, chunk_crlf{}) @@ -103,8 +104,8 @@ chunk_body( ConstBufferSequence const& buffers, string_view extensions) : view_( - boost::asio::buffer_size(buffers), - boost::asio::const_buffer{ + buffer_bytes(buffers), + net::const_buffer{ extensions.data(), extensions.size()}, chunk_crlf{}, buffers, @@ -122,7 +123,7 @@ chunk_body( typename std::decay<ChunkExtensions>::type>>( std::forward<ChunkExtensions>(extensions))) , view_( - boost::asio::buffer_size(buffers), + buffer_bytes(buffers), exts_->str(), chunk_crlf{}, buffers, @@ -141,7 +142,7 @@ chunk_body( typename std::decay<ChunkExtensions>::type>>(allocator, std::forward<ChunkExtensions>(extensions))) , view_( - boost::asio::buffer_size(buffers), + buffer_bytes(buffers), exts_->str(), chunk_crlf{}, buffers, @@ -387,7 +388,7 @@ do_parse(FwdIt it, FwdIt last, error_code& ec) loop: if(it == last) { - ec.assign(0, ec.category()); + ec = {}; return it; } // BWS @@ -680,7 +681,6 @@ insert(string_view name, string_view value) } template<class Allocator> -inline auto basic_chunk_extensions<Allocator>:: begin() const -> @@ -690,7 +690,6 @@ begin() const -> } template<class Allocator> -inline auto basic_chunk_extensions<Allocator>:: end() const -> diff --git a/boost/beast/http/impl/error.hpp b/boost/beast/http/impl/error.hpp new file mode 100644 index 0000000000..b4efaa05ca --- /dev/null +++ b/boost/beast/http/impl/error.hpp @@ -0,0 +1,37 @@ +// +// Copyright (c) 2016-2019 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) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_HTTP_IMPL_ERROR_HPP +#define BOOST_BEAST_HTTP_IMPL_ERROR_HPP + +#include <type_traits> + +namespace boost { +namespace system { +template<> +struct is_error_code_enum<::boost::beast::http::error> +{ + static bool const value = true; +}; +} // system +} // boost + +namespace boost { +namespace beast { +namespace http { + +BOOST_BEAST_DECL +error_code +make_error_code(error ev); + +} // http +} // beast +} // boost + +#endif diff --git a/boost/beast/http/impl/error.ipp b/boost/beast/http/impl/error.ipp index b6320cf4c9..e0167b308e 100644 --- a/boost/beast/http/impl/error.ipp +++ b/boost/beast/http/impl/error.ipp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2016-2019 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) @@ -10,18 +10,10 @@ #ifndef BOOST_BEAST_HTTP_IMPL_ERROR_IPP #define BOOST_BEAST_HTTP_IMPL_ERROR_IPP +#include <boost/beast/http/error.hpp> #include <type_traits> namespace boost { - -namespace system { -template<> -struct is_error_code_enum<beast::http::error> -{ - static bool const value = true; -}; -} // system - namespace beast { namespace http { namespace detail { @@ -63,6 +55,7 @@ public: case error::bad_chunk: return "bad chunk"; case error::bad_chunk_extension: return "bad chunk extension"; case error::bad_obs_fold: return "bad obs-fold"; + case error::stale_parser: return "stale parser"; default: return "beast.http error"; @@ -96,7 +89,6 @@ public: } // detail -inline error_code make_error_code(error ev) { diff --git a/boost/beast/http/impl/field.ipp b/boost/beast/http/impl/field.ipp index b61a0ba8a2..46af6f8552 100644 --- a/boost/beast/http/impl/field.ipp +++ b/boost/beast/http/impl/field.ipp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2016-2019 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) @@ -10,11 +10,10 @@ #ifndef BOOST_BEAST_HTTP_IMPL_FIELD_IPP #define BOOST_BEAST_HTTP_IMPL_FIELD_IPP -#include <boost/beast/core/string.hpp> +#include <boost/beast/http/field.hpp> #include <algorithm> #include <array> -#include <unordered_map> -#include <vector> +#include <cstring> #include <boost/assert.hpp> namespace boost { @@ -28,58 +27,66 @@ struct field_table using array_type = std::array<string_view, 353>; - struct hash + // Strings are converted to lowercase + static + std::uint32_t + digest(string_view s) { - std::size_t - operator()(string_view s) const + std::uint32_t r = 0; + std::size_t n = s.size(); + unsigned char const* p =reinterpret_cast< + unsigned char const*>(s.data()); + while(n >= 4) { - auto const n = s.size(); - return - beast::detail::ascii_tolower(s[0]) * - beast::detail::ascii_tolower(s[n/2]) ^ - beast::detail::ascii_tolower(s[n-1]); // hist[] = 331, 10, max_load_factor = 0.15f + std::uint32_t v; + std::memcpy(&v, p, 4); + r = r * 5 + ( v | 0x20202020 ); + p += 4; + n -= 4; } - }; + while( n > 0 ) + { + r = r * 5 + ( *p | 0x20 ); + ++p; + --n; + } + return r; + } - struct iequal + // This comparison is case-insensitive, and the + // strings must contain only valid http field characters. + static + bool + equals(string_view lhs, string_view rhs) { - // assumes inputs have equal length - bool - operator()( - string_view lhs, - string_view rhs) const + using Int = std::uint32_t; // or std::size_t + auto n = lhs.size(); + if(n != rhs.size()) + return false; + auto p1 = lhs.data(); + auto p2 = rhs.data(); + auto constexpr S = sizeof(Int); + auto constexpr Mask = static_cast<Int>( + 0xDFDFDFDFDFDFDFDF & ~Int{0}); + for(; n >= S; p1 += S, p2 += S, n -= S) { - auto p1 = lhs.data(); - auto p2 = rhs.data(); - auto pend = p1 + lhs.size(); - char a, b; - while(p1 < pend) - { - a = *p1++; - b = *p2++; - if(a != b) - goto slow; - } - return true; - - while(p1 < pend) - { - slow: - if( beast::detail::ascii_tolower(a) != - beast::detail::ascii_tolower(b)) - return false; - a = *p1++; - b = *p2++; - } - return true; + Int v1, v2; + std::memcpy( &v1, p1, S ); + std::memcpy( &v2, p2, S ); + if((v1 ^ v2) & Mask) + return false; } - }; - - using map_type = std::unordered_map< - string_view, field, hash, iequal>; + for(; n; ++p1, ++p2, --n) + if(( *p1 ^ *p2) & 0xDF) + return false; + return true; + } array_type by_name_; - std::vector<map_type> by_size_; + + enum { N = 5155 }; + unsigned char map_[ N ][ 2 ] = {}; + /* From: @@ -442,58 +449,43 @@ struct field_table "Xref" }}) { - // find the longest field length - std::size_t high = 0; - for(auto const& s : by_name_) - if(high < s.size()) - high = s.size(); - // build by_size map - // skip field::unknown - by_size_.resize(high + 1); - for(auto& map : by_size_) - map.max_load_factor(.15f); - for(std::size_t i = 1; - i < by_name_.size(); ++i) + for(std::size_t i = 1, n = 256; i < n; ++i) { - auto const& s = by_name_[i]; - by_size_[s.size()].emplace( - s, static_cast<field>(i)); + auto sv = by_name_[ i ]; + auto h = digest(sv); + auto j = h % N; + BOOST_ASSERT(map_[j][0] == 0); + map_[j][0] = static_cast<unsigned char>(i); } -#if 0 - // This snippet calculates the performance - // of the hash function and map settings + for(std::size_t i = 256, n = by_name_.size(); i < n; ++i) { - std::vector<std::size_t> hist; - for(auto const& map : by_size_) - { - for(std::size_t i = 0; i < map.bucket_count(); ++i) - { - auto const n = map.bucket_size(i); - if(n > 0) - { - if(hist.size() < n) - hist.resize(n); - ++hist[n-1]; - } - } - } + auto sv = by_name_[i]; + auto h = digest(sv); + auto j = h % N; + BOOST_ASSERT(map_[j][1] == 0); + map_[j][1] = static_cast<unsigned char>(i - 255); } -#endif } field string_to_field(string_view s) const { - if(s.size() >= by_size_.size()) + auto h = digest(s); + auto j = h % N; + int i = map_[j][0]; + string_view s2 = by_name_[i]; + if(i != 0 && equals(s, s2)) + return static_cast<field>(i); + i = map_[j][1]; + if(i == 0) return field::unknown; - auto const& map = by_size_[s.size()]; - if(map.empty()) - return field::unknown; - auto it = map.find(s); - if(it == map.end()) - return field::unknown; - return it->second; + i += 255; + s2 = by_name_[i]; + + if(equals(s, s2)) + return static_cast<field>(i); + return field::unknown; } // @@ -522,7 +514,7 @@ struct field_table } }; -inline +BOOST_BEAST_DECL field_table const& get_field_table() { @@ -530,7 +522,7 @@ get_field_table() return tab; } -template<class = void> +BOOST_BEAST_DECL string_view to_string(field f) { @@ -541,14 +533,12 @@ to_string(field f) } // detail -inline string_view to_string(field f) { return detail::to_string(f); } -inline field string_to_field(string_view s) { diff --git a/boost/beast/http/impl/fields.ipp b/boost/beast/http/impl/fields.hpp index f34a8e7471..9616af829c 100644 --- a/boost/beast/http/impl/fields.ipp +++ b/boost/beast/http/impl/fields.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2016-2019 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) @@ -7,13 +7,14 @@ // Official repository: https://github.com/boostorg/beast // -#ifndef BOOST_BEAST_HTTP_IMPL_FIELDS_IPP -#define BOOST_BEAST_HTTP_IMPL_FIELDS_IPP +#ifndef BOOST_BEAST_HTTP_IMPL_FIELDS_HPP +#define BOOST_BEAST_HTTP_IMPL_FIELDS_HPP #include <boost/beast/core/buffers_cat.hpp> #include <boost/beast/core/string.hpp> #include <boost/beast/core/static_string.hpp> #include <boost/beast/core/detail/buffers_ref.hpp> +#include <boost/beast/core/detail/clamp.hpp> #include <boost/beast/http/verb.hpp> #include <boost/beast/http/rfc7230.hpp> #include <boost/beast/http/status.hpp> @@ -44,7 +45,7 @@ public: { iter_type it_; - using value_type = boost::asio::const_buffer; + using value_type = net::const_buffer; using pointer = value_type const*; using reference = value_type const; using difference_type = std::ptrdiff_t; @@ -144,9 +145,9 @@ public: }; using view_type = buffers_cat_view< - boost::asio::const_buffer, - boost::asio::const_buffer, - boost::asio::const_buffer, + net::const_buffer, + net::const_buffer, + net::const_buffer, field_range, chunk_crlf>; @@ -179,9 +180,9 @@ writer(basic_fields const& f) : f_(f) { view_.emplace( - boost::asio::const_buffer{nullptr, 0}, - boost::asio::const_buffer{nullptr, 0}, - boost::asio::const_buffer{nullptr, 0}, + net::const_buffer{nullptr, 0}, + net::const_buffer{nullptr, 0}, + net::const_buffer{nullptr, 0}, field_range(f_.list_.begin(), f_.list_.end()), chunk_crlf()); } @@ -219,11 +220,11 @@ writer(basic_fields const& f, buf_[10]= '\n'; view_.emplace( - boost::asio::const_buffer{sv.data(), sv.size()}, - boost::asio::const_buffer{ + net::const_buffer{sv.data(), sv.size()}, + net::const_buffer{ f_.target_or_reason_.data(), f_.target_or_reason_.size()}, - boost::asio::const_buffer{buf_, 11}, + net::const_buffer{buf_, 11}, field_range(f_.list_.begin(), f_.list_.end()), chunk_crlf()); } @@ -261,9 +262,9 @@ writer(basic_fields const& f, sv = obsolete_reason(static_cast<status>(code)); view_.emplace( - boost::asio::const_buffer{buf_, 13}, - boost::asio::const_buffer{sv.data(), sv.size()}, - boost::asio::const_buffer{"\r\n", 2}, + net::const_buffer{buf_, 13}, + net::const_buffer{sv.data(), sv.size()}, + net::const_buffer{"\r\n", 2}, field_range(f_.list_.begin(), f_.list_.end()), chunk_crlf{}); } @@ -282,12 +283,12 @@ data() const } template<class Allocator> -boost::asio::const_buffer +net::const_buffer basic_fields<Allocator>:: value_type:: buffer() const { - return boost::asio::const_buffer{data(), + return net::const_buffer{data(), static_cast<std::size_t>(off_) + len_ + 2}; } @@ -1018,7 +1019,8 @@ set_chunked_impl(bool value) itt = next; } static_string<max_static_buffer> buf; - if(it->value().size() <= buf.size() + 9) + if(! beast::detail::sum_exceeds( + it->value().size(), 9u, buf.max_size())) { buf.append(it->value().data(), it->value().size()); buf.append(", chunked", 9); @@ -1048,6 +1050,7 @@ set_chunked_impl(bool value) // filter "chunked" if(it == end()) return; +#ifndef BOOST_NO_EXCEPTIONS try { static_string<max_static_buffer> buf; @@ -1062,6 +1065,7 @@ set_chunked_impl(bool value) erase(field::transfer_encoding); } catch(std::length_error const&) +#endif { #ifdef BOOST_BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437 @@ -1108,6 +1112,7 @@ set_keep_alive_impl( { // VFALCO What about Proxy-Connection ? auto const value = (*this)[field::connection]; +#ifndef BOOST_NO_EXCEPTIONS try { static_string<max_static_buffer> buf; @@ -1119,6 +1124,7 @@ set_keep_alive_impl( set(field::connection, buf); } catch(std::length_error const&) +#endif { #ifdef BOOST_BEAST_HTTP_NO_FIELDS_BASIC_STRING_ALLOCATOR // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437 @@ -1168,7 +1174,7 @@ new_element(field name, auto const p = alloc_traits::allocate(a, (sizeof(element) + off + len + 2 + sizeof(align_type) - 1) / sizeof(align_type)); - return *(new(p) element(name, sname, value)); + return *(::new(p) element(name, sname, value)); } template<class Allocator> diff --git a/boost/beast/http/impl/file_body_win32.ipp b/boost/beast/http/impl/file_body_win32.hpp index 6357cf4983..fc74c49772 100644 --- a/boost/beast/http/impl/file_body_win32.ipp +++ b/boost/beast/http/impl/file_body_win32.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2016-2019 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) @@ -7,22 +7,18 @@ // Official repository: https://github.com/boostorg/beast // -#ifndef BOOST_BEAST_HTTP_IMPL_FILE_BODY_WIN32_IPP -#define BOOST_BEAST_HTTP_IMPL_FILE_BODY_WIN32_IPP +#ifndef BOOST_BEAST_HTTP_IMPL_FILE_BODY_WIN32_HPP +#define BOOST_BEAST_HTTP_IMPL_FILE_BODY_WIN32_HPP #if BOOST_BEAST_USE_WIN32_FILE +#include <boost/beast/core/async_base.hpp> #include <boost/beast/core/bind_handler.hpp> -#include <boost/beast/core/type_traits.hpp> +#include <boost/beast/core/buffers_range.hpp> #include <boost/beast/core/detail/clamp.hpp> #include <boost/beast/http/serializer.hpp> -#include <boost/asio/associated_allocator.hpp> -#include <boost/asio/associated_executor.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/basic_stream_socket.hpp> -#include <boost/asio/executor_work_guard.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> @@ -36,7 +32,7 @@ namespace beast { namespace http { namespace detail { -template<class, class, bool, class> +template<class, class, bool, class, class> class write_some_win32_op; } // detail @@ -56,14 +52,15 @@ struct basic_file_body<file_win32> friend class reader; friend struct basic_file_body<file_win32>; - template<class, class, bool, class> + template<class, class, bool, class, class> friend class detail::write_some_win32_op; template< - class Protocol, bool isRequest, class Fields> + class Protocol, class Executor, + bool isRequest, class Fields> friend std::size_t write_some( - boost::asio::basic_stream_socket<Protocol>& sock, + net::basic_stream_socket<Protocol, Executor>& sock, serializer<isRequest, basic_file_body<file_win32>, Fields>& sr, error_code& ec); @@ -105,14 +102,15 @@ struct basic_file_body<file_win32> class writer { - template<class, class, bool, class> + template<class, class, bool, class, class> friend class detail::write_some_win32_op; template< - class Protocol, bool isRequest, class Fields> + class Protocol, class Executor, + bool isRequest, class Fields> friend std::size_t write_some( - boost::asio::basic_stream_socket<Protocol>& sock, + net::basic_stream_socket<Protocol, Executor>& sock, serializer<isRequest, basic_file_body<file_win32>, Fields>& sr, error_code& ec); @@ -123,7 +121,7 @@ struct basic_file_body<file_win32> public: using const_buffers_type = - boost::asio::const_buffer; + net::const_buffer; template<bool isRequest, class Fields> writer(header<isRequest, Fields>&, value_type& b) @@ -145,7 +143,7 @@ struct basic_file_body<file_win32> beast::detail::clamp(body_.last_ - pos_)); if(n == 0) { - ec.assign(0, ec.category()); + ec = {}; return boost::none; } auto const nread = body_.file_.read(buf_, n, ec); @@ -153,7 +151,7 @@ struct basic_file_body<file_win32> return boost::none; BOOST_ASSERT(nread != 0); pos_ += nread; - ec.assign(0, ec.category()); + ec = {}; return {{ {buf_, nread}, // buffer to return. pos_ < body_.last_}}; // `true` if there are more buffers. @@ -182,7 +180,7 @@ struct basic_file_body<file_win32> // VFALCO We could reserve space in the file boost::ignore_unused(content_length); BOOST_ASSERT(body_.file_.is_open()); - ec.assign(0, ec.category()); + ec = {}; } template<class ConstBufferSequence> @@ -191,21 +189,21 @@ struct basic_file_body<file_win32> error_code& ec) { std::size_t nwritten = 0; - for(auto buffer : beast::detail::buffers_range(buffers)) + for(auto buffer : beast::buffers_range_ref(buffers)) { nwritten += body_.file_.write( buffer.data(), buffer.size(), ec); if(ec) return nwritten; } - ec.assign(0, ec.category()); + ec = {}; return nwritten; } void finish(error_code& ec) { - ec.assign(0, ec.category()); + ec = {}; } }; @@ -280,7 +278,6 @@ reset(file_win32&& file, error_code& ec) namespace detail { template<class Unsigned> -inline boost::winapi::DWORD_ lowPart(Unsigned n) { @@ -290,7 +287,6 @@ lowPart(Unsigned n) } template<class Unsigned> -inline boost::winapi::DWORD_ highPart(Unsigned n, std::true_type) { @@ -300,7 +296,6 @@ highPart(Unsigned n, std::true_type) } template<class Unsigned> -inline boost::winapi::DWORD_ highPart(Unsigned, std::false_type) { @@ -308,7 +303,6 @@ highPart(Unsigned, std::false_type) } template<class Unsigned> -inline boost::winapi::DWORD_ highPart(Unsigned n) { @@ -333,165 +327,144 @@ public: #if BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR template< - class Protocol, class Handler, - bool isRequest, class Fields> + class Protocol, class Executor, + bool isRequest, class Fields, + class Handler> class write_some_win32_op + : public beast::async_base<Handler, Executor> { - boost::asio::basic_stream_socket<Protocol>& sock_; - boost::asio::executor_work_guard<decltype(std::declval< - boost::asio::basic_stream_socket<Protocol>&>().get_executor())> wg_; + net::basic_stream_socket< + Protocol, Executor>& sock_; serializer<isRequest, basic_file_body<file_win32>, Fields>& sr_; std::size_t bytes_transferred_ = 0; - Handler h_; bool header_ = false; public: - write_some_win32_op(write_some_win32_op&&) = default; - write_some_win32_op(write_some_win32_op const&) = delete; - - template<class DeducedHandler> + template<class Handler_> write_some_win32_op( - DeducedHandler&& h, - boost::asio::basic_stream_socket<Protocol>& s, + Handler_&& h, + net::basic_stream_socket< + Protocol, Executor>& s, serializer<isRequest, basic_file_body<file_win32>,Fields>& sr) - : sock_(s) - , wg_(sock_.get_executor()) + : async_base< + Handler, Executor>( + std::forward<Handler_>(h), + s.get_executor()) + , sock_(s) , sr_(sr) - , h_(std::forward<DeducedHandler>(h)) - { - } - - using allocator_type = - boost::asio::associated_allocator_t<Handler>; - - allocator_type - get_allocator() const noexcept { - return (boost::asio::get_associated_allocator)(h_); + (*this)(); } - using executor_type = - boost::asio::associated_executor_t<Handler, decltype(std::declval< - boost::asio::basic_stream_socket<Protocol>&>().get_executor())>; - - executor_type - get_executor() const noexcept + void + operator()() { - return (boost::asio::get_associated_executor)( - h_, sock_.get_executor()); + if(! sr_.is_header_done()) + { + header_ = true; + sr_.split(true); + return detail::async_write_some_impl( + sock_, sr_, std::move(*this)); + } + if(sr_.get().chunked()) + { + return detail::async_write_some_impl( + sock_, sr_, std::move(*this)); + } + 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>)(w.body_.last_ - w.pos_, sr_.limit()), + (std::numeric_limits<boost::winapi::DWORD_>::max)())); + net::windows::overlapped_ptr overlapped{ + sock_.get_executor(), 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(w.pos_); + ov.OffsetHigh = highPart(w.pos_); + auto const bSuccess = ::TransmitFile( + sock_.native_handle(), + sr_.get().body().file_.native_handle(), + nNumberOfBytesToWrite, + 0, + overlapped.get(), + nullptr, + 0); + 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>(dwError), + system_category()}, 0); + return; + } + overlapped.release(); } void - operator()(); - - void operator()( error_code ec, - std::size_t bytes_transferred = 0); - - friend - bool asio_handler_is_continuation(write_some_win32_op* op) - { - using boost::asio::asio_handler_is_continuation; - return asio_handler_is_continuation( - std::addressof(op->h_)); - } - - template<class Function> - friend - void asio_handler_invoke(Function&& f, write_some_win32_op* op) + std::size_t bytes_transferred = 0) { - using boost::asio::asio_handler_invoke; - asio_handler_invoke(f, std::addressof(op->h_)); + bytes_transferred_ += bytes_transferred; + if(! ec) + { + if(header_) + { + header_ = false; + return (*this)(); + } + 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); + BOOST_ASSERT(sr_.is_done()); + } + } + this->complete_now(ec, bytes_transferred_); } }; -template< - class Protocol, class Handler, - bool isRequest, class Fields> -void -write_some_win32_op< - Protocol, Handler, isRequest, Fields>:: -operator()() +struct run_write_some_win32_op { - if(! sr_.is_header_done()) - { - header_ = true; - sr_.split(true); - return detail::async_write_some_impl( - sock_, sr_, std::move(*this)); - } - if(sr_.get().chunked()) - { - return detail::async_write_some_impl( - sock_, sr_, std::move(*this)); - } - 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>)(w.body_.last_ - w.pos_, sr_.limit()), - (std::numeric_limits<boost::winapi::DWORD_>::max)())); - boost::asio::windows::overlapped_ptr overlapped{ - 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(w.pos_); - ov.OffsetHigh = highPart(w.pos_); - auto const bSuccess = ::TransmitFile( - sock_.native_handle(), - sr_.get().body().file_.native_handle(), - nNumberOfBytesToWrite, - 0, - overlapped.get(), - nullptr, - 0); - 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>(dwError), - system_category()}, 0); - return; - } - overlapped.release(); -} - -template< - class Protocol, class Handler, - bool isRequest, class Fields> -void -write_some_win32_op< - Protocol, Handler, isRequest, Fields>:: -operator()( - error_code ec, std::size_t bytes_transferred) -{ - bytes_transferred_ += bytes_transferred; - if(! ec) + template< + class Protocol, class Executor, + bool isRequest, class Fields, + class WriteHandler> + void + operator()( + WriteHandler&& h, + net::basic_stream_socket< + Protocol, Executor>* s, + serializer<isRequest, + basic_file_body<file_win32>, Fields>* sr) { - if(header_) - { - header_ = false; - return (*this)(); - } - 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); - BOOST_ASSERT(sr_.is_done()); - } + // If you get an error on the following line it means + // that your handler does not meet the documented type + // requirements for the handler. + + static_assert( + beast::detail::is_invocable<WriteHandler, + void(error_code, std::size_t)>::value, + "WriteHandler type requirements not met"); + + write_some_win32_op< + Protocol, Executor, + isRequest, Fields, + typename std::decay<WriteHandler>::type>( + std::forward<WriteHandler>(h), *s, *sr); } - h_(ec, bytes_transferred_); -} +}; #endif @@ -499,10 +472,13 @@ operator()( //------------------------------------------------------------------------------ -template<class Protocol, bool isRequest, class Fields> +template< + class Protocol, class Executor, + bool isRequest, class Fields> std::size_t write_some( - boost::asio::basic_stream_socket<Protocol>& sock, + net::basic_stream_socket< + Protocol, Executor>& sock, serializer<isRequest, basic_file_body<file_win32>, Fields>& sr, error_code& ec) @@ -552,7 +528,7 @@ write_some( BOOST_ASSERT(w.pos_ <= w.body_.last_); if(w.pos_ < w.body_.last_) { - ec.assign(0, ec.category()); + ec = {}; } else { @@ -566,26 +542,24 @@ write_some( #if BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR template< - class Protocol, + class Protocol, class Executor, bool isRequest, class Fields, class WriteHandler> -BOOST_ASIO_INITFN_RESULT_TYPE( - WriteHandler, void(error_code, std::size_t)) +BOOST_BEAST_ASYNC_RESULT2(WriteHandler) async_write_some( - boost::asio::basic_stream_socket<Protocol>& sock, + net::basic_stream_socket< + Protocol, Executor>& sock, serializer<isRequest, basic_file_body<file_win32>, Fields>& sr, WriteHandler&& 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>{ - std::move(init.completion_handler), sock, sr}(); - return init.result.get(); +{ + return net::async_initiate< + WriteHandler, + void(error_code, std::size_t)>( + detail::run_write_some_win32_op{}, + handler, + &sock, + &sr); } #endif diff --git a/boost/beast/http/impl/message.ipp b/boost/beast/http/impl/message.hpp index a2a10402f9..805d01f09a 100644 --- a/boost/beast/http/impl/message.ipp +++ b/boost/beast/http/impl/message.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2016-2019 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) @@ -7,8 +7,8 @@ // Official repository: https://github.com/boostorg/beast // -#ifndef BOOST_BEAST_HTTP_IMPL_MESSAGE_IPP -#define BOOST_BEAST_HTTP_IMPL_MESSAGE_IPP +#ifndef BOOST_BEAST_HTTP_IMPL_MESSAGE_HPP +#define BOOST_BEAST_HTTP_IMPL_MESSAGE_HPP #include <boost/beast/core/error.hpp> #include <boost/beast/core/detail/type_traits.hpp> @@ -30,7 +30,6 @@ header(Arg1&& arg1, ArgN&&... argn) } template<class Fields> -inline verb header<true, Fields>:: method() const @@ -73,7 +72,6 @@ method_string(string_view s) } template<class Fields> -inline string_view header<true, Fields>:: target() const @@ -82,7 +80,6 @@ target() const } template<class Fields> -inline void header<true, Fields>:: target(string_view s) @@ -116,7 +113,6 @@ header(Arg1&& arg1, ArgN&&... argn) } template<class Fields> -inline status header<false, Fields>:: result() const @@ -126,7 +122,6 @@ result() const } template<class Fields> -inline void header<false, Fields>:: result(status v) @@ -135,7 +130,6 @@ result(status v) } template<class Fields> -inline void header<false, Fields>:: result(unsigned v) @@ -148,7 +142,6 @@ result(unsigned v) } template<class Fields> -inline unsigned header<false, Fields>:: result_int() const @@ -168,7 +161,6 @@ reason() const } template<class Fields> -inline void header<false, Fields>:: reason(string_view s) @@ -295,7 +287,7 @@ message(std::piecewise_construct_t, std::tuple<BodyArgs...> body_args) : message(std::piecewise_construct, body_args, - beast::detail::make_index_sequence< + mp11::make_index_sequence< sizeof...(BodyArgs)>{}) { } @@ -309,9 +301,9 @@ message(std::piecewise_construct_t, : message(std::piecewise_construct, body_args, fields_args, - beast::detail::make_index_sequence< + mp11::make_index_sequence< sizeof...(BodyArgs)>{}, - beast::detail::make_index_sequence< + mp11::make_index_sequence< sizeof...(FieldsArgs)>{}) { } diff --git a/boost/beast/http/impl/parser.ipp b/boost/beast/http/impl/parser.hpp index 45bef1c6ac..066ac5fea1 100644 --- a/boost/beast/http/impl/parser.ipp +++ b/boost/beast/http/impl/parser.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2016-2019 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) @@ -7,8 +7,8 @@ // Official repository: https://github.com/boostorg/beast // -#ifndef BOOST_BEAST_HTTP_IMPL_PARSER_IPP -#define BOOST_BEAST_HTTP_IMPL_PARSER_IPP +#ifndef BOOST_BEAST_HTTP_IMPL_PARSER_HPP +#define BOOST_BEAST_HTTP_IMPL_PARSER_HPP #include <boost/throw_exception.hpp> #include <stdexcept> @@ -42,7 +42,7 @@ parser<isRequest, Body, Allocator>:: parser( parser<isRequest, OtherBody, Allocator>&& other, Args&&... args) - : base_type(std::move(other)) + : basic_parser<isRequest>(std::move(other)) , m_(other.release(), std::forward<Args>(args)...) , rd_(m_.base(), m_.body()) { diff --git a/boost/beast/http/impl/read.hpp b/boost/beast/http/impl/read.hpp new file mode 100644 index 0000000000..faea67eb25 --- /dev/null +++ b/boost/beast/http/impl/read.hpp @@ -0,0 +1,559 @@ +// +// Copyright (c) 2016-2019 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) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_HTTP_IMPL_READ_HPP +#define BOOST_BEAST_HTTP_IMPL_READ_HPP + +#include <boost/beast/http/type_traits.hpp> +#include <boost/beast/http/error.hpp> +#include <boost/beast/http/parser.hpp> +#include <boost/beast/http/read.hpp> +#include <boost/beast/core/async_base.hpp> +#include <boost/beast/core/stream_traits.hpp> +#include <boost/beast/core/detail/read.hpp> +#include <boost/asio/error.hpp> + +namespace boost { +namespace beast { +namespace http { + +namespace detail { + +// The default maximum number of bytes to transfer in a single operation. +std::size_t constexpr default_max_transfer_size = 65536; + +template< + class DynamicBuffer, + bool isRequest, + class Condition> +std::size_t +parse_until( + DynamicBuffer& buffer, + basic_parser<isRequest>& parser, + error_code& ec, + Condition cond) +{ + if(ec == net::error::eof) + { + if(parser.got_some()) + { + // Caller sees EOF on next read + ec = {}; + parser.put_eof(ec); + BOOST_ASSERT(ec || parser.is_done()); + } + else + { + ec = error::end_of_stream; + } + return 0; + } + if(ec) + { + // Upgrade the error if we have a partial message. + // This causes SSL short reads (and every other error) + // to be converted into something else, allowing the + // caller to distinguish an SSL short read which + // represents a safe connection closure, versus + // a closure with data loss. + if(parser.got_some() && ! parser.is_done()) + ec = error::partial_message; + return 0; + } + if(parser.is_done()) + return 0; + if(buffer.size() > 0) + { + auto const bytes_used = + parser.put(buffer.data(), ec); + // total = total + bytes_used; // VFALCO Can't do this in a condition + buffer.consume(bytes_used); + if(ec == http::error::need_more) + { + if(buffer.size() >= buffer.max_size()) + { + ec = http::error::buffer_overflow; + return 0; + } + ec = {}; + } + else if(ec || cond()) + { + return 0; + } + } + return default_max_transfer_size; +} + +// predicate is true on any forward parser progress +template<bool isRequest> +struct read_some_condition +{ + basic_parser<isRequest>& parser; + + template<class DynamicBuffer> + std::size_t + operator()(error_code& ec, std::size_t, + DynamicBuffer& buffer) + { + return detail::parse_until( + buffer, parser, ec, + [] + { + return true; + }); + } +}; + +// predicate is true when parser header is complete +template<bool isRequest> +struct read_header_condition +{ + basic_parser<isRequest>& parser; + + template<class DynamicBuffer> + std::size_t + operator()(error_code& ec, std::size_t, + DynamicBuffer& buffer) + { + return detail::parse_until( + buffer, parser, ec, + [this] + { + return parser.is_header_done(); + }); + } +}; + +// predicate is true when parser message is complete +template<bool isRequest> +struct read_all_condition +{ + basic_parser<isRequest>& parser; + + template<class DynamicBuffer> + std::size_t + operator()(error_code& ec, std::size_t, + DynamicBuffer& buffer) + { + return detail::parse_until( + buffer, parser, ec, + [this] + { + return parser.is_done(); + }); + } +}; + +//------------------------------------------------------------------------------ + +template< + class Stream, class DynamicBuffer, + bool isRequest, class Body, class Allocator, + class Handler> +class read_msg_op + : public beast::stable_async_base< + Handler, beast::executor_type<Stream>> + , public net::coroutine +{ + using parser_type = + parser<isRequest, Body, Allocator>; + + using message_type = + typename parser_type::value_type; + + struct data + { + Stream& s; + message_type& m; + parser_type p; + + data( + Stream& s_, + message_type& m_) + : s(s_) + , m(m_) + , p(std::move(m)) + { + } + }; + + data& d_; + +public: + template<class Handler_> + read_msg_op( + Handler_&& h, + Stream& s, + DynamicBuffer& b, + message_type& m) + : stable_async_base< + Handler, beast::executor_type<Stream>>( + std::forward<Handler_>(h), s.get_executor()) + , d_(beast::allocate_stable<data>( + *this, s, m)) + { + http::async_read(d_.s, b, d_.p, std::move(*this)); + } + + void + operator()( + error_code ec, + std::size_t bytes_transferred) + { + if(! ec) + d_.m = d_.p.release(); + this->complete_now(ec, bytes_transferred); + } +}; + +struct run_read_msg_op +{ + template< + class ReadHandler, + class AsyncReadStream, + class DynamicBuffer, + bool isRequest, class Body, class Allocator> + void + operator()( + ReadHandler&& h, + AsyncReadStream* s, + DynamicBuffer* b, + message<isRequest, Body, + basic_fields<Allocator>>* m) + { + // If you get an error on the following line it means + // that your handler does not meet the documented type + // requirements for the handler. + + static_assert( + beast::detail::is_invocable<ReadHandler, + void(error_code, std::size_t)>::value, + "ReadHandler type requirements not met"); + + read_msg_op< + AsyncReadStream, + DynamicBuffer, + isRequest, Body, Allocator, + typename std::decay<ReadHandler>::type>( + std::forward<ReadHandler>(h), *s, *b, *m); + } +}; + +} // detail + +//------------------------------------------------------------------------------ + +template< + class SyncReadStream, + class DynamicBuffer, + bool isRequest> +std::size_t +read_some( + SyncReadStream& stream, + DynamicBuffer& buffer, + basic_parser<isRequest>& parser) +{ + static_assert( + is_sync_read_stream<SyncReadStream>::value, + "SyncReadStream type requirements not met"); + static_assert( + net::is_dynamic_buffer<DynamicBuffer>::value, + "DynamicBuffer type requirements not met"); + error_code ec; + auto const bytes_transferred = + http::read_some(stream, buffer, parser, ec); + if(ec) + BOOST_THROW_EXCEPTION(system_error{ec}); + return bytes_transferred; +} + +template< + class SyncReadStream, + class DynamicBuffer, + bool isRequest> +std::size_t +read_some( + SyncReadStream& stream, + DynamicBuffer& buffer, + basic_parser<isRequest>& parser, + error_code& ec) +{ + static_assert( + is_sync_read_stream<SyncReadStream>::value, + "SyncReadStream type requirements not met"); + static_assert( + net::is_dynamic_buffer<DynamicBuffer>::value, + "DynamicBuffer type requirements not met"); + return beast::detail::read(stream, buffer, + detail::read_some_condition< + isRequest>{parser}, ec); +} + +template< + class AsyncReadStream, + class DynamicBuffer, + bool isRequest, + class ReadHandler> +BOOST_BEAST_ASYNC_RESULT2(ReadHandler) +async_read_some( + AsyncReadStream& stream, + DynamicBuffer& buffer, + basic_parser<isRequest>& parser, + ReadHandler&& handler) +{ + return beast::detail::async_read( + stream, + buffer, + detail::read_some_condition< + isRequest>{parser}, + std::forward<ReadHandler>(handler)); +} + +//------------------------------------------------------------------------------ + +template< + class SyncReadStream, + class DynamicBuffer, + bool isRequest> +std::size_t +read_header( + SyncReadStream& stream, + DynamicBuffer& buffer, + basic_parser<isRequest>& parser) +{ + static_assert( + is_sync_read_stream<SyncReadStream>::value, + "SyncReadStream type requirements not met"); + static_assert( + net::is_dynamic_buffer<DynamicBuffer>::value, + "DynamicBuffer type requirements not met"); + error_code ec; + auto const bytes_transferred = + http::read_header(stream, buffer, parser, ec); + if(ec) + BOOST_THROW_EXCEPTION(system_error{ec}); + return bytes_transferred; +} + +template< + class SyncReadStream, + class DynamicBuffer, + bool isRequest> +std::size_t +read_header( + SyncReadStream& stream, + DynamicBuffer& buffer, + basic_parser<isRequest>& parser, + error_code& ec) +{ + static_assert( + is_sync_read_stream<SyncReadStream>::value, + "SyncReadStream type requirements not met"); + static_assert( + net::is_dynamic_buffer<DynamicBuffer>::value, + "DynamicBuffer type requirements not met"); + parser.eager(false); + return beast::detail::read(stream, buffer, + detail::read_header_condition< + isRequest>{parser}, ec); +} + +template< + class AsyncReadStream, + class DynamicBuffer, + bool isRequest, + class ReadHandler> +BOOST_BEAST_ASYNC_RESULT2(ReadHandler) +async_read_header( + AsyncReadStream& stream, + DynamicBuffer& buffer, + basic_parser<isRequest>& parser, + ReadHandler&& handler) +{ + parser.eager(false); + return beast::detail::async_read( + stream, + buffer, + detail::read_header_condition< + isRequest>{parser}, + std::forward<ReadHandler>(handler)); +} + +//------------------------------------------------------------------------------ + +template< + class SyncReadStream, + class DynamicBuffer, + bool isRequest> +std::size_t +read( + SyncReadStream& stream, + DynamicBuffer& buffer, + basic_parser<isRequest>& parser) +{ + static_assert( + is_sync_read_stream<SyncReadStream>::value, + "SyncReadStream type requirements not met"); + static_assert( + net::is_dynamic_buffer<DynamicBuffer>::value, + "DynamicBuffer type requirements not met"); + error_code ec; + auto const bytes_transferred = + http::read(stream, buffer, parser, ec); + if(ec) + BOOST_THROW_EXCEPTION(system_error{ec}); + return bytes_transferred; +} + +template< + class SyncReadStream, + class DynamicBuffer, + bool isRequest> +std::size_t +read( + SyncReadStream& stream, + DynamicBuffer& buffer, + basic_parser<isRequest>& parser, + error_code& ec) +{ + static_assert( + is_sync_read_stream<SyncReadStream>::value, + "SyncReadStream type requirements not met"); + static_assert( + net::is_dynamic_buffer<DynamicBuffer>::value, + "DynamicBuffer type requirements not met"); + parser.eager(true); + return beast::detail::read(stream, buffer, + detail::read_all_condition< + isRequest>{parser}, ec); +} + +template< + class AsyncReadStream, + class DynamicBuffer, + bool isRequest, + class ReadHandler> +BOOST_BEAST_ASYNC_RESULT2(ReadHandler) +async_read( + AsyncReadStream& stream, + DynamicBuffer& buffer, + basic_parser<isRequest>& parser, + ReadHandler&& handler) +{ + static_assert( + is_async_read_stream<AsyncReadStream>::value, + "AsyncReadStream type requirements not met"); + static_assert( + net::is_dynamic_buffer<DynamicBuffer>::value, + "DynamicBuffer type requirements not met"); + parser.eager(true); + return beast::detail::async_read( + stream, + buffer, + detail::read_all_condition< + isRequest>{parser}, + std::forward<ReadHandler>(handler)); +} + +//------------------------------------------------------------------------------ + +template< + class SyncReadStream, + class DynamicBuffer, + bool isRequest, class Body, class Allocator> +std::size_t +read( + SyncReadStream& stream, + DynamicBuffer& buffer, + message<isRequest, Body, basic_fields<Allocator>>& msg) +{ + static_assert( + is_sync_read_stream<SyncReadStream>::value, + "SyncReadStream type requirements not met"); + static_assert( + net::is_dynamic_buffer<DynamicBuffer>::value, + "DynamicBuffer type requirements not met"); + static_assert(is_body<Body>::value, + "Body type requirements not met"); + static_assert(is_body_reader<Body>::value, + "BodyReader type requirements not met"); + error_code ec; + auto const bytes_transferred = + http::read(stream, buffer, msg, ec); + if(ec) + BOOST_THROW_EXCEPTION(system_error{ec}); + return bytes_transferred; +} + +template< + class SyncReadStream, + class DynamicBuffer, + bool isRequest, class Body, class Allocator> +std::size_t +read( + SyncReadStream& stream, + DynamicBuffer& buffer, + message<isRequest, Body, basic_fields<Allocator>>& msg, + error_code& ec) +{ + static_assert( + is_sync_read_stream<SyncReadStream>::value, + "SyncReadStream type requirements not met"); + static_assert( + net::is_dynamic_buffer<DynamicBuffer>::value, + "DynamicBuffer type requirements not met"); + static_assert(is_body<Body>::value, + "Body type requirements not met"); + static_assert(is_body_reader<Body>::value, + "BodyReader type requirements not met"); + parser<isRequest, Body, Allocator> p(std::move(msg)); + p.eager(true); + auto const bytes_transferred = + http::read(stream, buffer, p, ec); + if(ec) + return bytes_transferred; + msg = p.release(); + return bytes_transferred; +} + +template< + class AsyncReadStream, + class DynamicBuffer, + bool isRequest, class Body, class Allocator, + class ReadHandler> +BOOST_BEAST_ASYNC_RESULT2(ReadHandler) +async_read( + AsyncReadStream& stream, + DynamicBuffer& buffer, + message<isRequest, Body, basic_fields<Allocator>>& msg, + ReadHandler&& handler) +{ + static_assert( + is_async_read_stream<AsyncReadStream>::value, + "AsyncReadStream type requirements not met"); + static_assert( + net::is_dynamic_buffer<DynamicBuffer>::value, + "DynamicBuffer type requirements not met"); + static_assert(is_body<Body>::value, + "Body type requirements not met"); + static_assert(is_body_reader<Body>::value, + "BodyReader type requirements not met"); + return net::async_initiate< + ReadHandler, + void(error_code, std::size_t)>( + detail::run_read_msg_op{}, + handler, &stream, &buffer, &msg); +} + +} // http +} // beast +} // boost + +#endif diff --git a/boost/beast/http/impl/read.ipp b/boost/beast/http/impl/read.ipp deleted file mode 100644 index 42ce175d8c..0000000000 --- a/boost/beast/http/impl/read.ipp +++ /dev/null @@ -1,857 +0,0 @@ -// -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/boostorg/beast -// - -#ifndef BOOST_BEAST_HTTP_IMPL_READ_IPP_HPP -#define BOOST_BEAST_HTTP_IMPL_READ_IPP_HPP - -#include <boost/beast/http/type_traits.hpp> -#include <boost/beast/http/error.hpp> -#include <boost/beast/http/parser.hpp> -#include <boost/beast/http/read.hpp> -#include <boost/beast/core/bind_handler.hpp> -#include <boost/beast/core/handler_ptr.hpp> -#include <boost/beast/core/read_size.hpp> -#include <boost/beast/core/type_traits.hpp> -#include <boost/beast/core/detail/buffer.hpp> -#include <boost/asio/associated_allocator.hpp> -#include <boost/asio/associated_executor.hpp> -#include <boost/asio/coroutine.hpp> -#include <boost/asio/error.hpp> -#include <boost/asio/executor_work_guard.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> -#include <boost/optional.hpp> -#include <boost/throw_exception.hpp> - -namespace boost { -namespace beast { -namespace http { - -namespace detail { - -//------------------------------------------------------------------------------ - -template<class Stream, class DynamicBuffer, - bool isRequest, class Derived, class Handler> -class read_some_op - : public boost::asio::coroutine -{ - Stream& s_; - boost::asio::executor_work_guard<decltype( - std::declval<Stream&>().get_executor())> wg_; - DynamicBuffer& b_; - basic_parser<isRequest, Derived>& p_; - 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&) = delete; - - template<class DeducedHandler> - read_some_op(DeducedHandler&& h, Stream& s, - DynamicBuffer& b, basic_parser<isRequest, Derived>& p) - : s_(s) - , wg_(s_.get_executor()) - , b_(b) - , p_(p) - , h_(std::forward<DeducedHandler>(h)) - { - } - - using allocator_type = - boost::asio::associated_allocator_t<Handler>; - - allocator_type - get_allocator() const noexcept - { - return (boost::asio::get_associated_allocator)(h_); - } - - using executor_type = boost::asio::associated_executor_t< - Handler, decltype(std::declval<Stream&>().get_executor())>; - - executor_type - get_executor() const noexcept - { - return (boost::asio::get_associated_executor)( - h_, s_.get_executor()); - } - - void - operator()( - 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->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, - bool isRequest, class Derived, class Handler> -void -read_some_op<Stream, DynamicBuffer, - isRequest, Derived, Handler>:: -operator()( - error_code ec, - std::size_t bytes_transferred, - bool cont) -{ - cont_ = cont; - BOOST_ASIO_CORO_REENTER(*this) - { - if(b_.size() == 0) - goto do_read; - for(;;) - { - // parse - { - auto const used = p_.put(b_.data(), ec); - bytes_transferred_ += used; - b_.consume(used); - } - if(ec != http::error::need_more) - break; - - do_read: - BOOST_ASIO_CORO_YIELD - { - // VFALCO This was read_size_or_throw - auto const size = read_size(b_, 65536); - if(size == 0) - { - ec = error::buffer_overflow; - goto upcall; - } - auto const mb = - beast::detail::dynamic_buffer_prepare( - b_, size, ec, error::buffer_overflow); - if(ec) - goto upcall; - 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); - } - - upcall: - if(! cont_) - { - BOOST_ASIO_CORO_YIELD - boost::asio::post( - s_.get_executor(), - bind_handler(std::move(*this), - ec, bytes_transferred_)); - } - h_(ec, bytes_transferred_); - } -} - -//------------------------------------------------------------------------------ - -struct parser_is_done -{ - template<bool isRequest, class Derived> - bool - operator()(basic_parser< - isRequest, Derived> const& p) const - { - return p.is_done(); - } -}; - -struct parser_is_header_done -{ - template<bool isRequest, class Derived> - bool - operator()(basic_parser< - isRequest, Derived> const& p) const - { - return p.is_header_done(); - } -}; - -template<class Stream, class DynamicBuffer, - bool isRequest, class Derived, class Condition, - class Handler> -class read_op - : public boost::asio::coroutine -{ - Stream& s_; - boost::asio::executor_work_guard<decltype( - std::declval<Stream&>().get_executor())> wg_; - 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&) = delete; - - template<class DeducedHandler> - read_op(DeducedHandler&& h, Stream& s, - DynamicBuffer& b, basic_parser<isRequest, - Derived>& p) - : s_(s) - , wg_(s_.get_executor()) - , b_(b) - , p_(p) - , h_(std::forward<DeducedHandler>(h)) - { - } - - using allocator_type = - boost::asio::associated_allocator_t<Handler>; - - allocator_type - get_allocator() const noexcept - { - return (boost::asio::get_associated_allocator)(h_); - } - - using executor_type = boost::asio::associated_executor_t< - Handler, decltype(std::declval<Stream&>().get_executor())>; - - executor_type - get_executor() const noexcept - { - return (boost::asio::get_associated_executor)( - h_, s_.get_executor()); - } - - void - operator()( - 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->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, - bool isRequest, class Derived, class Condition, - class Handler> -void -read_op<Stream, DynamicBuffer, - isRequest, Derived, Condition, Handler>:: -operator()( - error_code ec, - std::size_t bytes_transferred, - bool cont) -{ - cont_ = cont; - BOOST_ASIO_CORO_REENTER(*this) - { - if(Condition{}(p_)) - { - BOOST_ASIO_CORO_YIELD - boost::asio::post(s_.get_executor(), - bind_handler(std::move(*this), ec)); - goto upcall; - } - 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_); - } -} - -//------------------------------------------------------------------------------ - -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>; - - using message_type = - typename parser_type::value_type; - - struct data - { - Stream& s; - boost::asio::executor_work_guard<decltype( - std::declval<Stream&>().get_executor())> wg; - DynamicBuffer& b; - message_type& m; - parser_type p; - std::size_t bytes_transferred = 0; - bool cont = false; - - data(Handler const&, Stream& s_, - DynamicBuffer& b_, message_type& m_) - : s(s_) - , wg(s.get_executor()) - , b(b_) - , m(m_) - , p(std::move(m)) - { - p.eager(true); - } - }; - - handler_ptr<data, Handler> d_; - -public: - read_msg_op(read_msg_op&&) = default; - read_msg_op(read_msg_op const&) = delete; - - template<class DeducedHandler, class... Args> - read_msg_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::forward<DeducedHandler>(h), - s, std::forward<Args>(args)...) - { - } - - using allocator_type = - boost::asio::associated_allocator_t<Handler>; - - allocator_type - get_allocator() const noexcept - { - return (boost::asio::get_associated_allocator)(d_.handler()); - } - - using executor_type = boost::asio::associated_executor_t< - Handler, decltype(std::declval<Stream&>().get_executor())>; - - executor_type - get_executor() const noexcept - { - return (boost::asio::get_associated_executor)( - d_.handler(), d_->s.get_executor()); - } - - void - operator()( - 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_->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, - bool isRequest, class Body, class Allocator, - class Handler> -void -read_msg_op<Stream, DynamicBuffer, - isRequest, Body, Allocator, Handler>:: -operator()( - error_code ec, - std::size_t bytes_transferred, - bool cont) -{ - auto& d = *d_; - d.cont = cont; - BOOST_ASIO_CORO_REENTER(*this) - { - for(;;) - { - 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; - } - } - upcall: - bytes_transferred = d.bytes_transferred; - { - auto wg = std::move(d.wg); - d_.invoke(ec, bytes_transferred); - } - } -} - -} // detail - -//------------------------------------------------------------------------------ - -template< - class SyncReadStream, - class DynamicBuffer, - bool isRequest, class Derived> -std::size_t -read_some( - SyncReadStream& stream, - DynamicBuffer& buffer, - basic_parser<isRequest, Derived>& parser) -{ - static_assert(is_sync_read_stream<SyncReadStream>::value, - "SyncReadStream requirements not met"); - static_assert( - boost::asio::is_dynamic_buffer<DynamicBuffer>::value, - "DynamicBuffer requirements not met"); - BOOST_ASSERT(! parser.is_done()); - error_code ec; - auto const bytes_transferred = - read_some(stream, buffer, parser, ec); - if(ec) - BOOST_THROW_EXCEPTION(system_error{ec}); - return bytes_transferred; -} - -template< - class SyncReadStream, - class DynamicBuffer, - bool isRequest, class Derived> -std::size_t -read_some( - SyncReadStream& stream, - DynamicBuffer& buffer, - basic_parser<isRequest, Derived>& parser, - error_code& ec) -{ - static_assert(is_sync_read_stream<SyncReadStream>::value, - "SyncReadStream requirements not met"); - static_assert( - boost::asio::is_dynamic_buffer<DynamicBuffer>::value, - "DynamicBuffer requirements not met"); - BOOST_ASSERT(! parser.is_done()); - std::size_t bytes_transferred = 0; - if(buffer.size() == 0) - goto do_read; - for(;;) - { - // invoke parser - { - auto const n = parser.put(buffer.data(), ec); - bytes_transferred += n; - buffer.consume(n); - if(! ec) - break; - if(ec != http::error::need_more) - break; - } - do_read: - auto const size = read_size(buffer, 65536); - if(size == 0) - { - ec = error::buffer_overflow; - break; - } - auto const mb = - beast::detail::dynamic_buffer_prepare( - buffer, size, ec, error::buffer_overflow); - if(ec) - break; - auto const n = stream.read_some(*mb, ec); - if(ec == boost::asio::error::eof) - { - BOOST_ASSERT(n == 0); - if(parser.got_some()) - { - // caller sees EOF on next read - parser.put_eof(ec); - if(ec) - break; - BOOST_ASSERT(parser.is_done()); - break; - } - ec = error::end_of_stream; - break; - } - if(ec) - break; - buffer.commit(n); - } - return bytes_transferred; -} - -template< - class AsyncReadStream, - class DynamicBuffer, - bool isRequest, class Derived, - class ReadHandler> -BOOST_ASIO_INITFN_RESULT_TYPE( - ReadHandler, void(error_code, std::size_t)) -async_read_some( - AsyncReadStream& stream, - DynamicBuffer& buffer, - basic_parser<isRequest, Derived>& parser, - ReadHandler&& handler) -{ - static_assert(is_async_read_stream<AsyncReadStream>::value, - "AsyncReadStream requirements not met"); - static_assert( - boost::asio::is_dynamic_buffer<DynamicBuffer>::value, - "DynamicBuffer requirements not met"); - BOOST_ASSERT(! parser.is_done()); - 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))>{ - std::move(init.completion_handler), stream, buffer, parser}( - {}, 0, false); - return init.result.get(); -} - -//------------------------------------------------------------------------------ - -template< - class SyncReadStream, - class DynamicBuffer, - bool isRequest, class Derived> -std::size_t -read_header( - SyncReadStream& stream, - DynamicBuffer& buffer, - basic_parser<isRequest, Derived>& parser) -{ - static_assert(is_sync_read_stream<SyncReadStream>::value, - "SyncReadStream requirements not met"); - static_assert( - boost::asio::is_dynamic_buffer<DynamicBuffer>::value, - "DynamicBuffer requirements not met"); - error_code ec; - auto const bytes_transferred = - read_header(stream, buffer, parser, ec); - if(ec) - BOOST_THROW_EXCEPTION(system_error{ec}); - return bytes_transferred; -} - -template< - class SyncReadStream, - class DynamicBuffer, - bool isRequest, class Derived> -std::size_t -read_header( - SyncReadStream& stream, - DynamicBuffer& buffer, - basic_parser<isRequest, Derived>& parser, - error_code& ec) -{ - static_assert(is_sync_read_stream<SyncReadStream>::value, - "SyncReadStream requirements not met"); - static_assert( - boost::asio::is_dynamic_buffer<DynamicBuffer>::value, - "DynamicBuffer requirements not met"); - parser.eager(false); - if(parser.is_header_done()) - { - ec.assign(0, ec.category()); - return 0; - } - std::size_t bytes_transferred = 0; - do - { - bytes_transferred += read_some( - stream, buffer, parser, ec); - if(ec) - return bytes_transferred; - } - while(! parser.is_header_done()); - return bytes_transferred; -} - -template< - class AsyncReadStream, - class DynamicBuffer, - bool isRequest, class Derived, - class ReadHandler> -BOOST_ASIO_INITFN_RESULT_TYPE( - ReadHandler, void(error_code, std::size_t)) -async_read_header( - AsyncReadStream& stream, - DynamicBuffer& buffer, - basic_parser<isRequest, Derived>& parser, - ReadHandler&& handler) -{ - static_assert(is_async_read_stream<AsyncReadStream>::value, - "AsyncReadStream requirements not met"); - static_assert( - boost::asio::is_dynamic_buffer<DynamicBuffer>::value, - "DynamicBuffer requirements not met"); - parser.eager(false); - 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))>{ - std::move(init.completion_handler), stream, - buffer, parser}({}, 0, false); - return init.result.get(); -} - -//------------------------------------------------------------------------------ - -template< - class SyncReadStream, - class DynamicBuffer, - bool isRequest, class Derived> -std::size_t -read( - SyncReadStream& stream, - DynamicBuffer& buffer, - basic_parser<isRequest, Derived>& parser) -{ - static_assert(is_sync_read_stream<SyncReadStream>::value, - "SyncReadStream requirements not met"); - static_assert( - boost::asio::is_dynamic_buffer<DynamicBuffer>::value, - "DynamicBuffer requirements not met"); - error_code ec; - auto const bytes_transferred = - read(stream, buffer, parser, ec); - if(ec) - BOOST_THROW_EXCEPTION(system_error{ec}); - return bytes_transferred; -} - -template< - class SyncReadStream, - class DynamicBuffer, - bool isRequest, class Derived> -std::size_t -read( - SyncReadStream& stream, - DynamicBuffer& buffer, - basic_parser<isRequest, Derived>& parser, - error_code& ec) -{ - static_assert(is_sync_read_stream<SyncReadStream>::value, - "SyncReadStream requirements not met"); - static_assert( - boost::asio::is_dynamic_buffer<DynamicBuffer>::value, - "DynamicBuffer requirements not met"); - parser.eager(true); - if(parser.is_done()) - { - ec.assign(0, ec.category()); - return 0; - } - std::size_t bytes_transferred = 0; - do - { - bytes_transferred += read_some( - stream, buffer, parser, ec); - if(ec) - return bytes_transferred; - } - while(! parser.is_done()); - return bytes_transferred; -} - -template< - class AsyncReadStream, - class DynamicBuffer, - bool isRequest, class Derived, - class ReadHandler> -BOOST_ASIO_INITFN_RESULT_TYPE( - ReadHandler, void(error_code, std::size_t)) -async_read( - AsyncReadStream& stream, - DynamicBuffer& buffer, - basic_parser<isRequest, Derived>& parser, - ReadHandler&& handler) -{ - static_assert(is_async_read_stream<AsyncReadStream>::value, - "AsyncReadStream requirements not met"); - static_assert( - boost::asio::is_dynamic_buffer<DynamicBuffer>::value, - "DynamicBuffer requirements not met"); - parser.eager(true); - 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))>{ - std::move(init.completion_handler), stream, buffer, parser}( - {}, 0, false); - return init.result.get(); -} - -//------------------------------------------------------------------------------ - -template< - class SyncReadStream, - class DynamicBuffer, - bool isRequest, class Body, class Allocator> -std::size_t -read( - SyncReadStream& stream, - DynamicBuffer& buffer, - message<isRequest, Body, basic_fields<Allocator>>& msg) -{ - static_assert(is_sync_read_stream<SyncReadStream>::value, - "SyncReadStream requirements not met"); - static_assert( - boost::asio::is_dynamic_buffer<DynamicBuffer>::value, - "DynamicBuffer requirements not met"); - static_assert(is_body<Body>::value, - "Body requirements not met"); - static_assert(is_body_reader<Body>::value, - "BodyReader requirements not met"); - error_code ec; - auto const bytes_transferred = - read(stream, buffer, msg, ec); - if(ec) - BOOST_THROW_EXCEPTION(system_error{ec}); - return bytes_transferred; -} - -template< - class SyncReadStream, - class DynamicBuffer, - bool isRequest, class Body, class Allocator> -std::size_t -read( - SyncReadStream& stream, - DynamicBuffer& buffer, - message<isRequest, Body, basic_fields<Allocator>>& msg, - error_code& ec) -{ - static_assert(is_sync_read_stream<SyncReadStream>::value, - "SyncReadStream requirements not met"); - static_assert( - boost::asio::is_dynamic_buffer<DynamicBuffer>::value, - "DynamicBuffer requirements not met"); - static_assert(is_body<Body>::value, - "Body requirements not met"); - static_assert(is_body_reader<Body>::value, - "BodyReader requirements not met"); - parser<isRequest, Body, Allocator> p{std::move(msg)}; - p.eager(true); - auto const bytes_transferred = - read(stream, buffer, p.base(), ec); - if(ec) - return bytes_transferred; - msg = p.release(); - return bytes_transferred; -} - -template< - class AsyncReadStream, - class DynamicBuffer, - bool isRequest, class Body, class Allocator, - class ReadHandler> -BOOST_ASIO_INITFN_RESULT_TYPE( - ReadHandler, void(error_code, std::size_t)) -async_read( - AsyncReadStream& stream, - DynamicBuffer& buffer, - message<isRequest, Body, basic_fields<Allocator>>& msg, - ReadHandler&& handler) -{ - static_assert(is_async_read_stream<AsyncReadStream>::value, - "AsyncReadStream requirements not met"); - static_assert( - boost::asio::is_dynamic_buffer<DynamicBuffer>::value, - "DynamicBuffer requirements not met"); - static_assert(is_body<Body>::value, - "Body requirements not met"); - static_assert(is_body_reader<Body>::value, - "BodyReader requirements not met"); - 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))>{ - std::move(init.completion_handler), stream, buffer, msg}( - {}, 0, false); - return init.result.get(); -} - -} // http -} // beast -} // boost - -#endif diff --git a/boost/beast/http/impl/rfc7230.hpp b/boost/beast/http/impl/rfc7230.hpp new file mode 100644 index 0000000000..11e424b4d1 --- /dev/null +++ b/boost/beast/http/impl/rfc7230.hpp @@ -0,0 +1,423 @@ +// +// Copyright (c) 2016-2019 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) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_HTTP_IMPL_RFC7230_HPP +#define BOOST_BEAST_HTTP_IMPL_RFC7230_HPP + +#include <boost/beast/http/detail/rfc7230.hpp> +#include <iterator> + +namespace boost { +namespace beast { +namespace http { + +class param_list::const_iterator +{ + using iter_type = string_view::const_iterator; + + std::string s_; + detail::param_iter pi_; + +public: + using value_type = param_list::value_type; + using pointer = value_type const*; + using reference = value_type const&; + using difference_type = std::ptrdiff_t; + using iterator_category = std::input_iterator_tag; + + const_iterator() = default; + + bool + operator==(const_iterator const& other) const + { + return + other.pi_.it == pi_.it && + other.pi_.last == pi_.last && + other.pi_.first == pi_.first; + } + + bool + operator!=(const_iterator const& other) const + { + return !(*this == other); + } + + reference + operator*() const + { + return pi_.v; + } + + pointer + operator->() const + { + return &*(*this); + } + + const_iterator& + operator++() + { + increment(); + return *this; + } + + const_iterator + operator++(int) + { + auto temp = *this; + ++(*this); + return temp; + } + +private: + friend class param_list; + + const_iterator(iter_type first, iter_type last) + { + pi_.it = first; + pi_.first = first; + pi_.last = last; + increment(); + } + + BOOST_BEAST_DECL + static + std::string + unquote(string_view sr); + + BOOST_BEAST_DECL + void + increment(); +}; + +inline +auto +param_list:: +begin() const -> + const_iterator +{ + return const_iterator{s_.begin(), s_.end()}; +} + +inline +auto +param_list:: +end() const -> + const_iterator +{ + return const_iterator{s_.end(), s_.end()}; +} + +inline +auto +param_list:: +cbegin() const -> + const_iterator +{ + return const_iterator{s_.begin(), s_.end()}; +} + +inline +auto +param_list:: +cend() const -> + const_iterator +{ + return const_iterator{s_.end(), s_.end()}; +} + +//------------------------------------------------------------------------------ + +class ext_list::const_iterator +{ + ext_list::value_type v_; + iter_type it_; + iter_type first_; + iter_type last_; + +public: + using value_type = ext_list::value_type; + using pointer = value_type const*; + using reference = value_type const&; + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + + const_iterator() = default; + + bool + operator==(const_iterator const& other) const + { + return + other.it_ == it_ && + other.first_ == first_ && + other.last_ == last_; + } + + bool + operator!=(const_iterator const& other) const + { + return !(*this == other); + } + + reference + operator*() const + { + return v_; + } + + pointer + operator->() const + { + return &*(*this); + } + + const_iterator& + operator++() + { + increment(); + return *this; + } + + const_iterator + operator++(int) + { + auto temp = *this; + ++(*this); + return temp; + } + +private: + friend class ext_list; + + const_iterator(iter_type begin, iter_type end) + { + it_ = begin; + first_ = begin; + last_ = end; + increment(); + } + + BOOST_BEAST_DECL + void + increment(); +}; + +inline +auto +ext_list:: +begin() const -> + const_iterator +{ + return const_iterator{s_.begin(), s_.end()}; +} + +inline +auto +ext_list:: +end() const -> + const_iterator +{ + return const_iterator{s_.end(), s_.end()}; +} + +inline +auto +ext_list:: +cbegin() const -> + const_iterator +{ + return const_iterator{s_.begin(), s_.end()}; +} + +inline +auto +ext_list:: +cend() const -> + const_iterator +{ + return const_iterator{s_.end(), s_.end()}; +} + +template<class T> +auto +ext_list:: +find(T const& s) -> + const_iterator +{ + return std::find_if(begin(), end(), + [&s](value_type const& v) + { + return iequals(s, v.first); + }); +} + +template<class T> +bool +ext_list:: +exists(T const& s) +{ + return find(s) != end(); +} + + +//------------------------------------------------------------------------------ + +class token_list::const_iterator +{ + token_list::value_type v_; + iter_type it_; + iter_type first_; + iter_type last_; + +public: + using value_type = token_list::value_type; + using pointer = value_type const*; + using reference = value_type const&; + using difference_type = std::ptrdiff_t; + using iterator_category = std::forward_iterator_tag; + + const_iterator() = default; + + bool + operator==(const_iterator const& other) const + { + return + other.it_ == it_ && + other.first_ == first_ && + other.last_ == last_; + } + + bool + operator!=(const_iterator const& other) const + { + return !(*this == other); + } + + reference + operator*() const + { + return v_; + } + + pointer + operator->() const + { + return &*(*this); + } + + const_iterator& + operator++() + { + increment(); + return *this; + } + + const_iterator + operator++(int) + { + auto temp = *this; + ++(*this); + return temp; + } + +private: + friend class token_list; + + const_iterator(iter_type begin, iter_type end) + { + it_ = begin; + first_ = begin; + last_ = end; + increment(); + } + + BOOST_BEAST_DECL + void + increment(); +}; + +inline +auto +token_list:: +begin() const -> + const_iterator +{ + return const_iterator{s_.begin(), s_.end()}; +} + +inline +auto +token_list:: +end() const -> + const_iterator +{ + return const_iterator{s_.end(), s_.end()}; +} + +inline +auto +token_list:: +cbegin() const -> + const_iterator +{ + return const_iterator{s_.begin(), s_.end()}; +} + +inline +auto +token_list:: +cend() const -> + const_iterator +{ + return const_iterator{s_.end(), s_.end()}; +} + +template<class T> +bool +token_list:: +exists(T const& s) +{ + return std::find_if(begin(), end(), + [&s](value_type const& v) + { + return iequals(s, v); + } + ) != end(); +} + +template<class Policy> +bool +validate_list(detail::basic_parsed_list< + Policy> const& list) +{ + auto const last = list.end(); + auto it = list.begin(); + if(it.error()) + return false; + while(it != last) + { + ++it; + if(it.error()) + return false; + if(it == last) + break; + } + return true; +} + +} // http +} // beast +} // boost + +#ifdef BOOST_BEAST_HEADER_ONLY +#include <boost/beast/http/impl/rfc7230.ipp> +#endif + +#endif + diff --git a/boost/beast/http/impl/rfc7230.ipp b/boost/beast/http/impl/rfc7230.ipp index 96ec902ceb..cf60cefa36 100644 --- a/boost/beast/http/impl/rfc7230.ipp +++ b/boost/beast/http/impl/rfc7230.ipp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2016-2019 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) @@ -10,129 +10,13 @@ #ifndef BOOST_BEAST_HTTP_IMPL_RFC7230_IPP #define BOOST_BEAST_HTTP_IMPL_RFC7230_IPP -#include <boost/beast/http/detail/rfc7230.hpp> -#include <iterator> +#include <boost/beast/http/rfc7230.hpp> namespace boost { namespace beast { namespace http { -class param_list::const_iterator -{ - using iter_type = string_view::const_iterator; - - std::string s_; - detail::param_iter pi_; - -public: - using value_type = param_list::value_type; - using pointer = value_type const*; - using reference = value_type const&; - using difference_type = std::ptrdiff_t; - using iterator_category = std::input_iterator_tag; - - const_iterator() = default; - - bool - operator==(const_iterator const& other) const - { - return - other.pi_.it == pi_.it && - other.pi_.last == pi_.last && - other.pi_.first == pi_.first; - } - - bool - operator!=(const_iterator const& other) const - { - return !(*this == other); - } - - reference - operator*() const - { - return pi_.v; - } - - pointer - operator->() const - { - return &*(*this); - } - - const_iterator& - operator++() - { - increment(); - return *this; - } - - const_iterator - operator++(int) - { - auto temp = *this; - ++(*this); - return temp; - } - -private: - friend class param_list; - - const_iterator(iter_type first, iter_type last) - { - pi_.it = first; - pi_.first = first; - pi_.last = last; - increment(); - } - - template<class = void> - static - std::string - unquote(string_view sr); - - template<class = void> - void - increment(); -}; - -inline -auto -param_list:: -begin() const -> - const_iterator -{ - return const_iterator{s_.begin(), s_.end()}; -} - -inline -auto -param_list:: -end() const -> - const_iterator -{ - return const_iterator{s_.end(), s_.end()}; -} - -inline -auto -param_list:: -cbegin() const -> - const_iterator -{ - return const_iterator{s_.begin(), s_.end()}; -} - -inline -auto -param_list:: -cend() const -> - const_iterator -{ - return const_iterator{s_.end(), s_.end()}; -} -template<class> std::string param_list::const_iterator:: unquote(string_view sr) @@ -151,7 +35,6 @@ unquote(string_view sr) return s; } -template<class> void param_list::const_iterator:: increment() @@ -172,140 +55,6 @@ increment() } } -//------------------------------------------------------------------------------ - -class ext_list::const_iterator -{ - ext_list::value_type v_; - iter_type it_; - iter_type first_; - iter_type last_; - -public: - using value_type = ext_list::value_type; - using pointer = value_type const*; - using reference = value_type const&; - using difference_type = std::ptrdiff_t; - using iterator_category = std::forward_iterator_tag; - - const_iterator() = default; - - bool - operator==(const_iterator const& other) const - { - return - other.it_ == it_ && - other.first_ == first_ && - other.last_ == last_; - } - - bool - operator!=(const_iterator const& other) const - { - return !(*this == other); - } - - reference - operator*() const - { - return v_; - } - - pointer - operator->() const - { - return &*(*this); - } - - const_iterator& - operator++() - { - increment(); - return *this; - } - - const_iterator - operator++(int) - { - auto temp = *this; - ++(*this); - return temp; - } - -private: - friend class ext_list; - - const_iterator(iter_type begin, iter_type end) - { - it_ = begin; - first_ = begin; - last_ = end; - increment(); - } - - template<class = void> - void - increment(); -}; - -inline -auto -ext_list:: -begin() const -> - const_iterator -{ - return const_iterator{s_.begin(), s_.end()}; -} - -inline -auto -ext_list:: -end() const -> - const_iterator -{ - return const_iterator{s_.end(), s_.end()}; -} - -inline -auto -ext_list:: -cbegin() const -> - const_iterator -{ - return const_iterator{s_.begin(), s_.end()}; -} - -inline -auto -ext_list:: -cend() const -> - const_iterator -{ - return const_iterator{s_.end(), s_.end()}; -} - -template<class T> -auto -ext_list:: -find(T const& s) -> - const_iterator -{ - return std::find_if(begin(), end(), - [&s](value_type const& v) - { - return iequals(s, v.first); - }); -} - -template<class T> -bool -ext_list:: -exists(T const& s) -{ - return find(s) != end(); -} - -template<class> void ext_list::const_iterator:: increment() @@ -316,7 +65,7 @@ increment() param-list = *( OWS ";" OWS param ) param = token OWS "=" OWS ( token / quoted-string ) - chunked;a=b;i=j,gzip;windowBits=12 + chunked;a=b;i=j;gzip;windowBits=12 x,y ,,,,,chameleon */ @@ -350,6 +99,8 @@ increment() } v_.first = string_view{&*p0, static_cast<std::size_t>(it_ - p0)}; + if (it_ == last_) + return; detail::param_iter pi; pi.it = it_; pi.first = it_; @@ -372,119 +123,6 @@ increment() } } -//------------------------------------------------------------------------------ - -class token_list::const_iterator -{ - token_list::value_type v_; - iter_type it_; - iter_type first_; - iter_type last_; - -public: - using value_type = token_list::value_type; - using pointer = value_type const*; - using reference = value_type const&; - using difference_type = std::ptrdiff_t; - using iterator_category = std::forward_iterator_tag; - - const_iterator() = default; - - bool - operator==(const_iterator const& other) const - { - return - other.it_ == it_ && - other.first_ == first_ && - other.last_ == last_; - } - - bool - operator!=(const_iterator const& other) const - { - return !(*this == other); - } - - reference - operator*() const - { - return v_; - } - - pointer - operator->() const - { - return &*(*this); - } - - const_iterator& - operator++() - { - increment(); - return *this; - } - - const_iterator - operator++(int) - { - auto temp = *this; - ++(*this); - return temp; - } - -private: - friend class token_list; - - const_iterator(iter_type begin, iter_type end) - { - it_ = begin; - first_ = begin; - last_ = end; - increment(); - } - - template<class = void> - void - increment(); -}; - -inline -auto -token_list:: -begin() const -> - const_iterator -{ - return const_iterator{s_.begin(), s_.end()}; -} - -inline -auto -token_list:: -end() const -> - const_iterator -{ - return const_iterator{s_.end(), s_.end()}; -} - -inline -auto -token_list:: -cbegin() const -> - const_iterator -{ - return const_iterator{s_.begin(), s_.end()}; -} - -inline -auto -token_list:: -cend() const -> - const_iterator -{ - return const_iterator{s_.end(), s_.end()}; -} - -template<class> void token_list::const_iterator:: increment() @@ -531,42 +169,8 @@ increment() } } -template<class T> -bool -token_list:: -exists(T const& s) -{ - return std::find_if(begin(), end(), - [&s](value_type const& v) - { - return iequals(s, v); - } - ) != end(); -} - -template<class Policy> -bool -validate_list(detail::basic_parsed_list< - Policy> const& list) -{ - auto const last = list.end(); - auto it = list.begin(); - if(it.error()) - return false; - while(it != last) - { - ++it; - if(it.error()) - return false; - if(it == last) - break; - } - return true; -} - } // http } // beast } // boost -#endif - +#endif // BOOST_BEAST_HTTP_IMPL_RFC7230_IPP diff --git a/boost/beast/http/impl/serializer.ipp b/boost/beast/http/impl/serializer.hpp index b9e7d26bdb..39efb482d0 100644 --- a/boost/beast/http/impl/serializer.ipp +++ b/boost/beast/http/impl/serializer.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2016-2019 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) @@ -7,9 +7,10 @@ // Official repository: https://github.com/boostorg/beast // -#ifndef BOOST_BEAST_HTTP_IMPL_SERIALIZER_IPP -#define BOOST_BEAST_HTTP_IMPL_SERIALIZER_IPP +#ifndef BOOST_BEAST_HTTP_IMPL_SERIALIZER_HPP +#define BOOST_BEAST_HTTP_IMPL_SERIALIZER_HPP +#include <boost/beast/core/buffer_traits.hpp> #include <boost/beast/core/detail/buffers_ref.hpp> #include <boost/beast/http/error.hpp> #include <boost/beast/http/status.hpp> @@ -70,7 +71,6 @@ void serializer<isRequest, Body, Fields>:: next(error_code& ec, Visit&& visit) { - using boost::asio::buffer_size; switch(s_) { case do_construct: @@ -165,21 +165,21 @@ next(error_code& ec, Visit&& visit) v_.template emplace<7>( boost::in_place_init, fwr_->get(), - buffer_size(result->first), - boost::asio::const_buffer{nullptr, 0}, + buffer_bytes(result->first), + net::const_buffer{nullptr, 0}, chunk_crlf{}, result->first, chunk_crlf{}, detail::chunk_last(), - boost::asio::const_buffer{nullptr, 0}, + net::const_buffer{nullptr, 0}, chunk_crlf{}); goto go_all_c; } v_.template emplace<4>( boost::in_place_init, fwr_->get(), - buffer_size(result->first), - boost::asio::const_buffer{nullptr, 0}, + buffer_bytes(result->first), + net::const_buffer{nullptr, 0}, chunk_crlf{}, result->first, chunk_crlf{}); @@ -217,20 +217,20 @@ next(error_code& ec, Visit&& visit) // do it all in one buffer v_.template emplace<6>( boost::in_place_init, - buffer_size(result->first), - boost::asio::const_buffer{nullptr, 0}, + buffer_bytes(result->first), + net::const_buffer{nullptr, 0}, chunk_crlf{}, result->first, chunk_crlf{}, detail::chunk_last(), - boost::asio::const_buffer{nullptr, 0}, + net::const_buffer{nullptr, 0}, chunk_crlf{}); goto go_body_final_c; } v_.template emplace<5>( boost::in_place_init, - buffer_size(result->first), - boost::asio::const_buffer{nullptr, 0}, + buffer_bytes(result->first), + net::const_buffer{nullptr, 0}, chunk_crlf{}, result->first, chunk_crlf{}); @@ -261,7 +261,7 @@ next(error_code& ec, Visit&& visit) v_.template emplace<8>( boost::in_place_init, detail::chunk_last(), - boost::asio::const_buffer{nullptr, 0}, + net::const_buffer{nullptr, 0}, chunk_crlf{}); s_ = do_final_c + 1; BOOST_FALLTHROUGH; @@ -289,14 +289,13 @@ void serializer<isRequest, Body, Fields>:: consume(std::size_t n) { - using boost::asio::buffer_size; switch(s_) { case do_header: BOOST_ASSERT( - n <= buffer_size(v_.template get<2>())); + n <= buffer_bytes(v_.template get<2>())); v_.template get<2>().consume(n); - if(buffer_size(v_.template get<2>()) > 0) + if(buffer_bytes(v_.template get<2>()) > 0) break; header_done_ = true; v_.reset(); @@ -307,9 +306,9 @@ consume(std::size_t n) case do_header_only: BOOST_ASSERT( - n <= buffer_size(v_.template get<1>())); + n <= buffer_bytes(v_.template get<1>())); v_.template get<1>().consume(n); - if(buffer_size(v_.template get<1>()) > 0) + if(buffer_bytes(v_.template get<1>()) > 0) break; fwr_ = boost::none; header_done_ = true; @@ -321,9 +320,9 @@ consume(std::size_t n) case do_body + 2: { BOOST_ASSERT( - n <= buffer_size(v_.template get<3>())); + n <= buffer_bytes(v_.template get<3>())); v_.template get<3>().consume(n); - if(buffer_size(v_.template get<3>()) > 0) + if(buffer_bytes(v_.template get<3>()) > 0) break; v_.reset(); if(! more_) @@ -336,9 +335,9 @@ consume(std::size_t n) case do_header_c: BOOST_ASSERT( - n <= buffer_size(v_.template get<4>())); + n <= buffer_bytes(v_.template get<4>())); v_.template get<4>().consume(n); - if(buffer_size(v_.template get<4>()) > 0) + if(buffer_bytes(v_.template get<4>()) > 0) break; header_done_ = true; v_.reset(); @@ -351,9 +350,9 @@ consume(std::size_t n) case do_header_only_c: { BOOST_ASSERT( - n <= buffer_size(v_.template get<1>())); + n <= buffer_bytes(v_.template get<1>())); v_.template get<1>().consume(n); - if(buffer_size(v_.template get<1>()) > 0) + if(buffer_bytes(v_.template get<1>()) > 0) break; fwr_ = boost::none; header_done_ = true; @@ -368,9 +367,9 @@ consume(std::size_t n) case do_body_c + 2: BOOST_ASSERT( - n <= buffer_size(v_.template get<5>())); + n <= buffer_bytes(v_.template get<5>())); v_.template get<5>().consume(n); - if(buffer_size(v_.template get<5>()) > 0) + if(buffer_bytes(v_.template get<5>()) > 0) break; v_.reset(); if(more_) @@ -382,9 +381,9 @@ consume(std::size_t n) case do_body_final_c: { BOOST_ASSERT( - n <= buffer_size(v_.template get<6>())); + n <= buffer_bytes(v_.template get<6>())); v_.template get<6>().consume(n); - if(buffer_size(v_.template get<6>()) > 0) + if(buffer_bytes(v_.template get<6>()) > 0) break; v_.reset(); s_ = do_complete; @@ -394,9 +393,9 @@ consume(std::size_t n) case do_all_c: { BOOST_ASSERT( - n <= buffer_size(v_.template get<7>())); + n <= buffer_bytes(v_.template get<7>())); v_.template get<7>().consume(n); - if(buffer_size(v_.template get<7>()) > 0) + if(buffer_bytes(v_.template get<7>()) > 0) break; header_done_ = true; v_.reset(); @@ -405,9 +404,9 @@ consume(std::size_t n) } case do_final_c + 1: - BOOST_ASSERT(buffer_size(v_.template get<8>())); + BOOST_ASSERT(buffer_bytes(v_.template get<8>())); v_.template get<8>().consume(n); - if(buffer_size(v_.template get<8>()) > 0) + if(buffer_bytes(v_.template get<8>()) > 0) break; v_.reset(); goto go_complete; diff --git a/boost/beast/http/impl/status.ipp b/boost/beast/http/impl/status.ipp index 7d37919423..2a61acd5c9 100644 --- a/boost/beast/http/impl/status.ipp +++ b/boost/beast/http/impl/status.ipp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2016-2019 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) @@ -10,15 +10,13 @@ #ifndef BOOST_BEAST_HTTP_IMPL_STATUS_IPP #define BOOST_BEAST_HTTP_IMPL_STATUS_IPP -#include <boost/beast/core/detail/config.hpp> +#include <boost/beast/http/status.hpp> #include <boost/throw_exception.hpp> namespace boost { namespace beast { namespace http { -namespace detail { -template<class = void> status int_to_status(unsigned v) { @@ -107,9 +105,30 @@ int_to_status(unsigned v) return status::unknown; } -template<class = void> +status_class +to_status_class(unsigned v) +{ + switch(v / 100) + { + case 1: return status_class::informational; + case 2: return status_class::successful; + case 3: return status_class::redirection; + case 4: return status_class::client_error; + case 5: return status_class::server_error; + default: + break; + } + return status_class::unknown; +} + +status_class +to_status_class(status v) +{ + return to_status_class(static_cast<int>(v)); +} + string_view -status_to_string(unsigned v) +obsolete_reason(status v) { switch(static_cast<status>(v)) { @@ -190,55 +209,6 @@ status_to_string(unsigned v) return "<unknown-status>"; } -template<class = void> -status_class -to_status_class(unsigned v) -{ - switch(v / 100) - { - case 1: return status_class::informational; - case 2: return status_class::successful; - case 3: return status_class::redirection; - case 4: return status_class::client_error; - case 5: return status_class::server_error; - default: - break; - } - return status_class::unknown; -} - -} // detail - -inline -status -int_to_status(unsigned v) -{ - return detail::int_to_status(v); -} - -inline -status_class -to_status_class(unsigned v) -{ - return detail::to_status_class(v); -} - -inline -status_class -to_status_class(status v) -{ - return to_status_class(static_cast<int>(v)); -} - -inline -string_view -obsolete_reason(status v) -{ - return detail::status_to_string( - static_cast<unsigned>(v)); -} - -inline std::ostream& operator<<(std::ostream& os, status v) { diff --git a/boost/beast/http/impl/verb.ipp b/boost/beast/http/impl/verb.ipp index 36a1734c33..20ef47c551 100644 --- a/boost/beast/http/impl/verb.ipp +++ b/boost/beast/http/impl/verb.ipp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2016-2019 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) @@ -10,7 +10,7 @@ #ifndef BOOST_BEAST_HTTP_IMPL_VERB_IPP #define BOOST_BEAST_HTTP_IMPL_VERB_IPP -#include <boost/beast/core/detail/config.hpp> +#include <boost/beast/http/verb.hpp> #include <boost/throw_exception.hpp> #include <stdexcept> @@ -18,12 +18,8 @@ namespace boost { namespace beast { namespace http { -namespace detail { - -template<class = void> -inline string_view -verb_to_string(verb v) +to_string(verb v) { switch(v) { @@ -74,7 +70,6 @@ verb_to_string(verb v) BOOST_THROW_EXCEPTION(std::invalid_argument{"unknown verb"}); } -template<class = void> verb string_to_verb(string_view v) { @@ -314,22 +309,6 @@ string_to_verb(string_view v) return verb::unknown; } -} // detail - -inline -string_view -to_string(verb v) -{ - return detail::verb_to_string(v); -} - -inline -verb -string_to_verb(string_view s) -{ - return detail::string_to_verb(s); -} - } // http } // beast } // boost diff --git a/boost/beast/http/impl/write.ipp b/boost/beast/http/impl/write.hpp index bbada07024..5636ce92f8 100644 --- a/boost/beast/http/impl/write.ipp +++ b/boost/beast/http/impl/write.hpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) +// Copyright (c) 2016-2019 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) @@ -7,21 +7,16 @@ // Official repository: https://github.com/boostorg/beast // -#ifndef BOOST_BEAST_HTTP_IMPL_WRITE_IPP -#define BOOST_BEAST_HTTP_IMPL_WRITE_IPP +#ifndef BOOST_BEAST_HTTP_IMPL_WRITE_HPP +#define BOOST_BEAST_HTTP_IMPL_WRITE_HPP #include <boost/beast/http/type_traits.hpp> +#include <boost/beast/core/async_base.hpp> #include <boost/beast/core/bind_handler.hpp> +#include <boost/beast/core/buffers_range.hpp> #include <boost/beast/core/ostream.hpp> -#include <boost/beast/core/handler_ptr.hpp> -#include <boost/beast/core/type_traits.hpp> -#include <boost/beast/core/detail/config.hpp> -#include <boost/asio/associated_allocator.hpp> -#include <boost/asio/associated_executor.hpp> +#include <boost/beast/core/stream_traits.hpp> #include <boost/asio/coroutine.hpp> -#include <boost/asio/executor_work_guard.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> @@ -35,15 +30,15 @@ namespace http { namespace detail { template< - class Stream, class Handler, + class Handler, + class Stream, bool isRequest, class Body, class Fields> class write_some_op + : public beast::async_base< + Handler, beast::executor_type<Stream>> { Stream& s_; - boost::asio::executor_work_guard<decltype( - std::declval<Stream&>().get_executor())> wg_; serializer<isRequest,Body, Fields>& sr_; - Handler h_; class lambda { @@ -60,122 +55,74 @@ class write_some_op template<class ConstBufferSequence> void - operator()(error_code& ec, + operator()( + error_code& ec, ConstBufferSequence const& buffers) { invoked = true; - ec.assign(0, ec.category()); - return op_.s_.async_write_some( + ec = {}; + op_.s_.async_write_some( buffers, std::move(op_)); } }; public: - write_some_op(write_some_op&&) = default; - write_some_op(write_some_op const&) = delete; - - template<class DeducedHandler> - write_some_op(DeducedHandler&& h, Stream& s, - serializer<isRequest, Body, Fields>& sr) - : s_(s) - , wg_(s_.get_executor()) + template<class Handler_> + write_some_op( + Handler_&& h, + Stream& s, + serializer<isRequest, Body, Fields>& sr) + : async_base< + Handler, beast::executor_type<Stream>>( + std::forward<Handler_>(h), s.get_executor()) + , s_(s) , sr_(sr) - , h_(std::forward<DeducedHandler>(h)) { + (*this)(); } - using allocator_type = - boost::asio::associated_allocator_t<Handler>; - - allocator_type - get_allocator() const noexcept + void + operator()() { - return (boost::asio::get_associated_allocator)(h_); - } - - using executor_type = boost::asio::associated_executor_t< - Handler, decltype(std::declval<Stream&>().get_executor())>; + error_code ec; + if(! sr_.is_done()) + { + lambda f{*this}; + sr_.next(ec, f); + if(ec) + { + BOOST_ASSERT(! f.invoked); + return net::post( + s_.get_executor(), + beast::bind_front_handler( + std::move(*this), ec, 0)); + } + if(f.invoked) + { + // *this is now moved-from, + return; + } + // What else could it be? + BOOST_ASSERT(sr_.is_done()); + } - executor_type - get_executor() const noexcept - { - return (boost::asio::get_associated_executor)( - h_, s_.get_executor()); + return net::post( + s_.get_executor(), + beast::bind_front_handler( + std::move(*this), ec, 0)); } void - operator()(); - - void operator()( error_code ec, - std::size_t bytes_transferred); - - friend - bool asio_handler_is_continuation(write_some_op* op) + std::size_t bytes_transferred) { - using boost::asio::asio_handler_is_continuation; - 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_)); + if(! ec) + sr_.consume(bytes_transferred); + this->complete_now(ec, bytes_transferred); } }; -template< - class Stream, class Handler, - bool isRequest, class Body, class Fields> -void -write_some_op< - Stream, Handler, isRequest, Body, Fields>:: -operator()() -{ - error_code ec; - if(! sr_.is_done()) - { - lambda f{*this}; - sr_.next(ec, f); - if(ec) - { - BOOST_ASSERT(! f.invoked); - return boost::asio::post( - s_.get_executor(), - bind_handler(std::move(*this), ec, 0)); - } - if(f.invoked) - { - // *this has been moved from, - // cannot access members here. - return; - } - // What else could it be? - BOOST_ASSERT(sr_.is_done()); - } - return boost::asio::post( - s_.get_executor(), - bind_handler(std::move(*this), ec, 0)); -} - -template< - class Stream, class Handler, - bool isRequest, class Body, class Fields> -void -write_some_op< - Stream, Handler, isRequest, Body, Fields>:: -operator()( - error_code ec, std::size_t bytes_transferred) -{ - if(! ec) - sr_.consume(bytes_transferred); - h_(ec, bytes_transferred); -} - //------------------------------------------------------------------------------ struct serializer_is_header_done @@ -205,221 +152,235 @@ struct serializer_is_done //------------------------------------------------------------------------------ template< - class Stream, class Handler, class Predicate, + class Handler, + class Stream, + class Predicate, bool isRequest, class Body, class Fields> -class write_op : public boost::asio::coroutine +class write_op + : public beast::async_base< + Handler, beast::executor_type<Stream>> + , public net::coroutine { Stream& s_; - boost::asio::executor_work_guard<decltype( - std::declval<Stream&>().get_executor())> wg_; serializer<isRequest, Body, Fields>& sr_; std::size_t bytes_transferred_ = 0; - Handler h_; - bool cont_; public: - write_op(write_op&&) = default; - write_op(write_op const&) = delete; - - template<class DeducedHandler> - write_op(DeducedHandler&& h, Stream& s, - serializer<isRequest, Body, Fields>& sr) - : s_(s) - , wg_(s_.get_executor()) + template<class Handler_> + write_op( + Handler_&& h, + Stream& s, + serializer<isRequest, Body, Fields>& sr) + : async_base< + Handler, beast::executor_type<Stream>>( + std::forward<Handler_>(h), s.get_executor()) + , s_(s) , sr_(sr) - , h_(std::forward<DeducedHandler>(h)) - , cont_([&] - { - using boost::asio::asio_handler_is_continuation; - return asio_handler_is_continuation( - std::addressof(h_)); - }()) { - } - - using allocator_type = - boost::asio::associated_allocator_t<Handler>; - - allocator_type - get_allocator() const noexcept - { - return (boost::asio::get_associated_allocator)(h_); - } - - using executor_type = boost::asio::associated_executor_t< - Handler, decltype(std::declval<Stream&>().get_executor())>; - - executor_type - get_executor() const noexcept - { - return (boost::asio::get_associated_executor)( - h_, s_.get_executor()); + (*this)(); } void operator()( error_code ec = {}, - std::size_t bytes_transferred = 0); - - friend - bool asio_handler_is_continuation(write_op* op) - { - return op->cont_; - } - - 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< - class Stream, class Handler, class Predicate, - bool isRequest, class Body, class Fields> -void -write_op<Stream, Handler, Predicate, - isRequest, Body, Fields>:: -operator()( - error_code ec, - std::size_t bytes_transferred) -{ - BOOST_ASIO_CORO_REENTER(*this) + std::size_t bytes_transferred = 0) { - if(Predicate{}(sr_)) + BOOST_ASIO_CORO_REENTER(*this) { - BOOST_ASIO_CORO_YIELD - boost::asio::post( - s_.get_executor(), - bind_handler(std::move(*this))); - goto upcall; - } - for(;;) - { - BOOST_ASIO_CORO_YIELD - beast::http::async_write_some( - s_, sr_, std::move(*this)); - bytes_transferred_ += bytes_transferred; - if(ec) - goto upcall; if(Predicate{}(sr_)) - break; - cont_ = true; + { + BOOST_ASIO_CORO_YIELD + net::post( + s_.get_executor(), + std::move(*this)); + goto upcall; + } + for(;;) + { + BOOST_ASIO_CORO_YIELD + beast::http::async_write_some( + s_, sr_, std::move(*this)); + bytes_transferred_ += bytes_transferred; + if(ec) + goto upcall; + if(Predicate{}(sr_)) + break; + } + upcall: + this->complete_now(ec, bytes_transferred_); } - upcall: - h_(ec, bytes_transferred_); } -} +}; //------------------------------------------------------------------------------ -template<class Stream, class Handler, +template< + class Handler, + class Stream, bool isRequest, class Body, class Fields> class write_msg_op + : public beast::stable_async_base< + Handler, beast::executor_type<Stream>> { - struct data - { - Stream& s; - boost::asio::executor_work_guard<decltype( - std::declval<Stream&>().get_executor())> wg; - serializer<isRequest, Body, Fields> sr; - - data(Handler const&, Stream& s_, message< - isRequest, Body, Fields>& m_) - : s(s_) - , wg(s.get_executor()) - , sr(m_) - { - } - - data(Handler const&, Stream& s_, message< - isRequest, Body, Fields> const& m_) - : s(s_) - , wg(s.get_executor()) - , sr(m_) - { - } - }; - - handler_ptr<data, Handler> d_; + Stream& s_; + serializer<isRequest, Body, Fields>& sr_; public: - write_msg_op(write_msg_op&&) = default; - write_msg_op(write_msg_op const&) = delete; - - template<class DeducedHandler, class... Args> - write_msg_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::forward<DeducedHandler>(h), - s, std::forward<Args>(args)...) - { + template< + class Handler_, + class... Args> + write_msg_op( + Handler_&& h, + Stream& s, + Args&&... args) + : stable_async_base< + Handler, beast::executor_type<Stream>>( + std::forward<Handler_>(h), s.get_executor()) + , s_(s) + , sr_(beast::allocate_stable< + serializer<isRequest, Body, Fields>>( + *this, std::forward<Args>(args)...)) + { + (*this)(); } - using allocator_type = - boost::asio::associated_allocator_t<Handler>; - - allocator_type - get_allocator() const noexcept + void + operator()() { - return (boost::asio::get_associated_allocator)(d_.handler()); + async_write(s_, sr_, std::move(*this)); } - using executor_type = boost::asio::associated_executor_t< - Handler, decltype(std::declval<Stream&>().get_executor())>; - - executor_type - get_executor() const noexcept + void + operator()( + error_code ec, std::size_t bytes_transferred) { - return (boost::asio::get_associated_executor)( - d_.handler(), d_->s.get_executor()); + this->complete_now(ec, bytes_transferred); } +}; - void - operator()(); - +struct run_write_some_op +{ + template< + class WriteHandler, + class Stream, + bool isRequest, class Body, class Fields> void operator()( - error_code ec, std::size_t bytes_transferred); - - friend - bool asio_handler_is_continuation(write_msg_op* op) - { - using boost::asio::asio_handler_is_continuation; - return asio_handler_is_continuation( - std::addressof(op->d_.handler())); + WriteHandler&& h, + Stream* s, + serializer<isRequest, Body, Fields>* sr) + { + // If you get an error on the following line it means + // that your handler does not meet the documented type + // requirements for the handler. + + static_assert( + beast::detail::is_invocable<WriteHandler, + void(error_code, std::size_t)>::value, + "WriteHandler type requirements not met"); + + write_some_op< + typename std::decay<WriteHandler>::type, + Stream, + isRequest, Body, Fields>( + std::forward<WriteHandler>(h), *s, *sr); } +}; - 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())); +struct run_write_op +{ + template< + class WriteHandler, + class Stream, + class Predicate, + bool isRequest, class Body, class Fields> + void + operator()( + WriteHandler&& h, + Stream* s, + Predicate const&, + serializer<isRequest, Body, Fields>* sr) + { + // If you get an error on the following line it means + // that your handler does not meet the documented type + // requirements for the handler. + + static_assert( + beast::detail::is_invocable<WriteHandler, + void(error_code, std::size_t)>::value, + "WriteHandler type requirements not met"); + + write_op< + typename std::decay<WriteHandler>::type, + Stream, + Predicate, + isRequest, Body, Fields>( + std::forward<WriteHandler>(h), *s, *sr); } }; -template<class Stream, class Handler, - bool isRequest, class Body, class Fields> -void -write_msg_op< - Stream, Handler, isRequest, Body, Fields>:: -operator()() +struct run_write_msg_op { - auto& d = *d_; - return async_write(d.s, d.sr, std::move(*this)); -} + template< + class WriteHandler, + class Stream, + bool isRequest, class Body, class Fields, + class... Args> + void + operator()( + WriteHandler&& h, + Stream* s, + message<isRequest, Body, Fields>* m, + std::false_type, + Args&&... args) + { + // If you get an error on the following line it means + // that your handler does not meet the documented type + // requirements for the handler. + + static_assert( + beast::detail::is_invocable<WriteHandler, + void(error_code, std::size_t)>::value, + "WriteHandler type requirements not met"); + + write_msg_op< + typename std::decay<WriteHandler>::type, + Stream, + isRequest, Body, Fields>( + std::forward<WriteHandler>(h), *s, *m, + std::forward<Args>(args)...); + } -template<class Stream, class Handler, - bool isRequest, class Body, class Fields> -void -write_msg_op< - Stream, Handler, isRequest, Body, Fields>:: -operator()(error_code ec, std::size_t bytes_transferred) -{ - auto wg = std::move(d_->wg); - d_.invoke(ec, bytes_transferred); -} + template< + class WriteHandler, + class Stream, + bool isRequest, class Body, class Fields, + class... Args> + void + operator()( + WriteHandler&& h, + Stream* s, + message<isRequest, Body, Fields> const* m, + std::true_type, + Args&&... args) + { + // If you get an error on the following line it means + // that your handler does not meet the documented type + // requirements for the handler. + + static_assert( + beast::detail::is_invocable<WriteHandler, + void(error_code, std::size_t)>::value, + "WriteHandler type requirements not met"); + + write_msg_op< + typename std::decay<WriteHandler>::type, + Stream, + isRequest, Body, Fields>( + std::forward<WriteHandler>(h), *s, *m, + std::forward<Args>(args)...); + } +}; //------------------------------------------------------------------------------ @@ -470,7 +431,7 @@ public: ConstBufferSequence const& buffers) { invoked = true; - bytes_transferred = boost::asio::write( + bytes_transferred = net::write( stream_, buffers, ec); } }; @@ -494,7 +455,7 @@ write_some_impl( sr.consume(f.bytes_transferred); return f.bytes_transferred; } - ec.assign(0, ec.category()); + ec = {}; return 0; } @@ -502,22 +463,19 @@ template< class AsyncWriteStream, bool isRequest, class Body, class Fields, class WriteHandler> -BOOST_ASIO_INITFN_RESULT_TYPE( - WriteHandler, void(error_code, std::size_t)) +BOOST_BEAST_ASYNC_RESULT2(WriteHandler) async_write_some_impl( AsyncWriteStream& stream, serializer<isRequest, Body, Fields>& sr, WriteHandler&& 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>{ - std::move(init.completion_handler), stream, sr}(); - return init.result.get(); + return net::async_initiate< + WriteHandler, + void(error_code, std::size_t)>( + run_write_some_op{}, + handler, + &stream, + &sr); } } // detail @@ -533,11 +491,11 @@ write_some( serializer<isRequest, Body, Fields>& sr) { static_assert(is_sync_write_stream<SyncWriteStream>::value, - "SyncWriteStream requirements not met"); + "SyncWriteStream type requirements not met"); static_assert(is_body<Body>::value, - "Body requirements not met"); + "Body type requirements not met"); static_assert(is_body_writer<Body>::value, - "BodyWriter requirements not met"); + "BodyWriter type requirements not met"); error_code ec; auto const bytes_transferred = write_some(stream, sr, ec); @@ -556,11 +514,11 @@ write_some( error_code& ec) { static_assert(is_sync_write_stream<SyncWriteStream>::value, - "SyncWriteStream requirements not met"); + "SyncWriteStream type requirements not met"); static_assert(is_body<Body>::value, - "Body requirements not met"); + "Body type requirements not met"); static_assert(is_body_writer<Body>::value, - "BodyWriter requirements not met"); + "BodyWriter type requirements not met"); return detail::write_some_impl(stream, sr, ec); } @@ -568,8 +526,7 @@ template< class AsyncWriteStream, bool isRequest, class Body, class Fields, class WriteHandler> -BOOST_ASIO_INITFN_RESULT_TYPE( - WriteHandler, void(error_code, std::size_t)) +BOOST_BEAST_ASYNC_RESULT2(WriteHandler) async_write_some( AsyncWriteStream& stream, serializer<isRequest, Body, Fields>& sr, @@ -577,11 +534,11 @@ async_write_some( { static_assert(is_async_write_stream< AsyncWriteStream>::value, - "AsyncWriteStream requirements not met"); + "AsyncWriteStream type requirements not met"); static_assert(is_body<Body>::value, - "Body requirements not met"); + "Body type requirements not met"); static_assert(is_body_writer<Body>::value, - "BodyWriter requirements not met"); + "BodyWriter type requirements not met"); return detail::async_write_some_impl(stream, sr, std::forward<WriteHandler>(handler)); } @@ -596,11 +553,11 @@ write_header(SyncWriteStream& stream, serializer<isRequest, Body, Fields>& sr) { static_assert(is_sync_write_stream<SyncWriteStream>::value, - "SyncWriteStream requirements not met"); + "SyncWriteStream type requirements not met"); static_assert(is_body<Body>::value, - "Body requirements not met"); + "Body type requirements not met"); static_assert(is_body_writer<Body>::value, - "BodyWriter requirements not met"); + "BodyWriter type requirements not met"); error_code ec; auto const bytes_transferred = write_header(stream, sr, ec); @@ -619,11 +576,11 @@ write_header( error_code& ec) { static_assert(is_sync_write_stream<SyncWriteStream>::value, - "SyncWriteStream requirements not met"); + "SyncWriteStream type requirements not met"); static_assert(is_body<Body>::value, - "Body requirements not met"); + "Body type requirements not met"); static_assert(is_body_writer<Body>::value, - "BodyWriter requirements not met"); + "BodyWriter type requirements not met"); sr.split(true); std::size_t bytes_transferred = 0; if(! sr.is_header_done()) @@ -642,7 +599,7 @@ write_header( } else { - ec.assign(0, ec.category()); + ec = {}; } return bytes_transferred; } @@ -651,8 +608,7 @@ template< class AsyncWriteStream, bool isRequest, class Body, class Fields, class WriteHandler> -BOOST_ASIO_INITFN_RESULT_TYPE( - WriteHandler, void(error_code, std::size_t)) +BOOST_BEAST_ASYNC_RESULT2(WriteHandler) async_write_header( AsyncWriteStream& stream, serializer<isRequest, Body, Fields>& sr, @@ -660,22 +616,20 @@ async_write_header( { static_assert(is_async_write_stream< AsyncWriteStream>::value, - "AsyncWriteStream requirements not met"); + "AsyncWriteStream type requirements not met"); static_assert(is_body<Body>::value, - "Body requirements not met"); + "Body type requirements not met"); static_assert(is_body_writer<Body>::value, - "BodyWriter requirements not met"); + "BodyWriter type requirements not met"); sr.split(true); - 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>{ - std::move(init.completion_handler), stream, sr}(); - return init.result.get(); + return net::async_initiate< + WriteHandler, + void(error_code, std::size_t)>( + detail::run_write_op{}, + handler, + &stream, + detail::serializer_is_header_done{}, + &sr); } //------------------------------------------------------------------------------ @@ -689,7 +643,7 @@ write( serializer<isRequest, Body, Fields>& sr) { static_assert(is_sync_write_stream<SyncWriteStream>::value, - "SyncWriteStream requirements not met"); + "SyncWriteStream type requirements not met"); error_code ec; auto const bytes_transferred = write(stream, sr, ec); @@ -708,7 +662,7 @@ write( error_code& ec) { static_assert(is_sync_write_stream<SyncWriteStream>::value, - "SyncWriteStream requirements not met"); + "SyncWriteStream type requirements not met"); std::size_t bytes_transferred = 0; sr.split(false); for(;;) @@ -727,8 +681,7 @@ template< class AsyncWriteStream, bool isRequest, class Body, class Fields, class WriteHandler> -BOOST_ASIO_INITFN_RESULT_TYPE( - WriteHandler, void(error_code, std::size_t)) +BOOST_BEAST_ASYNC_RESULT2(WriteHandler) async_write( AsyncWriteStream& stream, serializer<isRequest, Body, Fields>& sr, @@ -736,22 +689,20 @@ async_write( { static_assert(is_async_write_stream< AsyncWriteStream>::value, - "AsyncWriteStream requirements not met"); + "AsyncWriteStream type requirements not met"); static_assert(is_body<Body>::value, - "Body requirements not met"); + "Body type requirements not met"); static_assert(is_body_writer<Body>::value, - "BodyWriter requirements not met"); + "BodyWriter type requirements not met"); sr.split(false); - 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>{ - std::move(init.completion_handler), stream, sr}(); - return init.result.get(); + return net::async_initiate< + WriteHandler, + void(error_code, std::size_t)>( + detail::run_write_op{}, + handler, + &stream, + detail::serializer_is_done{}, + &sr); } //------------------------------------------------------------------------------ @@ -767,11 +718,11 @@ write( message<isRequest, Body, Fields>& msg) { static_assert(is_sync_write_stream<SyncWriteStream>::value, - "SyncWriteStream requirements not met"); + "SyncWriteStream type requirements not met"); static_assert(is_body<Body>::value, - "Body requirements not met"); + "Body type requirements not met"); static_assert(is_body_writer<Body>::value, - "BodyWriter requirements not met"); + "BodyWriter type requirements not met"); error_code ec; auto const bytes_transferred = write(stream, msg, ec); @@ -791,11 +742,11 @@ write( message<isRequest, Body, Fields> const& msg) { static_assert(is_sync_write_stream<SyncWriteStream>::value, - "SyncWriteStream requirements not met"); + "SyncWriteStream type requirements not met"); static_assert(is_body<Body>::value, - "Body requirements not met"); + "Body type requirements not met"); static_assert(is_body_writer<Body>::value, - "BodyWriter requirements not met"); + "BodyWriter type requirements not met"); error_code ec; auto const bytes_transferred = write(stream, msg, ec); @@ -816,11 +767,11 @@ write( error_code& ec) { static_assert(is_sync_write_stream<SyncWriteStream>::value, - "SyncWriteStream requirements not met"); + "SyncWriteStream type requirements not met"); static_assert(is_body<Body>::value, - "Body requirements not met"); + "Body type requirements not met"); static_assert(is_body_writer<Body>::value, - "BodyWriter requirements not met"); + "BodyWriter type requirements not met"); serializer<isRequest, Body, Fields> sr{msg}; return write(stream, sr, ec); } @@ -837,11 +788,11 @@ write( error_code& ec) { static_assert(is_sync_write_stream<SyncWriteStream>::value, - "SyncWriteStream requirements not met"); + "SyncWriteStream type requirements not met"); static_assert(is_body<Body>::value, - "Body requirements not met"); + "Body type requirements not met"); static_assert(is_body_writer<Body>::value, - "BodyWriter requirements not met"); + "BodyWriter type requirements not met"); serializer<isRequest, Body, Fields> sr{msg}; return write(stream, sr, ec); } @@ -852,8 +803,7 @@ template< class WriteHandler> typename std::enable_if< is_mutable_body_writer<Body>::value, - BOOST_ASIO_INITFN_RESULT_TYPE( - WriteHandler, void(error_code, std::size_t))>::type + BOOST_BEAST_ASYNC_RESULT2(WriteHandler)>::type async_write( AsyncWriteStream& stream, message<isRequest, Body, Fields>& msg, @@ -861,20 +811,19 @@ async_write( { static_assert( is_async_write_stream<AsyncWriteStream>::value, - "AsyncWriteStream requirements not met"); + "AsyncWriteStream type requirements not met"); static_assert(is_body<Body>::value, - "Body requirements not met"); + "Body type requirements not met"); static_assert(is_body_writer<Body>::value, - "BodyWriter requirements not met"); - 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>{ - std::move(init.completion_handler), stream, msg}(); - return init.result.get(); + "BodyWriter type requirements not met"); + return net::async_initiate< + WriteHandler, + void(error_code, std::size_t)>( + detail::run_write_msg_op{}, + handler, + &stream, + &msg, + std::false_type{}); } template< @@ -883,8 +832,7 @@ template< class WriteHandler> typename std::enable_if< ! is_mutable_body_writer<Body>::value, - BOOST_ASIO_INITFN_RESULT_TYPE( - WriteHandler, void(error_code, std::size_t))>::type + BOOST_BEAST_ASYNC_RESULT2(WriteHandler)>::type async_write( AsyncWriteStream& stream, message<isRequest, Body, Fields> const& msg, @@ -892,20 +840,19 @@ async_write( { static_assert( is_async_write_stream<AsyncWriteStream>::value, - "AsyncWriteStream requirements not met"); + "AsyncWriteStream type requirements not met"); static_assert(is_body<Body>::value, - "Body requirements not met"); + "Body type requirements not met"); static_assert(is_body_writer<Body>::value, - "BodyWriter requirements not met"); - 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>{ - std::move(init.completion_handler), stream, msg}(); - return init.result.get(); + "BodyWriter type requirements not met"); + return net::async_initiate< + WriteHandler, + void(error_code, std::size_t)>( + detail::run_write_msg_op{}, + handler, + &stream, + &msg, + std::true_type{}); } //------------------------------------------------------------------------------ @@ -931,11 +878,11 @@ public: operator()(error_code& ec, ConstBufferSequence const& buffers) const { - ec.assign(0, ec.category()); + ec = {}; if(os_.fail()) return; std::size_t bytes_transferred = 0; - for(auto b : buffers_range(buffers)) + for(auto b : beast::buffers_range_ref(buffers)) { os_.write(static_cast<char const*>( b.data()), b.size()); @@ -975,9 +922,9 @@ operator<<(std::ostream& os, message<isRequest, Body, Fields> const& msg) { static_assert(is_body<Body>::value, - "Body requirements not met"); + "Body type requirements not met"); static_assert(is_body_writer<Body>::value, - "BodyWriter requirements not met"); + "BodyWriter type requirements not met"); serializer<isRequest, Body, Fields> sr{msg}; error_code ec; detail::write_ostream_lambda<decltype(sr)> f{os, sr}; @@ -990,7 +937,7 @@ operator<<(std::ostream& os, { os.setstate(std::ios::failbit); break; - } + } } while(! sr.is_done()); return os; |