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_BUFFER_BODY_HPP 11 #define BOOST_BEAST_HTTP_BUFFER_BODY_HPP 12 13 #include <boost/beast/core/detail/config.hpp> 14 #include <boost/beast/core/buffer_traits.hpp> 15 #include <boost/beast/http/error.hpp> 16 #include <boost/beast/http/message.hpp> 17 #include <boost/beast/http/type_traits.hpp> 18 #include <boost/optional.hpp> 19 #include <type_traits> 20 #include <utility> 21 22 namespace boost { 23 namespace beast { 24 namespace http { 25 26 /** A <em>Body</em> using a caller provided buffer 27 28 Messages using this body type may be serialized and parsed. 29 To use this class, the caller must initialize the members 30 of @ref buffer_body::value_type to appropriate values before 31 each call to read or write during a stream operation. 32 */ 33 struct buffer_body 34 { 35 /// The type of the body member when used in a message. 36 struct value_type 37 { 38 /** A pointer to a contiguous area of memory of @ref size octets, else `nullptr`. 39 40 @par When Serializing 41 42 If this is `nullptr` and `more` is `true`, the error 43 @ref error::need_buffer will be returned from @ref serializer::get 44 Otherwise, the serializer will use the memory pointed to 45 by `data` having `size` octets of valid storage as the 46 next buffer representing the body. 47 48 @par When Parsing 49 50 If this is `nullptr`, the error @ref error::need_buffer 51 will be returned from @ref parser::put. Otherwise, the 52 parser will store body octets into the memory pointed to 53 by `data` having `size` octets of valid storage. After 54 octets are stored, the `data` and `size` members are 55 adjusted: `data` is incremented to point to the next 56 octet after the data written, while `size` is decremented 57 to reflect the remaining space at the memory location 58 pointed to by `data`. 59 */ 60 void* data = nullptr; 61 62 /** The number of octets in the buffer pointed to by @ref data. 63 64 @par When Serializing 65 66 If `data` is `nullptr` during serialization, this value 67 is ignored. Otherwise, it represents the number of valid 68 body octets pointed to by `data`. 69 70 @par When Parsing 71 72 The value of this field will be decremented during parsing 73 to indicate the number of remaining free octets in the 74 buffer pointed to by `data`. When it reaches zero, the 75 parser will return @ref error::need_buffer, indicating to 76 the caller that the values of `data` and `size` should be 77 updated to point to a new memory buffer. 78 */ 79 std::size_t size = 0; 80 81 /** `true` if this is not the last buffer. 82 83 @par When Serializing 84 85 If this is `true` and `data` is `nullptr`, the error 86 @ref error::need_buffer will be returned from @ref serializer::get 87 88 @par When Parsing 89 90 This field is not used during parsing. 91 */ 92 bool more = true; 93 }; 94 95 /** The algorithm for parsing the body 96 97 Meets the requirements of <em>BodyReader</em>. 98 */ 99 #if BOOST_BEAST_DOXYGEN 100 using reader = __implementation_defined__; 101 #else 102 class reader 103 { 104 value_type& body_; 105 106 public: 107 template<bool isRequest, class Fields> 108 explicit reader(header<isRequest,Fields> &,value_type & b)109 reader(header<isRequest, Fields>&, value_type& b) 110 : body_(b) 111 { 112 } 113 114 void init(boost::optional<std::uint64_t> const &,error_code & ec)115 init(boost::optional<std::uint64_t> const&, error_code& ec) 116 { 117 ec = {}; 118 } 119 120 template<class ConstBufferSequence> 121 std::size_t put(ConstBufferSequence const & buffers,error_code & ec)122 put(ConstBufferSequence const& buffers, 123 error_code& ec) 124 { 125 if(! body_.data) 126 { 127 ec = error::need_buffer; 128 return 0; 129 } 130 auto const bytes_transferred = 131 net::buffer_copy(net::buffer( 132 body_.data, body_.size), buffers); 133 body_.data = static_cast<char*>( 134 body_.data) + bytes_transferred; 135 body_.size -= bytes_transferred; 136 if(bytes_transferred == buffer_bytes(buffers)) 137 ec = {}; 138 else 139 ec = error::need_buffer; 140 return bytes_transferred; 141 } 142 143 void finish(error_code & ec)144 finish(error_code& ec) 145 { 146 ec = {}; 147 } 148 }; 149 #endif 150 151 /** The algorithm for serializing the body 152 153 Meets the requirements of <em>BodyWriter</em>. 154 */ 155 #if BOOST_BEAST_DOXYGEN 156 using writer = __implementation_defined__; 157 #else 158 class writer 159 { 160 bool toggle_ = false; 161 value_type const& body_; 162 163 public: 164 using const_buffers_type = 165 net::const_buffer; 166 167 template<bool isRequest, class Fields> 168 explicit writer(header<isRequest,Fields> const &,value_type const & b)169 writer(header<isRequest, Fields> const&, value_type const& b) 170 : body_(b) 171 { 172 } 173 174 void init(error_code & ec)175 init(error_code& ec) 176 { 177 ec = {}; 178 } 179 180 boost::optional< 181 std::pair<const_buffers_type, bool>> get(error_code & ec)182 get(error_code& ec) 183 { 184 if(toggle_) 185 { 186 if(body_.more) 187 { 188 toggle_ = false; 189 ec = error::need_buffer; 190 } 191 else 192 { 193 ec = {}; 194 } 195 return boost::none; 196 } 197 if(body_.data) 198 { 199 ec = {}; 200 toggle_ = true; 201 return {{const_buffers_type{ 202 body_.data, body_.size}, body_.more}}; 203 } 204 if(body_.more) 205 ec = error::need_buffer; 206 else 207 ec = {}; 208 return boost::none; 209 } 210 }; 211 #endif 212 }; 213 214 #if ! BOOST_BEAST_DOXYGEN 215 // operator<< is not supported for buffer_body 216 template<bool isRequest, class Fields> 217 std::ostream& 218 operator<<(std::ostream& os, message<isRequest, 219 buffer_body, Fields> const& msg) = delete; 220 #endif 221 222 } // http 223 } // beast 224 } // boost 225 226 #endif 227