Files
boost_beast/include/beast/http/detail/chunk_encode.hpp
T

258 lines
5.1 KiB
C++
Raw Normal View History

//
2017-02-06 20:07:03 -05:00
// 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
2017-07-09 20:09:30 -07:00
#include <beast/core/type_traits.hpp>
#include <beast/http/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <algorithm>
#include <array>
#include <cstddef>
namespace beast {
namespace http {
namespace detail {
2017-07-09 20:09:30 -07:00
struct chunk_extensions
{
virtual ~chunk_extensions() = default;
virtual boost::asio::const_buffers_1 str() = 0;
};
template<class ChunkExtensions>
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<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(),
(void)0)>> : std::true_type
{
};
//------------------------------------------------------------------------------
2017-05-08 12:41:45 -07:00
/** A buffer sequence containing a chunk-encoding header
*/
2017-07-09 20:09:30 -07:00
class chunk_size
{
2017-07-09 19:44:18 -07:00
public:
2017-05-08 12:41:45 -07:00
// Storage for the longest hex string we might need
2017-07-09 19:44:18 -07:00
class value_type
{
2017-07-09 20:09:30 -07:00
friend class chunk_size;
2017-07-09 19:44:18 -07:00
// First byte holds the length
char buf_[1 + 2 * sizeof(std::size_t)];
template<class = void>
void
prepare(std::size_t n);
template<class OutIter>
static
OutIter
to_hex(OutIter last, std::size_t n)
{
2017-07-09 19:44:18 -07:00
if(n == 0)
{
*--last = '0';
return last;
}
while(n)
{
*--last = "0123456789abcdef"[n&0xf];
n>>=4;
}
return last;
}
2017-07-09 19:44:18 -07:00
public:
operator
boost::asio::const_buffer() const
{
2017-07-09 19:44:18 -07:00
return {
buf_ + sizeof(buf_) - buf_[0],
static_cast<unsigned>(buf_[0])};
}
2017-07-09 19:44:18 -07:00
};
using const_iterator = value_type const*;
2017-07-09 20:09:30 -07:00
chunk_size(chunk_size const& other) = default;
2017-05-08 12:41:45 -07:00
/** Construct a chunk header
@param n The number of octets in this chunk.
*/
2017-07-09 20:09:30 -07:00
chunk_size(std::size_t n)
{
2017-07-09 19:44:18 -07:00
value_.prepare(n);
}
const_iterator
begin() const
{
2017-07-09 19:44:18 -07:00
return &value_;
}
const_iterator
end() const
{
return begin() + 1;
}
2017-05-08 12:41:45 -07:00
2017-07-09 19:44:18 -07:00
private:
value_type value_;
};
template<class>
void
2017-07-09 20:09:30 -07:00
chunk_size::
2017-07-09 19:44:18 -07:00
value_type::
prepare(std::size_t n)
{
2017-07-09 19:44:18 -07:00
auto const last = &buf_[sizeof(buf_)];
auto it = to_hex(last, n);
buf_[0] = static_cast<char>(last - it);
2017-05-08 12:41:45 -07:00
}
2017-07-09 20:09:30 -07:00
//------------------------------------------------------------------------------
2017-05-08 12:41:45 -07:00
/// 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
2017-07-09 20:09:30 -07:00
chunk_last()
2017-05-08 12:41:45 -07:00
{
return {"0\r\n", 3};
}
2017-07-09 20:09:30 -07:00
//------------------------------------------------------------------------------
template<class = void>
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<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>;
//------------------------------------------------------------------------------
template<class = void>
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<class T>
typename chunk_size0_iter_type<T>::value_type
chunk_size0_iter_type<T>::value;
using chunk_size0_iter = chunk_size0_iter_type<void>;
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<class T,
bool = is_fields<T>::value>
struct buffers_or_fields
{
using type = typename
T::reader::const_buffers_type;
};
template<class T>
struct buffers_or_fields<T, false>
{
using type = T;
};
} // detail
} // http
} // beast
#endif