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_SERIALIZER_HPP 11 #define BOOST_BEAST_HTTP_SERIALIZER_HPP 12 13 #include <boost/beast/core/detail/config.hpp> 14 #include <boost/beast/core/buffers_cat.hpp> 15 #include <boost/beast/core/buffers_prefix.hpp> 16 #include <boost/beast/core/buffers_suffix.hpp> 17 #include <boost/beast/core/string.hpp> 18 #include <boost/beast/core/detail/variant.hpp> 19 #include <boost/beast/http/message.hpp> 20 #include <boost/beast/http/chunk_encode.hpp> 21 #include <boost/asio/buffer.hpp> 22 #include <boost/optional.hpp> 23 24 namespace boost { 25 namespace beast { 26 namespace http { 27 28 /** Provides buffer oriented HTTP message serialization functionality. 29 30 An object of this type is used to serialize a complete 31 HTTP message into a sequence of octets. To use this class, 32 construct an instance with the message to be serialized. 33 The implementation will automatically perform chunk encoding 34 if the contents of the message indicate that chunk encoding 35 is required. 36 37 Chunked output produced by the serializer never contains chunk 38 extensions or trailers, and the location of chunk boundaries 39 is not specified. If callers require chunk extensions, trailers, 40 or control over the exact contents of each chunk they should 41 use the serializer to write just the message header, and then 42 assume control over serializing the chunked payload by using 43 the chunk buffer sequence types @ref chunk_body, @ref chunk_crlf, 44 @ref chunk_header, and @ref chunk_last. 45 46 @tparam isRequest `true` if the message is a request. 47 48 @tparam Body The body type of the message. 49 50 @tparam Fields The type of fields in the message. 51 */ 52 template< 53 bool isRequest, 54 class Body, 55 class Fields = fields> 56 class serializer 57 { 58 public: 59 static_assert(is_body<Body>::value, 60 "Body type requirements not met"); 61 62 static_assert(is_body_writer<Body>::value, 63 "BodyWriter type requirements not met"); 64 65 /** The type of message this serializer uses 66 67 This may be const or non-const depending on the 68 implementation of the corresponding <em>BodyWriter</em>. 69 */ 70 #if BOOST_BEAST_DOXYGEN 71 using value_type = __implementation_defined__; 72 #else 73 using value_type = typename std::conditional< 74 std::is_constructible<typename Body::writer, 75 header<isRequest, Fields>&, 76 typename Body::value_type&>::value && 77 ! std::is_constructible<typename Body::writer, 78 header<isRequest, Fields> const&, 79 typename Body::value_type const&>::value, 80 message<isRequest, Body, Fields>, 81 message<isRequest, Body, Fields> const>::type; 82 #endif 83 84 private: 85 enum 86 { 87 do_construct = 0, 88 89 do_init = 10, 90 do_header_only = 20, 91 do_header = 30, 92 do_body = 40, 93 94 do_init_c = 50, 95 do_header_only_c = 60, 96 do_header_c = 70, 97 do_body_c = 80, 98 do_final_c = 90, 99 #ifndef BOOST_BEAST_NO_BIG_VARIANTS 100 do_body_final_c = 100, 101 do_all_c = 110, 102 #endif 103 104 do_complete = 120 105 }; 106 107 void fwrinit(std::true_type); 108 void fwrinit(std::false_type); 109 110 template<std::size_t, class Visit> 111 void 112 do_visit(error_code& ec, Visit& visit); 113 114 using writer = typename Body::writer; 115 116 using cb1_t = buffers_suffix<typename 117 Fields::writer::const_buffers_type>; // header 118 using pcb1_t = buffers_prefix_view<cb1_t const&>; 119 120 using cb2_t = buffers_suffix<buffers_cat_view< 121 typename Fields::writer::const_buffers_type,// header 122 typename writer::const_buffers_type>>; // body 123 using pcb2_t = buffers_prefix_view<cb2_t const&>; 124 125 using cb3_t = buffers_suffix< 126 typename writer::const_buffers_type>; // body 127 using pcb3_t = buffers_prefix_view<cb3_t const&>; 128 129 using cb4_t = buffers_suffix<buffers_cat_view< 130 typename Fields::writer::const_buffers_type,// header 131 detail::chunk_size, // chunk-size 132 net::const_buffer, // chunk-ext 133 chunk_crlf, // crlf 134 typename writer::const_buffers_type, // body 135 chunk_crlf>>; // crlf 136 using pcb4_t = buffers_prefix_view<cb4_t const&>; 137 138 using cb5_t = buffers_suffix<buffers_cat_view< 139 detail::chunk_size, // chunk-header 140 net::const_buffer, // chunk-ext 141 chunk_crlf, // crlf 142 typename writer::const_buffers_type, // body 143 chunk_crlf>>; // crlf 144 using pcb5_t = buffers_prefix_view<cb5_t const&>; 145 146 using cb6_t = buffers_suffix<buffers_cat_view< 147 detail::chunk_size, // chunk-header 148 net::const_buffer, // chunk-size 149 chunk_crlf, // crlf 150 typename writer::const_buffers_type, // body 151 chunk_crlf, // crlf 152 net::const_buffer, // chunk-final 153 net::const_buffer, // trailers 154 chunk_crlf>>; // crlf 155 using pcb6_t = buffers_prefix_view<cb6_t const&>; 156 157 using cb7_t = buffers_suffix<buffers_cat_view< 158 typename Fields::writer::const_buffers_type,// header 159 detail::chunk_size, // chunk-size 160 net::const_buffer, // chunk-ext 161 chunk_crlf, // crlf 162 typename writer::const_buffers_type, // body 163 chunk_crlf, // crlf 164 net::const_buffer, // chunk-final 165 net::const_buffer, // trailers 166 chunk_crlf>>; // crlf 167 using pcb7_t = buffers_prefix_view<cb7_t const&>; 168 169 using cb8_t = buffers_suffix<buffers_cat_view< 170 net::const_buffer, // chunk-final 171 net::const_buffer, // trailers 172 chunk_crlf>>; // crlf 173 using pcb8_t = buffers_prefix_view<cb8_t const&>; 174 175 value_type& m_; 176 writer wr_; 177 boost::optional<typename Fields::writer> fwr_; 178 beast::detail::variant< 179 cb1_t, cb2_t, cb3_t, cb4_t, 180 cb5_t ,cb6_t, cb7_t, cb8_t> v_; 181 beast::detail::variant< 182 pcb1_t, pcb2_t, pcb3_t, pcb4_t, 183 pcb5_t ,pcb6_t, pcb7_t, pcb8_t> pv_; 184 std::size_t limit_ = 185 (std::numeric_limits<std::size_t>::max)(); 186 int s_ = do_construct; 187 bool split_ = false; 188 bool header_done_ = false; 189 bool more_ = false; 190 191 public: 192 /// Constructor 193 serializer(serializer&&) = default; 194 195 /// Constructor 196 serializer(serializer const&) = default; 197 198 /// Assignment 199 serializer& operator=(serializer const&) = delete; 200 201 /** Constructor 202 203 The implementation guarantees that the message passed on 204 construction will not be accessed until the first call to 205 @ref next. This allows the message to be lazily created. 206 For example, if the header is filled in before serialization. 207 208 @param msg A reference to the message to serialize, which must 209 remain valid for the lifetime of the serializer. Depending on 210 the type of Body used, this may or may not be a `const` reference. 211 212 @note This function participates in overload resolution only if 213 Body::writer is constructible from a `const` message reference. 214 */ 215 explicit 216 serializer(value_type& msg); 217 218 /// Returns the message being serialized 219 value_type& get()220 get() 221 { 222 return m_; 223 } 224 225 /// Returns the serialized buffer size limit 226 std::size_t limit()227 limit() 228 { 229 return limit_; 230 } 231 232 /** Set the serialized buffer size limit 233 234 This function adjusts the limit on the maximum size of the 235 buffers passed to the visitor. The new size limit takes effect 236 in the following call to @ref next. 237 238 The default is no buffer size limit. 239 240 @param limit The new buffer size limit. If this number 241 is zero, the size limit is removed. 242 */ 243 void limit(std::size_t limit)244 limit(std::size_t limit) 245 { 246 limit_ = limit > 0 ? limit : 247 (std::numeric_limits<std::size_t>::max)(); 248 } 249 250 /** Returns `true` if we will pause after writing the complete header. 251 */ 252 bool split()253 split() 254 { 255 return split_; 256 } 257 258 /** Set whether the header and body are written separately. 259 260 When the split feature is enabled, the implementation will 261 write only the octets corresponding to the serialized header 262 first. If the header has already been written, this function 263 will have no effect on output. 264 */ 265 void split(bool v)266 split(bool v) 267 { 268 split_ = v; 269 } 270 271 /** Return `true` if serialization of the header is complete. 272 273 This function indicates whether or not all buffers containing 274 serialized header octets have been retrieved. 275 */ 276 bool is_header_done()277 is_header_done() 278 { 279 return header_done_; 280 } 281 282 /** Return `true` if serialization is complete. 283 284 The operation is complete when all octets corresponding 285 to the serialized representation of the message have been 286 successfully retrieved. 287 */ 288 bool is_done()289 is_done() 290 { 291 return s_ == do_complete; 292 } 293 294 /** Returns the next set of buffers in the serialization. 295 296 This function will attempt to call the `visit` function 297 object with a <em>ConstBufferSequence</em> of unspecified type 298 representing the next set of buffers in the serialization 299 of the message represented by this object. 300 301 If there are no more buffers in the serialization, the 302 visit function will not be called. In this case, no error 303 will be indicated, and the function @ref is_done will 304 return `true`. 305 306 @param ec Set to the error, if any occurred. 307 308 @param visit The function to call. The equivalent function 309 signature of this object must be: 310 @code 311 template<class ConstBufferSequence> 312 void visit(error_code&, ConstBufferSequence const&); 313 @endcode 314 The function is not copied, if no error occurs it will be 315 invoked before the call to @ref next returns. 316 317 */ 318 template<class Visit> 319 void 320 next(error_code& ec, Visit&& visit); 321 322 /** Consume buffer octets in the serialization. 323 324 This function should be called after one or more octets 325 contained in the buffers provided in the prior call 326 to @ref next have been used. 327 328 After a call to @ref consume, callers should check the 329 return value of @ref is_done to determine if the entire 330 message has been serialized. 331 332 @param n The number of octets to consume. This number must 333 be greater than zero and no greater than the number of 334 octets in the buffers provided in the prior call to @ref next. 335 */ 336 void 337 consume(std::size_t n); 338 339 /** Provides low-level access to the associated <em>BodyWriter</em> 340 341 This function provides access to the instance of the writer 342 associated with the body and created by the serializer 343 upon construction. The behavior of accessing this object 344 is defined by the specification of the particular writer 345 and its associated body. 346 347 @return A reference to the writer. 348 */ 349 writer& writer_impl()350 writer_impl() 351 { 352 return wr_; 353 } 354 }; 355 356 /// A serializer for HTTP/1 requests 357 template<class Body, class Fields = fields> 358 using request_serializer = serializer<true, Body, Fields>; 359 360 /// A serializer for HTTP/1 responses 361 template<class Body, class Fields = fields> 362 using response_serializer = serializer<false, Body, Fields>; 363 364 } // http 365 } // beast 366 } // boost 367 368 #include <boost/beast/http/impl/serializer.hpp> 369 370 #endif 371