// // Copyright (c) 2013-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) // #ifndef BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP #define BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP #include #include #include #include #include #include namespace beast { namespace http { namespace detail { struct chunk_extensions { virtual ~chunk_extensions() = default; virtual boost::asio::const_buffers_1 str() = 0; }; template struct chunk_extensions_impl : chunk_extensions { ChunkExtensions ext_; chunk_extensions_impl(ChunkExtensions&& ext) : ext_(std::move(ext)) { } chunk_extensions_impl(ChunkExtensions const& ext) : ext_(ext) { } boost::asio::const_buffers_1 str() override { auto const s = ext_.str(); return {s.data(), s.size()}; } }; template struct is_chunk_extensions : std::false_type {}; template struct is_chunk_extensions() = std::declval().str(), (void)0)>> : std::true_type { }; //------------------------------------------------------------------------------ /** A buffer sequence containing a chunk-encoding header */ class chunk_size { public: // Storage for the longest hex string we might need class value_type { friend class chunk_size; // First byte holds the length char buf_[1 + 2 * sizeof(std::size_t)]; template void prepare(std::size_t n); template 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; } public: operator boost::asio::const_buffer() const { return { buf_ + sizeof(buf_) - buf_[0], static_cast(buf_[0])}; } }; 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) { value_.prepare(n); } const_iterator begin() const { return &value_; } const_iterator end() const { return begin() + 1; } private: value_type value_; }; template void chunk_size:: value_type:: prepare(std::size_t n) { auto const last = &buf_[sizeof(buf_)]; auto it = to_hex(last, n); buf_[0] = static_cast(last - it); } //------------------------------------------------------------------------------ /// Returns a buffer sequence holding a CRLF for chunk encoding inline boost::asio::const_buffers_1 chunk_crlf() { return {"\r\n", 2}; } /// Returns a buffer sequence holding a final chunk header inline boost::asio::const_buffers_1 chunk_last() { return {"0\r\n", 3}; } //------------------------------------------------------------------------------ template struct chunk_crlf_iter_type { class value_type { char const s[2] = {'\r', '\n'}; public: value_type() = default; operator boost::asio::const_buffer() const { return {s, sizeof(s)}; } }; static value_type value; }; template typename chunk_crlf_iter_type::value_type chunk_crlf_iter_type::value; using chunk_crlf_iter = chunk_crlf_iter_type; //------------------------------------------------------------------------------ template struct chunk_size0_iter_type { class value_type { char const s[3] = {'0', '\r', '\n'}; public: value_type() = default; operator boost::asio::const_buffer() const { return {s, sizeof(s)}; } }; static value_type value; }; template typename chunk_size0_iter_type::value_type chunk_size0_iter_type::value; using chunk_size0_iter = chunk_size0_iter_type; struct chunk_size0 { using value_type = chunk_size0_iter::value_type; using const_iterator = value_type const*; const_iterator begin() const { return &chunk_size0_iter::value; } const_iterator end() const { return begin() + 1; } }; //------------------------------------------------------------------------------ template::value> struct buffers_or_fields { using type = typename T::reader::const_buffers_type; }; template struct buffers_or_fields { using type = T; }; } // detail } // http } // beast #endif