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