| 1 | // |
| 2 | // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) |
| 3 | // |
| 4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| 5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 6 | // |
| 7 | // Official repository: https://github.com/boostorg/beast |
| 8 | // |
| 9 | |
| 10 | #ifndef BOOST_BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP |
| 11 | #define BOOST_BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP |
| 12 | |
| 13 | #include <boost/beast/http/type_traits.hpp> |
| 14 | #include <boost/asio/buffer.hpp> |
| 15 | #include <algorithm> |
| 16 | #include <array> |
| 17 | #include <cstddef> |
| 18 | #include <memory> |
| 19 | |
| 20 | namespace boost { |
| 21 | namespace beast { |
| 22 | namespace http { |
| 23 | namespace detail { |
| 24 | |
| 25 | struct chunk_extensions |
| 26 | { |
| 27 | virtual ~chunk_extensions() = default; |
| 28 | virtual net::const_buffer str() = 0; |
| 29 | }; |
| 30 | |
| 31 | template<class ChunkExtensions> |
| 32 | struct chunk_extensions_impl : chunk_extensions |
| 33 | { |
| 34 | ChunkExtensions ext_; |
| 35 | |
| 36 | chunk_extensions_impl(ChunkExtensions&& ext) noexcept |
| 37 | : ext_(std::move(ext)) |
| 38 | { |
| 39 | } |
| 40 | |
| 41 | chunk_extensions_impl(ChunkExtensions const& ext) |
| 42 | : ext_(ext) |
| 43 | { |
| 44 | } |
| 45 | |
| 46 | net::const_buffer |
| 47 | str() override |
| 48 | { |
| 49 | auto const s = ext_.str(); |
| 50 | return {s.data(), s.size()}; |
| 51 | } |
| 52 | }; |
| 53 | |
| 54 | template<class T, class = void> |
| 55 | struct is_chunk_extensions : std::false_type {}; |
| 56 | |
| 57 | template<class T> |
| 58 | struct is_chunk_extensions<T, beast::detail::void_t<decltype( |
| 59 | std::declval<string_view&>() = std::declval<T&>().str() |
| 60 | )>> : std::true_type |
| 61 | { |
| 62 | }; |
| 63 | |
| 64 | //------------------------------------------------------------------------------ |
| 65 | |
| 66 | /** A buffer sequence containing a chunk-encoding header |
| 67 | */ |
| 68 | class chunk_size |
| 69 | { |
| 70 | template<class OutIter> |
| 71 | static |
| 72 | OutIter |
| 73 | to_hex(OutIter last, std::size_t n) |
| 74 | { |
| 75 | if(n == 0) |
| 76 | { |
| 77 | *--last = '0'; |
| 78 | return last; |
| 79 | } |
| 80 | while(n) |
| 81 | { |
| 82 | *--last = "0123456789abcdef" [n&0xf]; |
| 83 | n>>=4; |
| 84 | } |
| 85 | return last; |
| 86 | } |
| 87 | |
| 88 | struct sequence |
| 89 | { |
| 90 | net::const_buffer b; |
| 91 | char data[1 + 2 * sizeof(std::size_t)]; |
| 92 | |
| 93 | explicit |
| 94 | sequence(std::size_t n) |
| 95 | { |
| 96 | char* it0 = data + sizeof(data); |
| 97 | auto it = to_hex(last: it0, n); |
| 98 | b = {it, |
| 99 | static_cast<std::size_t>(it0 - it)}; |
| 100 | } |
| 101 | }; |
| 102 | |
| 103 | std::shared_ptr<sequence> sp_; |
| 104 | |
| 105 | public: |
| 106 | using value_type = net::const_buffer; |
| 107 | |
| 108 | using const_iterator = value_type const*; |
| 109 | |
| 110 | chunk_size(chunk_size const& other) = default; |
| 111 | |
| 112 | /** Construct a chunk header |
| 113 | |
| 114 | @param n The number of octets in this chunk. |
| 115 | */ |
| 116 | chunk_size(std::size_t n) |
| 117 | : sp_(std::make_shared<sequence>(args&: n)) |
| 118 | { |
| 119 | } |
| 120 | |
| 121 | const_iterator |
| 122 | begin() const |
| 123 | { |
| 124 | return &sp_->b; |
| 125 | } |
| 126 | |
| 127 | const_iterator |
| 128 | end() const |
| 129 | { |
| 130 | return begin() + 1; |
| 131 | } |
| 132 | }; |
| 133 | |
| 134 | //------------------------------------------------------------------------------ |
| 135 | |
| 136 | /// Returns a buffer sequence holding a CRLF for chunk encoding |
| 137 | inline |
| 138 | net::const_buffer const& |
| 139 | chunk_crlf() |
| 140 | { |
| 141 | static net::const_buffer const cb{"\r\n" , 2}; |
| 142 | return cb; |
| 143 | } |
| 144 | |
| 145 | /// Returns a buffer sequence holding a final chunk header |
| 146 | inline |
| 147 | net::const_buffer const& |
| 148 | chunk_last() |
| 149 | { |
| 150 | static net::const_buffer const cb{"0\r\n" , 3}; |
| 151 | return cb; |
| 152 | } |
| 153 | |
| 154 | //------------------------------------------------------------------------------ |
| 155 | |
| 156 | #if 0 |
| 157 | template<class = void> |
| 158 | struct chunk_crlf_iter_type |
| 159 | { |
| 160 | class value_type |
| 161 | { |
| 162 | char const s[2] = {'\r', '\n'}; |
| 163 | |
| 164 | public: |
| 165 | value_type() = default; |
| 166 | |
| 167 | operator |
| 168 | net::const_buffer() const |
| 169 | { |
| 170 | return {s, sizeof(s)}; |
| 171 | } |
| 172 | }; |
| 173 | static value_type value; |
| 174 | }; |
| 175 | |
| 176 | template<class T> |
| 177 | typename chunk_crlf_iter_type<T>::value_type |
| 178 | chunk_crlf_iter_type<T>::value; |
| 179 | |
| 180 | using chunk_crlf_iter = chunk_crlf_iter_type<void>; |
| 181 | #endif |
| 182 | |
| 183 | //------------------------------------------------------------------------------ |
| 184 | |
| 185 | struct chunk_size0 |
| 186 | { |
| 187 | using value_type = net::const_buffer; |
| 188 | using const_iterator = value_type const*; |
| 189 | |
| 190 | const_iterator |
| 191 | begin() const |
| 192 | { |
| 193 | return &chunk_last(); |
| 194 | } |
| 195 | |
| 196 | const_iterator |
| 197 | end() const |
| 198 | { |
| 199 | return begin() + 1; |
| 200 | } |
| 201 | }; |
| 202 | |
| 203 | //------------------------------------------------------------------------------ |
| 204 | |
| 205 | template<class T, |
| 206 | bool = is_fields<T>::value> |
| 207 | struct buffers_or_fields |
| 208 | { |
| 209 | using type = typename |
| 210 | T::writer::const_buffers_type; |
| 211 | }; |
| 212 | |
| 213 | template<class T> |
| 214 | struct buffers_or_fields<T, false> |
| 215 | { |
| 216 | using type = T; |
| 217 | }; |
| 218 | |
| 219 | } // detail |
| 220 | } // http |
| 221 | } // beast |
| 222 | } // boost |
| 223 | |
| 224 | #endif |
| 225 | |