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