• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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