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/buffered_base.hpp> 14 : #include <boost/http_proto/detail/config.hpp> 15 : #include <boost/http_proto/detail/array_of_buffers.hpp> 16 : #include <boost/http_proto/detail/header.hpp> 17 : #include <boost/http_proto/detail/workspace.hpp> 18 : #include <boost/buffers/circular_buffer.hpp> 19 : #include <boost/buffers/mutable_buffer_span.hpp> 20 : #include <boost/buffers/range.hpp> 21 : #include <boost/buffers/type_traits.hpp> 22 : #include <boost/buffers/type_traits.hpp> 23 : #include <boost/system/result.hpp> 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 : #endif 36 : 37 : /** A serializer for HTTP/1 messages 38 : 39 : This is used to serialize one or more complete 40 : HTTP/1 messages. Each message consists of a 41 : required header followed by an optional body. 42 : */ 43 : class BOOST_SYMBOL_VISIBLE 44 0 : serializer 45 : { 46 : public: 47 : /** A ConstBuffers representing the output 48 : */ 49 : class const_buffers_type; 50 : 51 : struct source; 52 : struct stream; 53 : 54 : /** Destructor 55 : */ 56 : BOOST_HTTP_PROTO_DECL 57 : ~serializer(); 58 : 59 : /** Constructor 60 : */ 61 : BOOST_HTTP_PROTO_DECL 62 : serializer(); 63 : 64 : /** Constructor 65 : */ 66 : BOOST_HTTP_PROTO_DECL 67 : serializer( 68 : serializer&&) noexcept; 69 : 70 : /** Constructor 71 : */ 72 : BOOST_HTTP_PROTO_DECL 73 : explicit 74 : serializer( 75 : std::size_t buffer_size); 76 : 77 : //-------------------------------------------- 78 : 79 : /** Prepare the serializer for a new stream 80 : */ 81 : BOOST_HTTP_PROTO_DECL 82 : void 83 : reset() noexcept; 84 : 85 : /** Prepare the serializer for a new message 86 : 87 : The message will not contain a body. 88 : Changing the contents of the message 89 : after calling this function and before 90 : @ref is_done returns `true` results in 91 : undefined behavior. 92 : */ 93 : void 94 4 : start( 95 : message_view_base const& m) 96 : { 97 4 : start_empty(m); 98 4 : } 99 : 100 : /** Prepare the serializer for a new message 101 : 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 : @par Constraints 108 : @code 109 : is_const_buffers< ConstBuffers >::value == true 110 : @endcode 111 : */ 112 : template< 113 : class ConstBufferSequence 114 : #ifndef BOOST_HTTP_PROTO_DOCS 115 : ,class = typename 116 : std::enable_if< 117 : buffers::is_const_buffer_sequence< 118 : ConstBufferSequence>::value 119 : >::type 120 : #endif 121 : > 122 : void 123 : start( 124 : message_view_base const& m, 125 : ConstBufferSequence&& body); 126 : 127 : /** Prepare the serializer for a new message 128 : 129 : Changing the contents of the message 130 : after calling this function and before 131 : @ref is_done returns `true` results in 132 : undefined behavior. 133 : */ 134 : template< 135 : class Source 136 : #ifndef BOOST_HTTP_PROTO_DOCS 137 : ,class = typename std::enable_if< 138 : std::is_convertible< 139 : typename std::decay<Source>::type*, 140 : source*>::value>::type 141 : #endif 142 : > 143 : auto 144 : start( 145 : message_view_base const& m, 146 : Source&& body) -> 147 : typename std::decay< 148 : Source>::type&; 149 : 150 : //-------------------------------------------- 151 : 152 : BOOST_HTTP_PROTO_DECL 153 : stream 154 : start_stream( 155 : message_view_base const& m); 156 : 157 : //-------------------------------------------- 158 : 159 : /** Return true if serialization is complete. 160 : */ 161 : bool 162 41 : is_done() const noexcept 163 : { 164 41 : return is_done_; 165 : } 166 : 167 : /** Return the output area. 168 : 169 : This function will serialize some or 170 : all of the content and return the 171 : corresponding output buffers. 172 : 173 : @par Preconditions 174 : @code 175 : this->is_done() == false 176 : @endcode 177 : */ 178 : BOOST_HTTP_PROTO_DECL 179 : auto 180 : prepare() -> 181 : system::result< 182 : const_buffers_type>; 183 : 184 : /** Consume bytes from the output area. 185 : */ 186 : BOOST_HTTP_PROTO_DECL 187 : void 188 : consume(std::size_t n); 189 : 190 : private: 191 : static void copy( 192 : buffers::const_buffer*, 193 : buffers::const_buffer const*, 194 : std::size_t n) noexcept; 195 : auto 196 : make_array(std::size_t n) -> 197 : detail::array_of_const_buffers; 198 : 199 : BOOST_HTTP_PROTO_DECL void start_init(message_view_base const&); 200 : BOOST_HTTP_PROTO_DECL void start_empty(message_view_base const&); 201 : BOOST_HTTP_PROTO_DECL void start_buffers(message_view_base const&); 202 : BOOST_HTTP_PROTO_DECL void start_source(message_view_base const&, source*); 203 : 204 : enum class style 205 : { 206 : empty, 207 : buffers, 208 : source, 209 : stream 210 : }; 211 : 212 : static 213 : constexpr 214 : std::size_t 215 : chunked_overhead_ = 216 : 16 + // size 217 : 2 + // CRLF 218 : 2 + // CRLF 219 : 1 + // "0" 220 : 2 + // CRLF 221 : 2; // CRLF 222 : 223 : detail::workspace ws_; 224 : detail::array_of_const_buffers buf_; 225 : source* src_; 226 : 227 : buffers::circular_buffer tmp0_; 228 : buffers::circular_buffer tmp1_; 229 : detail::array_of_const_buffers out_; 230 : 231 : buffers::const_buffer* hp_; // header 232 : 233 : style st_; 234 : bool more_; 235 : bool is_done_; 236 : bool is_chunked_; 237 : bool is_expect_continue_; 238 : }; 239 : 240 : //------------------------------------------------ 241 : 242 : /** An algorithm for producing buffers of data. 243 : 244 : This interface abstracts the production of 245 : a finite stream of data, returned by writing 246 : into caller-provided buffers until there 247 : is no more output data. 248 : 249 : @par Thread Safety 250 : Non-const member functions may not be 251 : called concurrently on the same instance. 252 : */ 253 : struct BOOST_HTTP_PROTO_DECL 254 : serializer::source 255 : : buffered_base 256 : { 257 : /** The results of producing data. 258 : */ 259 : struct results 260 : { 261 : /** The error, if any occurred. 262 : */ 263 : system::error_code ec; 264 : 265 : /** The number of bytes produced in the output. 266 : */ 267 : std::size_t bytes = 0; 268 : 269 : /** True if there will be no more output. 270 : */ 271 : bool finished = false; 272 : 273 : /** Accumulate results. 274 : */ 275 : results& 276 : operator+=( 277 : results const& rv) noexcept; 278 : }; 279 : 280 : /** Produce data. 281 : 282 : This function attempts to read from the 283 : source, placing the data into the given 284 : mutable buffer sequence. 285 : The return value indicates the number of 286 : bytes placed into the buffers, the error 287 : if any occurred, and a `bool` indicating 288 : whether or not there is more data 289 : remaining in the source. 290 : 291 : @par Preconditions 292 : @li @ref init was called, and 293 : @li There is more data remaining. 294 : 295 : @return The result of the operation. 296 : 297 : @param bs The buffers to use. 298 : Each buffer in the sequence will 299 : be filled completely before data 300 : is placed in the next buffer. 301 : */ 302 : template<class MutableBufferSequence> 303 : results 304 24 : read(MutableBufferSequence const& bs) 305 : { 306 : static_assert( 307 : buffers::is_mutable_buffer_sequence< 308 : MutableBufferSequence>::value, 309 : "Type requirements not met"); 310 : 311 24 : return read_impl(bs); 312 : } 313 : 314 : #ifdef BOOST_HTTP_PROTO_DOCS 315 : protected: 316 : #else 317 : private: 318 : #endif 319 : /** Derived class override. 320 : 321 : This pure virtual function is called by 322 : the implementation and must be overriden. 323 : The callee should attempt to place data 324 : into the given mutable buffer. 325 : The return value must be set to indicate 326 : the number of bytes placed into the 327 : buffers, the error if any occurred, 328 : and a `bool` indicating whether or 329 : not there is more data remaining 330 : in the source. 331 : 332 : @par Preconditions 333 : @li @ref init was called, and 334 : @li There is more data remaining. 335 : 336 : @return The result of the operation. 337 : 338 : @param b The buffer to use. 339 : If this is not filled completely, 340 : then the result must indicate failure 341 : or that no more data remains (or both). 342 : */ 343 : virtual 344 : results 345 : on_read( 346 : buffers::mutable_buffer b) = 0; 347 : 348 : /** Derived class override. 349 : 350 : This pure virtual function is called by 351 : the implementation and must be overriden. 352 : The callee should attempt to place data 353 : into the given mutable buffer sequence. 354 : The return value must be set to indicate 355 : the number of bytes placed into the 356 : buffers, the error if any occurred, 357 : and a `bool` indicating whether or 358 : not there is more data remaining 359 : in the source. 360 : 361 : @par Preconditions 362 : @li @ref init was called, and 363 : @li There is more data remaining. 364 : 365 : @return The result of the operation. 366 : 367 : @param bs The buffer sequence to use. 368 : Each buffer in the sequence must 369 : be filled completely before data 370 : is placed in the next buffer. 371 : If the buffers are not filled 372 : completely, then the result must 373 : indicate failure or that no more 374 : data remains (or both). 375 : */ 376 : virtual 377 : results 378 : on_read( 379 : buffers::mutable_buffer_span bs); 380 : 381 : private: 382 : results 383 2 : read_impl( 384 : buffers::mutable_buffer const& b) 385 : { 386 2 : return on_read(b); 387 : } 388 : 389 : results 390 5 : read_impl( 391 : buffers::mutable_buffer_span const& bs) 392 : { 393 5 : return on_read(bs); 394 : } 395 : 396 : template<class T> 397 : results 398 : read_impl(T const&); 399 : }; 400 : 401 : //------------------------------------------------ 402 : 403 : struct serializer::stream 404 : { 405 : /** Constructor. 406 : */ 407 : stream() = default; 408 : 409 : /** Constructor. 410 : */ 411 : stream(stream const&) = default; 412 : 413 : /** Constructor. 414 : */ 415 : stream& operator= 416 : (stream const&) = default; 417 : 418 : using buffers_type = 419 : buffers::mutable_buffer_pair; 420 : 421 : BOOST_HTTP_PROTO_DECL 422 : std::size_t 423 : capacity() const; 424 : 425 : BOOST_HTTP_PROTO_DECL 426 : std::size_t 427 : size() const; 428 : 429 : BOOST_HTTP_PROTO_DECL 430 : buffers_type 431 : prepare(std::size_t n) const; 432 : 433 : BOOST_HTTP_PROTO_DECL 434 : void 435 : commit(std::size_t n) const; 436 : 437 : BOOST_HTTP_PROTO_DECL 438 : void 439 : close() const; 440 : 441 : private: 442 : friend class serializer; 443 : 444 : explicit 445 0 : stream( 446 : serializer& sr) noexcept 447 0 : : sr_(&sr) 448 : { 449 0 : } 450 : 451 : serializer* sr_ = nullptr; 452 : }; 453 : 454 : } // http_proto 455 : } // boost 456 : 457 : #include <boost/http_proto/impl/serializer.hpp> 458 : 459 : #endif