// // 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_DETAIL_CHUNK_ENCODE_HPP #define BOOST_BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP #include <boost/beast/http/type_traits.hpp> #include <boost/asio/buffer.hpp> #include <algorithm> #include <array> #include <cstddef> #include <memory> namespace boost { namespace beast { namespace http { namespace detail { struct chunk_extensions { virtual ~chunk_extensions() = default; virtual net::const_buffer str() = 0; }; template<class ChunkExtensions> struct chunk_extensions_impl : chunk_extensions { ChunkExtensions ext_; chunk_extensions_impl(ChunkExtensions&& ext) noexcept : ext_(std::move(ext)) { } chunk_extensions_impl(ChunkExtensions const& ext) : ext_(ext) { } net::const_buffer str() override { auto const s = ext_.str(); return {s.data(), s.size()}; } }; template<class T, class = void> struct is_chunk_extensions : std::false_type {}; template<class T> struct is_chunk_extensions<T, beast::detail::void_t<decltype( std::declval<string_view&>() = std::declval<T&>().str() )>> : std::true_type { }; //------------------------------------------------------------------------------ /** A buffer sequence containing a chunk-encoding header */ class chunk_size { template<class OutIter> static OutIter to_hex(OutIter last, std::size_t n) { if(n == 0) { *--last = '0'; return last; } while(n) { *--last = "0123456789abcdef"[n&0xf]; n>>=4; } return last; } struct sequence { net::const_buffer b; char data[1 + 2 * sizeof(std::size_t)]; explicit sequence(std::size_t n) { char* it0 = data + sizeof(data); auto it = to_hex(it0, n); b = {it, static_cast<std::size_t>(it0 - it)}; } }; std::shared_ptr<sequence> sp_; public: using value_type = net::const_buffer; using const_iterator = value_type const*; chunk_size(chunk_size const& other) = default; /** Construct a chunk header @param n The number of octets in this chunk. */ chunk_size(std::size_t n) : sp_(std::make_shared<sequence>(n)) { } const_iterator begin() const { return &sp_->b; } const_iterator end() const { return begin() + 1; } }; //------------------------------------------------------------------------------ /// Returns a buffer sequence holding a CRLF for chunk encoding inline net::const_buffer const& chunk_crlf() { static net::const_buffer const cb{"\r\n", 2}; return cb; } /// Returns a buffer sequence holding a final chunk header inline net::const_buffer const& chunk_last() { static net::const_buffer const cb{"0\r\n", 3}; return cb; } //------------------------------------------------------------------------------ #if 0 template<class = void> struct chunk_crlf_iter_type { class value_type { char const s[2] = {'\r', '\n'}; public: value_type() = default; operator net::const_buffer() const { return {s, sizeof(s)}; } }; static value_type value; }; template<class T> typename chunk_crlf_iter_type<T>::value_type chunk_crlf_iter_type<T>::value; using chunk_crlf_iter = chunk_crlf_iter_type<void>; #endif //------------------------------------------------------------------------------ struct chunk_size0 { using value_type = net::const_buffer; using const_iterator = value_type const*; const_iterator begin() const { return &chunk_last(); } const_iterator end() const { return begin() + 1; } }; //------------------------------------------------------------------------------ template<class T, bool = is_fields<T>::value> struct buffers_or_fields { using type = typename T::writer::const_buffers_type; }; template<class T> struct buffers_or_fields<T, false> { using type = T; }; } // detail } // http } // beast } // boost #endif