Files
boost_beast/include/beast/http/chunk_encode.hpp
Vinnie Falco f98ec17121 Make chunk_encode public:
fix #154, fix #156

This adds public interfaces for transforming buffer
sequences into their chunk-encoded equivalents. The
transformations are O(1) in space and time.
2017-07-20 08:12:13 -07:00

158 lines
3.4 KiB
C++

//
// 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 <beast/core/buffer_cat.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/assert.hpp>
#include <algorithm>
#include <array>
#include <cstddef>
#include <iterator>
#include <type_traits>
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<char, 2 * sizeof(std::size_t) + 2> buf_;
template<class = void>
void
copy(chunk_encode_text const& other);
template<class = void>
void
setup(std::size_t n);
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;
}
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<class>
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<class>
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::size_t>(
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 <a href=https://tools.ietf.org/html/rfc7230#section-4.1.3>rfc7230 section 4.1.3</a>
*/
template<class ConstBufferSequence>
#if GENERATING_DOCS
implementation_defined
#else
beast::detail::buffer_cat_helper<boost::asio::const_buffer,
chunk_encode_text, ConstBufferSequence, boost::asio::const_buffers_1>
#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 <a href=https://tools.ietf.org/html/rfc7230#section-4.1.3>rfc7230 section 4.1.3</a>
*/
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