// // Copyright (c) 2013-2016 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 #include #include namespace beast { namespace http { class chunk_encode_text { boost::asio::const_buffer cb_; // Storage for the longest hex string we might need, plus delimiters. std::array buf_; template void copy(chunk_encode_text const& other); template void setup(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: using value_type = boost::asio::const_buffer; using const_iterator = value_type const*; chunk_encode_text(chunk_encode_text const& other) { copy(other); } explicit chunk_encode_text(std::size_t n) { setup(n); } const_iterator begin() const { return &cb_; } const_iterator end() const { return begin() + 1; } }; template void chunk_encode_text:: copy(chunk_encode_text const& other) { auto const n = boost::asio::buffer_size(other.cb_); buf_ = other.buf_; cb_ = boost::asio::const_buffer( &buf_[buf_.size() - n], n); } template void chunk_encode_text:: setup(std::size_t n) { buf_[buf_.size() - 2] = '\r'; buf_[buf_.size() - 1] = '\n'; auto it = to_hex(buf_.end() - 2, n); cb_ = boost::asio::const_buffer{&*it, static_cast( std::distance(it, buf_.end()))}; } /** Returns a chunk-encoded ConstBufferSequence. This returns a buffer sequence representing the first chunk of a chunked transfer coded body. @param fin `true` if this is the last chunk. @param buffers The input buffer sequence. @return A chunk-encoded ConstBufferSequence representing the input. @see rfc7230 section 4.1.3 */ template #if GENERATING_DOCS implementation_defined #else beast::detail::buffer_cat_helper #endif chunk_encode(bool fin, ConstBufferSequence const& buffers) { using boost::asio::buffer_size; return buffer_cat( chunk_encode_text{buffer_size(buffers)}, buffers, fin ? boost::asio::const_buffers_1{"\r\n0\r\n\r\n", 7} : boost::asio::const_buffers_1{"\r\n", 2}); } /** Returns a chunked encoding final chunk. @see rfc7230 section 4.1.3 */ inline #if GENERATING_DOCS implementation_defined #else boost::asio::const_buffers_1 #endif chunk_encode_final() { return boost::asio::const_buffers_1{"0\r\n\r\n", 5}; } } // http } // beast #endif