]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/beast/http/parser.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / beast / http / parser.hpp
CommitLineData
b32b8144 1//
92f5a8d4 2// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
b32b8144
FG
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_PARSER_HPP
11#define BOOST_BEAST_HTTP_PARSER_HPP
12
13#include <boost/beast/core/detail/config.hpp>
14#include <boost/beast/http/basic_parser.hpp>
15#include <boost/beast/http/message.hpp>
16#include <boost/beast/http/type_traits.hpp>
17#include <boost/optional.hpp>
18#include <boost/throw_exception.hpp>
19#include <functional>
20#include <memory>
21#include <type_traits>
22#include <utility>
23
24namespace boost {
25namespace beast {
26namespace http {
27
28/** An HTTP/1 parser for producing a message.
29
30 This class uses the basic HTTP/1 wire format parser to convert
31 a series of octets into a @ref message using the @ref basic_fields
32 container to represent the fields.
33
34 @tparam isRequest Indicates whether a request or response
35 will be parsed.
36
37 @tparam Body The type used to represent the body. This must
92f5a8d4 38 meet the requirements of <em>Body</em>.
b32b8144
FG
39
40 @tparam Allocator The type of allocator used with the
41 @ref basic_fields container.
42
43 @note A new instance of the parser is required for each message.
44*/
45template<
46 bool isRequest,
47 class Body,
48 class Allocator = std::allocator<char>>
49class parser
92f5a8d4 50 : public basic_parser<isRequest>
b32b8144
FG
51{
52 static_assert(is_body<Body>::value,
92f5a8d4 53 "Body type requirements not met");
b32b8144
FG
54
55 static_assert(is_body_reader<Body>::value,
92f5a8d4 56 "BodyReader type requirements not met");
b32b8144
FG
57
58 template<bool, class, class>
59 friend class parser;
60
b32b8144 61 message<isRequest, Body, basic_fields<Allocator>> m_;
11fdf7f2 62 typename Body::reader rd_;
b32b8144 63 bool rd_inited_ = false;
92f5a8d4 64 bool used_ = false;
b32b8144
FG
65
66 std::function<void(
67 std::uint64_t,
68 string_view,
69 error_code&)> cb_h_;
70
71 std::function<std::size_t(
72 std::uint64_t,
73 string_view,
74 error_code&)> cb_b_;
75
76public:
77 /// The type of message returned by the parser
78 using value_type =
79 message<isRequest, Body, basic_fields<Allocator>>;
80
81 /// Destructor
82 ~parser() = default;
83
11fdf7f2 84 /// Constructor (disallowed)
b32b8144
FG
85 parser(parser const&) = delete;
86
11fdf7f2 87 /// Assignment (disallowed)
b32b8144
FG
88 parser& operator=(parser const&) = delete;
89
11fdf7f2
TL
90 /// Constructor (disallowed)
91 parser(parser&& other) = delete;
b32b8144 92
11fdf7f2
TL
93 /// Constructor
94 parser();
b32b8144
FG
95
96 /** Constructor
97
98 @param args Optional arguments forwarded to the
92f5a8d4 99 @ref http::message constructor.
b32b8144
FG
100
101 @note This function participates in overload
102 resolution only if the first argument is not a
103 @ref parser.
104 */
105#if BOOST_BEAST_DOXYGEN
106 template<class... Args>
107 explicit
108 parser(Args&&... args);
109#else
110 template<class Arg1, class... ArgN,
111 class = typename std::enable_if<
112 ! detail::is_parser<typename
113 std::decay<Arg1>::type>::value>::type>
114 explicit
115 parser(Arg1&& arg1, ArgN&&... argn);
116#endif
117
118 /** Construct a parser from another parser, changing the Body type.
119
120 This constructs a new parser by move constructing the
121 header from another parser with a different body type. The
122 constructed-from parser must not have any parsed body octets or
92f5a8d4 123 initialized <em>BodyReader</em>, otherwise an exception is generated.
b32b8144
FG
124
125 @par Example
126 @code
127 // Deferred body type commitment
128 request_parser<empty_body> req0;
129 ...
130 request_parser<string_body> req{std::move(req0)};
131 @endcode
132
133 If an exception is thrown, the state of the constructed-from
134 parser is undefined.
135
136 @param parser The other parser to construct from. After
137 this call returns, the constructed-from parser may only
138 be destroyed.
139
140 @param args Optional arguments forwarded to the message
141 constructor.
142
143 @throws std::invalid_argument Thrown when the constructed-from
144 parser has already initialized a body reader.
145
146 @note This function participates in overload resolution only
147 if the other parser uses a different body type.
148 */
149#if BOOST_BEAST_DOXYGEN
150 template<class OtherBody, class... Args>
151#else
152 template<class OtherBody, class... Args,
153 class = typename std::enable_if<
154 ! std::is_same<Body, OtherBody>::value>::type>
155#endif
156 explicit
157 parser(parser<isRequest, OtherBody,
158 Allocator>&& parser, Args&&... args);
159
160 /** Returns the parsed message.
161
162 Depending on the parser's progress,
163 parts of this object may be incomplete.
164 */
165 value_type const&
166 get() const
167 {
168 return m_;
169 }
170
171 /** Returns the parsed message.
172
173 Depending on the parser's progress,
174 parts of this object may be incomplete.
175 */
176 value_type&
177 get()
178 {
179 return m_;
180 }
181
182 /** Returns ownership of the parsed message.
183
184 Ownership is transferred to the caller.
185 Depending on the parser's progress,
186 parts of this object may be incomplete.
187
188 @par Requires
189
190 @ref value_type is @b MoveConstructible
191 */
192 value_type
193 release()
194 {
195 static_assert(std::is_move_constructible<decltype(m_)>::value,
196 "MoveConstructible requirements not met");
197 return std::move(m_);
198 }
199
200 /** Set a callback to be invoked on each chunk header.
201
202 The callback will be invoked once for every chunk in the message
203 payload, as well as once for the last chunk. The invocation
204 happens after the chunk header is available but before any body
205 octets have been parsed.
206
207 The extensions are provided in raw, validated form, use
208 @ref chunk_extensions::parse to parse the extensions into a
209 structured container for easier access.
210 The implementation type-erases the callback without requiring
211 a dynamic allocation. For this reason, the callback object is
212 passed by a non-constant reference.
213
214 @par Example
215 @code
216 auto callback =
217 [](std::uint64_t size, string_view extensions, error_code& ec)
218 {
219 //...
220 };
221 parser.on_chunk_header(callback);
222 @endcode
223
224 @param cb The function to set, which must be invocable with
225 this equivalent signature:
226 @code
227 void
228 on_chunk_header(
229 std::uint64_t size, // Size of the chunk, zero for the last chunk
230 string_view extensions, // The chunk-extensions in raw form
231 error_code& ec); // May be set by the callback to indicate an error
232 @endcode
233 */
234 template<class Callback>
235 void
236 on_chunk_header(Callback& cb)
237 {
238 // Callback may not be constant, caller is responsible for
239 // managing the lifetime of the callback. Copies are not made.
240 BOOST_STATIC_ASSERT(! std::is_const<Callback>::value);
241
242 // Can't set the callback after receiving any chunk data!
243 BOOST_ASSERT(! rd_inited_);
244
245 cb_h_ = std::ref(cb);
246 }
247
248 /** Set a callback to be invoked on chunk body data
249
250 The provided function object will be invoked one or more times
251 to provide buffers corresponding to the chunk body for the current
252 chunk. The callback receives the number of octets remaining in this
253 chunk body including the octets in the buffer provided.
254
255 The callback must return the number of octets actually consumed.
256 Any octets not consumed will be presented again in a subsequent
257 invocation of the callback.
258 The implementation type-erases the callback without requiring
259 a dynamic allocation. For this reason, the callback object is
260 passed by a non-constant reference.
261
262 @par Example
263 @code
264 auto callback =
265 [](std::uint64_t remain, string_view body, error_code& ec)
266 {
267 //...
268 };
269 parser.on_chunk_body(callback);
270 @endcode
271
272 @param cb The function to set, which must be invocable with
273 this equivalent signature:
274 @code
275 std::size_t
276 on_chunk_header(
277 std::uint64_t remain, // Octets remaining in this chunk, includes `body`
278 string_view body, // A buffer holding some or all of the remainder of the chunk body
279 error_code& ec); // May be set by the callback to indicate an error
280 @endcode
281 */
282 template<class Callback>
283 void
284 on_chunk_body(Callback& cb)
285 {
286 // Callback may not be constant, caller is responsible for
287 // managing the lifetime of the callback. Copies are not made.
288 BOOST_STATIC_ASSERT(! std::is_const<Callback>::value);
289
290 // Can't set the callback after receiving any chunk data!
291 BOOST_ASSERT(! rd_inited_);
292
293 cb_b_ = std::ref(cb);
294 }
295
296private:
11fdf7f2
TL
297 parser(std::true_type);
298 parser(std::false_type);
299
300 template<class OtherBody, class... Args,
301 class = typename std::enable_if<
302 ! std::is_same<Body, OtherBody>::value>::type>
303 parser(
304 std::true_type,
305 parser<isRequest, OtherBody, Allocator>&& parser,
306 Args&&... args);
307
308 template<class OtherBody, class... Args,
309 class = typename std::enable_if<
310 ! std::is_same<Body, OtherBody>::value>::type>
311 parser(
312 std::false_type,
313 parser<isRequest, OtherBody, Allocator>&& parser,
314 Args&&... args);
315
316 template<class Arg1, class... ArgN,
317 class = typename std::enable_if<
318 ! detail::is_parser<typename
319 std::decay<Arg1>::type>::value>::type>
320 explicit
321 parser(Arg1&& arg1, std::true_type, ArgN&&... argn);
322
323 template<class Arg1, class... ArgN,
324 class = typename std::enable_if<
325 ! detail::is_parser<typename
326 std::decay<Arg1>::type>::value>::type>
327 explicit
328 parser(Arg1&& arg1, std::false_type, ArgN&&... argn);
329
b32b8144
FG
330 void
331 on_request_impl(
332 verb method,
333 string_view method_str,
334 string_view target,
335 int version,
92f5a8d4
TL
336 error_code& ec,
337 std::true_type)
b32b8144 338 {
92f5a8d4
TL
339 // If this assert goes off, it means you tried to re-use a
340 // parser after it was done reading a message. This is not
341 // allowed, you need to create a new parser for each message.
342 // The easiest way to do that is to store the parser in
343 // an optional object.
344
345 BOOST_ASSERT(! used_);
346 if(used_)
b32b8144 347 {
92f5a8d4
TL
348 ec = error::stale_parser;
349 return;
b32b8144 350 }
92f5a8d4
TL
351 used_ = true;
352
353 m_.target(target);
354 if(method != verb::unknown)
355 m_.method(method);
356 else
357 m_.method_string(method_str);
b32b8144
FG
358 m_.version(version);
359 }
360
92f5a8d4
TL
361 void
362 on_request_impl(
363 verb, string_view, string_view,
364 int, error_code&, std::false_type)
365 {
366 }
367
368 void
369 on_request_impl(
370 verb method,
371 string_view method_str,
372 string_view target,
373 int version,
374 error_code& ec) override
375 {
376 this->on_request_impl(
377 method, method_str, target, version, ec,
378 std::integral_constant<bool, isRequest>{});
379 }
380
b32b8144
FG
381 void
382 on_response_impl(
383 int code,
384 string_view reason,
385 int version,
92f5a8d4
TL
386 error_code& ec,
387 std::true_type)
b32b8144 388 {
92f5a8d4
TL
389 // If this assert goes off, it means you tried to re-use a
390 // parser after it was done reading a message. This is not
391 // allowed, you need to create a new parser for each message.
392 // The easiest way to do that is to store the parser in
393 // an optional object.
394
395 BOOST_ASSERT(! used_);
396 if(used_)
b32b8144 397 {
92f5a8d4
TL
398 ec = error::stale_parser;
399 return;
b32b8144 400 }
92f5a8d4
TL
401 used_ = true;
402
403 m_.result(code);
404 m_.version(version);
405 m_.reason(reason);
406 }
407
408 void
409 on_response_impl(
410 int, string_view, int,
411 error_code&, std::false_type)
412 {
413 }
414
415 void
416 on_response_impl(
417 int code,
418 string_view reason,
419 int version,
420 error_code& ec) override
421 {
422 this->on_response_impl(
423 code, reason, version, ec,
424 std::integral_constant<bool, ! isRequest>{});
b32b8144
FG
425 }
426
427 void
428 on_field_impl(
429 field name,
430 string_view name_string,
431 string_view value,
92f5a8d4 432 error_code&) override
b32b8144 433 {
92f5a8d4 434 m_.insert(name, name_string, value);
b32b8144
FG
435 }
436
437 void
92f5a8d4 438 on_header_impl(error_code& ec) override
b32b8144 439 {
92f5a8d4 440 ec = {};
b32b8144
FG
441 }
442
443 void
444 on_body_init_impl(
445 boost::optional<std::uint64_t> const& content_length,
92f5a8d4 446 error_code& ec) override
b32b8144 447 {
11fdf7f2 448 rd_.init(content_length, ec);
b32b8144
FG
449 rd_inited_ = true;
450 }
451
452 std::size_t
453 on_body_impl(
454 string_view body,
92f5a8d4 455 error_code& ec) override
b32b8144 456 {
92f5a8d4 457 return rd_.put(net::buffer(
b32b8144
FG
458 body.data(), body.size()), ec);
459 }
460
461 void
462 on_chunk_header_impl(
463 std::uint64_t size,
464 string_view extensions,
92f5a8d4 465 error_code& ec) override
b32b8144
FG
466 {
467 if(cb_h_)
468 return cb_h_(size, extensions, ec);
b32b8144
FG
469 }
470
471 std::size_t
472 on_chunk_body_impl(
473 std::uint64_t remain,
474 string_view body,
92f5a8d4 475 error_code& ec) override
b32b8144
FG
476 {
477 if(cb_b_)
478 return cb_b_(remain, body, ec);
92f5a8d4 479 return rd_.put(net::buffer(
b32b8144
FG
480 body.data(), body.size()), ec);
481 }
482
483 void
92f5a8d4
TL
484 on_finish_impl(
485 error_code& ec) override
b32b8144 486 {
11fdf7f2 487 rd_.finish(ec);
b32b8144
FG
488 }
489};
490
491/// An HTTP/1 parser for producing a request message.
492template<class Body, class Allocator = std::allocator<char>>
493using request_parser = parser<true, Body, Allocator>;
494
495/// An HTTP/1 parser for producing a response message.
496template<class Body, class Allocator = std::allocator<char>>
497using response_parser = parser<false, Body, Allocator>;
498
499} // http
500} // beast
501} // boost
502
92f5a8d4 503#include <boost/beast/http/impl/parser.hpp>
b32b8144
FG
504
505#endif