1//
2// Copyright (c) 2022 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//------------------------------------------------------------------------------
11//
12// Example: JSON body
13//
14//------------------------------------------------------------------------------
15
16#ifndef BOOST_BEAST_EXAMPLE_JSON_BODY
17#define BOOST_BEAST_EXAMPLE_JSON_BODY
18
19#include <boost/json.hpp>
20#include <boost/json/stream_parser.hpp>
21#include <boost/json/monotonic_resource.hpp>
22#include <boost/beast/http.hpp>
23#include <boost/asio/buffer.hpp>
24
25namespace json = boost::json;
26
27struct json_body
28{
29 using value_type = json::value;
30
31 struct writer
32 {
33 using const_buffers_type = boost::asio::const_buffer;
34 template<bool isRequest, class Fields>
35 writer(boost::beast::http::header<isRequest, Fields> const& h,
36 value_type const& body)
37 {
38 // The serializer holds a pointer to the value, so all we need to do is to reset it.
39 serializer.reset(p: &body);
40 }
41
42 void
43 init(boost::system::error_code& ec)
44 {
45 // The serializer always works, so no error can occur here.
46 ec = {};
47 }
48
49 boost::optional<std::pair<const_buffers_type, bool>>
50 get(boost::system::error_code& ec)
51 {
52 ec = {};
53 // We serialize as much as we can with the buffer. Often that'll suffice
54 const auto len = serializer.read(dest: buffer, size: sizeof(buffer));
55 return std::make_pair(
56 x: boost::asio::const_buffer(len.data(), len.size()),
57 y: !serializer.done());
58 }
59 private:
60 json::serializer serializer;
61 // half of the probable networking buffer, let's leave some space for headers
62 char buffer[32768];
63 };
64
65 struct reader
66 {
67 template<bool isRequest, class Fields>
68 reader(boost::beast::http::header<isRequest, Fields>& h, value_type& body)
69 : body(body)
70 {
71 }
72 void
73 init(
74 boost::optional<std::uint64_t> const& content_length,
75 boost::system::error_code& ec)
76 {
77
78 // If we know the content-length, we can allocate a monotonic resource to increase the parsing speed.
79 // We're using it rather then a static_resource, so a consumer can modify the resulting value.
80 // It is also only assumption that the parsed json will be smaller than the serialize one,
81 // it might not always be the case.
82 if (content_length)
83 parser.reset(sp: json::make_shared_resource<json::monotonic_resource>(args: *content_length));
84 ec = {};
85 }
86
87 template<class ConstBufferSequence>
88 std::size_t
89 put(ConstBufferSequence const& buffers, boost::system::error_code& ec)
90 {
91 ec = {};
92 // The parser just uses the `ec` to indicate errors, so we don't need to do anything.
93 return parser.write_some(
94 static_cast<const char*>(buffers.data()), buffers.size(), ec);
95 }
96
97 void
98 finish(boost::system::error_code& ec)
99 {
100 ec = {};
101 // We check manually if the json is complete.
102 if (parser.done())
103 body = parser.release();
104 else
105 ec = boost::json::error::incomplete;
106 }
107
108 private:
109 json::stream_parser parser;
110 value_type& body;
111 };
112};
113
114
115#endif

source code of boost/libs/beast/example/http/client/body/json_body.hpp