Line data Source code
1 : // 2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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/CPPAlliance/http_proto 8 : // 9 : 10 : #ifndef BOOST_HTTP_PROTO_SERIALIZER_HPP 11 : #define BOOST_HTTP_PROTO_SERIALIZER_HPP 12 : 13 : #include <boost/http_proto/detail/config.hpp> 14 : #include <boost/http_proto/error_types.hpp> 15 : #include <boost/http_proto/source.hpp> 16 : #include <boost/http_proto/string_view.hpp> 17 : #include <boost/http_proto/detail/circular_buffer.hpp> 18 : #include <boost/http_proto/detail/array_of_buffers.hpp> 19 : #include <boost/http_proto/detail/header.hpp> 20 : #include <boost/http_proto/detail/workspace.hpp> 21 : #include <cstdint> 22 : #include <memory> 23 : #include <type_traits> 24 : 25 : namespace boost { 26 : namespace http_proto { 27 : 28 : #ifndef BOOST_HTTP_PROTO_DOCS 29 : class request; 30 : class response; 31 : class request_view; 32 : class response_view; 33 : class message_view_base; 34 : struct brotli_decoder_t; 35 : struct brotli_encoder_t; 36 : struct deflate_decoder_t; 37 : struct deflate_encoder_t; 38 : struct gzip_decoder_t; 39 : struct gzip_encoder_t; 40 : namespace detail { 41 : struct codec; 42 : } // detail 43 : #endif 44 : 45 : /** A serializer for HTTP/1 messages 46 : 47 : This is used to serialize one or more complete 48 : HTTP/1 messages. Each message consists of a 49 : required header followed by an optional body. 50 : */ 51 : class BOOST_SYMBOL_VISIBLE 52 0 : serializer 53 : { 54 : public: 55 : /** A ConstBuffers representing the output 56 : */ 57 : class buffers; 58 : 59 : /** Destructor 60 : */ 61 : BOOST_HTTP_PROTO_DECL 62 : ~serializer(); 63 : 64 : /** Constructor 65 : */ 66 : BOOST_HTTP_PROTO_DECL 67 : serializer(); 68 : 69 : /** Constructor 70 : */ 71 : BOOST_HTTP_PROTO_DECL 72 : serializer( 73 : serializer&&) noexcept; 74 : 75 : /** Constructor 76 : */ 77 : BOOST_HTTP_PROTO_DECL 78 : explicit 79 : serializer( 80 : std::size_t buffer_size); 81 : 82 : /** Constructor 83 : */ 84 : template<class P0, class... Pn> 85 : serializer( 86 : std::size_t buffer_size, 87 : P0&& p0, 88 : Pn&&... pn); 89 : 90 : //-------------------------------------------- 91 : 92 : /** Prepare the serializer for a new stream 93 : */ 94 : BOOST_HTTP_PROTO_DECL 95 : void 96 : reset() noexcept; 97 : 98 : /** Prepare the serializer for a new message 99 : 100 : The message will not contain a body. 101 : Changing the contents of the message 102 : after calling this function and before 103 : @ref is_done returns `true` results in 104 : undefined behavior. 105 : */ 106 : void 107 4 : start( 108 : message_view_base const& m) 109 : { 110 4 : start_empty(m); 111 4 : } 112 : 113 : /** Prepare the serializer for a new message 114 : 115 : Changing the contents of the message 116 : after calling this function and before 117 : @ref is_done returns `true` results in 118 : undefined behavior. 119 : 120 : @par Constraints 121 : @code 122 : is_const_buffers< ConstBuffers >::value == true 123 : @endcode 124 : */ 125 : template< 126 : class ConstBuffers 127 : #ifndef BOOST_HTTP_PROTO_DOCS 128 : ,class = typename 129 : std::enable_if< 130 : is_const_buffers< 131 : ConstBuffers>::value 132 : >::type 133 : #endif 134 : > 135 : void 136 : start( 137 : message_view_base const& m, 138 : ConstBuffers&& body); 139 : 140 : /** Prepare the serializer for a new message 141 : 142 : Changing the contents of the message 143 : after calling this function and before 144 : @ref is_done returns `true` results in 145 : undefined behavior. 146 : */ 147 : template< 148 : class Source 149 : #ifndef BOOST_HTTP_PROTO_DOCS 150 : ,class = typename 151 : std::enable_if< 152 : is_source<Source 153 : >::value>::type 154 : #endif 155 : > 156 : auto 157 : start( 158 : message_view_base const& m, 159 : Source&& body) -> 160 : typename std::decay< 161 : Source>::type&; 162 : 163 : //-------------------------------------------- 164 : 165 : struct stream 166 : { 167 : stream() = default; 168 : stream(stream const&) = default; 169 : stream& operator= 170 : (stream const&) = default; 171 : 172 : using buffers_type = 173 : mutable_buffers_pair; 174 : 175 : BOOST_HTTP_PROTO_DECL 176 : std::size_t 177 : capacity() const; 178 : 179 : BOOST_HTTP_PROTO_DECL 180 : std::size_t 181 : size() const; 182 : 183 : BOOST_HTTP_PROTO_DECL 184 : buffers_type 185 : prepare(std::size_t n) const; 186 : 187 : BOOST_HTTP_PROTO_DECL 188 : void 189 : commit(std::size_t n) const; 190 : 191 : BOOST_HTTP_PROTO_DECL 192 : void 193 : close() const; 194 : 195 : private: 196 : friend class serializer; 197 : 198 : explicit 199 : stream( 200 : serializer& sr) noexcept 201 : : sr_(&sr) 202 : { 203 : } 204 : 205 : serializer* sr_ = nullptr; 206 : }; 207 : 208 : struct reserve_nothing 209 : { 210 : void 211 : operator()( 212 : std::size_t, 213 : source::reserve_fn const&) noexcept 214 : { 215 : } 216 : }; 217 : 218 : template< 219 : class MaybeReserve = reserve_nothing> 220 : stream 221 : start_stream( 222 : message_view_base const& m, 223 : MaybeReserve&& maybe_reserve = {}); 224 : 225 : //-------------------------------------------- 226 : 227 : /** Return true if serialization is complete. 228 : */ 229 : bool 230 21 : is_done() const noexcept 231 : { 232 21 : return is_done_; 233 : } 234 : 235 : /** Return the output area. 236 : 237 : This function will serialize some or 238 : all of the content and return the 239 : corresponding output buffers. 240 : 241 : @par Preconditions 242 : @code 243 : this->is_done() == false 244 : @endcode 245 : */ 246 : BOOST_HTTP_PROTO_DECL 247 : auto 248 : prepare() -> 249 : result<buffers>; 250 : 251 : /** Consume bytes from the output area. 252 : */ 253 : BOOST_HTTP_PROTO_DECL 254 : void 255 : consume(std::size_t n); 256 : 257 : private: 258 : static void copy( 259 : const_buffer*, 260 : const_buffer const*, 261 : std::size_t n) noexcept; 262 : auto 263 : make_array(std::size_t n) -> 264 : detail::array_of_const_buffers; 265 : void apply_param(...) = delete; 266 : void apply_params() noexcept; 267 : template<class P0, class... Pn> void apply_params(P0&&, Pn&&...); 268 : 269 : // in detail/impl/brotli_codec.ipp 270 : BOOST_HTTP_PROTO_EXT_DECL void apply_param(brotli_decoder_t const&); 271 : BOOST_HTTP_PROTO_EXT_DECL void apply_param(brotli_encoder_t const&); 272 : 273 : // in detail/impl/zlib_codec.ipp 274 : BOOST_HTTP_PROTO_ZLIB_DECL void apply_param(deflate_decoder_t const&); 275 : BOOST_HTTP_PROTO_ZLIB_DECL void apply_param(deflate_encoder_t const&); 276 : BOOST_HTTP_PROTO_ZLIB_DECL void apply_param(gzip_decoder_t const&); 277 : BOOST_HTTP_PROTO_ZLIB_DECL void apply_param(gzip_encoder_t const&); 278 : 279 : BOOST_HTTP_PROTO_DECL void do_maybe_reserve(source&, std::size_t); 280 : BOOST_HTTP_PROTO_DECL void start_init(message_view_base const&); 281 : BOOST_HTTP_PROTO_DECL void start_empty(message_view_base const&); 282 : BOOST_HTTP_PROTO_DECL void start_buffers(message_view_base const&); 283 : BOOST_HTTP_PROTO_DECL void start_source(message_view_base const&, source*); 284 : BOOST_HTTP_PROTO_DECL void start_stream(message_view_base const&, source&); 285 : 286 : enum class style 287 : { 288 : empty, 289 : buffers, 290 : source, 291 : stream 292 : }; 293 : 294 : enum 295 : { 296 : br_codec = 0, 297 : deflate_codec = 1, 298 : gzip_codec = 2 299 : }; 300 : 301 : static 302 : constexpr 303 : std::size_t 304 : chunked_overhead_ = 305 : 16 + // size 306 : 2 + // CRLF 307 : 2 + // CRLF 308 : 1 + // "0" 309 : 2 + // CRLF 310 : 2; // CRLF 311 : 312 : class reserve; 313 : 314 : detail::workspace ws_; 315 : std::unique_ptr< 316 : detail::codec> dec_[3]; 317 : std::unique_ptr< 318 : detail::codec> enc_[3]; 319 : 320 : source* src_; 321 : detail::array_of_const_buffers buf_; 322 : 323 : detail::circular_buffer tmp0_; 324 : detail::circular_buffer tmp1_; 325 : detail::array_of_const_buffers out_; 326 : 327 : const_buffer* hp_; // header 328 : detail::codec* cod_; 329 : 330 : style st_; 331 : bool more_; 332 : bool is_done_; 333 : bool is_chunked_; 334 : bool is_expect_continue_; 335 : bool is_reserving_ = false; 336 : }; 337 : 338 : //------------------------------------------------ 339 : 340 : } // http_proto 341 : } // boost 342 : 343 : #include <boost/http_proto/impl/serializer.hpp> 344 : 345 : #endif