include/boost/burl/any_request_body.hpp

100.0% Lines (22/22) 100.0% List of functions (36/36) 100.0% Branches (1/1)
any_request_body.hpp
f(x) Functions (36)
Function Calls Lines Branches Blocks
boost::burl::any_request_body::base::~base() :53 46x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::file_body>::impl(boost::burl::(anonymous namespace)::file_body) :70 7x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::json_body>::impl(boost::burl::(anonymous namespace)::json_body) :70 5x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::string_body>::impl(boost::burl::(anonymous namespace)::string_body) :70 5x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::string_view_body>::impl(boost::burl::(anonymous namespace)::string_view_body) :70 4x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::multipart_form::body>::impl(boost::burl::multipart_form::body) :70 15x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::urlencoded_form::body>::impl(boost::burl::urlencoded_form::body) :70 10x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::file_body>::content_type() const :76 7x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::json_body>::content_type() const :76 5x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::string_body>::content_type() const :76 3x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::string_view_body>::content_type() const :76 4x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::multipart_form::body>::content_type[abi:cxx11]() const :76 15x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::urlencoded_form::body>::content_type[abi:cxx11]() const :76 10x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::file_body>::content_length() const :82 1x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::json_body>::content_length() const :82 5x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::string_body>::content_length() const :82 4x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::string_view_body>::content_length() const :82 4x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::multipart_form::body>::content_length() const :82 15x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::urlencoded_form::body>::content_length() const :82 10x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::file_body>::write(boost::capy::any_buffer_sink&) const :88 1x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::json_body>::write(boost::capy::any_buffer_sink&) const :88 30x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::string_body>::write(boost::capy::any_buffer_sink&) const :88 8x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::(anonymous namespace)::string_view_body>::write(boost::capy::any_buffer_sink&) const :88 14x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::multipart_form::body>::write(boost::capy::any_buffer_sink&) const :88 112x 100.0% 100.0% boost::burl::any_request_body::impl<boost::burl::urlencoded_form::body>::write(boost::capy::any_buffer_sink&) const :88 56x 100.0% 100.0% boost::burl::any_request_body::any_request_body() :113 6x 100.0% 100.0% boost::burl::any_request_body::any_request_body<boost::burl::(anonymous namespace)::file_body, void>(boost::burl::(anonymous namespace)::file_body) :135 7x 100.0% 100.0% 100.0% boost::burl::any_request_body::any_request_body<boost::burl::(anonymous namespace)::json_body, void>(boost::burl::(anonymous namespace)::json_body) :135 5x 100.0% 100.0% 100.0% boost::burl::any_request_body::any_request_body<boost::burl::(anonymous namespace)::string_body, void>(boost::burl::(anonymous namespace)::string_body) :135 5x 100.0% 100.0% 100.0% boost::burl::any_request_body::any_request_body<boost::burl::(anonymous namespace)::string_view_body, void>(boost::burl::(anonymous namespace)::string_view_body) :135 4x 100.0% 100.0% 100.0% boost::burl::any_request_body::any_request_body<boost::burl::multipart_form::body, void>(boost::burl::multipart_form::body) :135 15x 100.0% 100.0% 100.0% boost::burl::any_request_body::any_request_body<boost::burl::urlencoded_form::body, void>(boost::burl::urlencoded_form::body) :135 10x 100.0% 100.0% 100.0% boost::burl::any_request_body::has_value() const :149 119x 100.0% 100.0% boost::burl::any_request_body::content_type[abi:cxx11]() const :179 44x 100.0% 100.0% boost::burl::any_request_body::content_length() const :196 39x 100.0% 100.0% boost::burl::any_request_body::write(boost::capy::any_buffer_sink&) const :218 221x 100.0% 100.0%
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Mohammad Nejati
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/cppalliance/burl
8 //
9
10 #ifndef BOOST_BURL_ANY_REQUEST_BODY_HPP
11 #define BOOST_BURL_ANY_REQUEST_BODY_HPP
12
13 #include <boost/burl/detail/config.hpp>
14 #include <boost/burl/request_body.hpp>
15
16 #include <boost/capy/io/any_buffer_sink.hpp>
17 #include <boost/capy/io_task.hpp>
18
19 #include <cstdint>
20 #include <memory>
21 #include <optional>
22 #include <string>
23 #include <type_traits>
24 #include <utility>
25
26 namespace boost
27 {
28 namespace burl
29 {
30
31 /** A type-erased request body.
32
33 This wrapper owns an object satisfying
34 @ref RequestBody and forwards calls to it
35 through an internal interface, erasing the
36 concrete type. It is the body representation
37 stored in @ref request and produced by
38 `tag_invoke` overloads of @ref body_from_tag.
39
40 A default-constructed wrapper is empty and
41 represents a request without a body.
42
43 @see
44 @ref RequestBody,
45 @ref body_from_tag,
46 @ref request,
47 @ref request_builder::body.
48 */
49 class any_request_body
50 {
51 struct base
52 {
53 46x virtual ~base() = default;
54
55 virtual std::optional<std::string>
56 content_type() const = 0;
57
58 virtual std::optional<std::uint64_t>
59 content_length() const = 0;
60
61 virtual capy::io_task<>
62 write(capy::any_buffer_sink& sink) const = 0;
63 };
64
65 template<RequestBody T>
66 struct impl final : base
67 {
68 T body;
69
70 46x explicit impl(T b)
71 46x : body(std::move(b))
72 {
73 46x }
74
75 std::optional<std::string>
76 44x content_type() const override
77 {
78 44x return body.content_type();
79 }
80
81 std::optional<std::uint64_t>
82 39x content_length() const override
83 {
84 39x return body.content_length();
85 }
86
87 capy::io_task<>
88 221x write(capy::any_buffer_sink& sink) const override
89 {
90 221x return body.write(sink);
91 }
92 };
93
94 std::unique_ptr<base> impl_;
95
96 public:
97 /** Constructor.
98
99 A default-constructed wrapper contains no
100 body.
101
102 @par Postconditions
103 @code
104 this->has_value() == false
105 @endcode
106
107 @par Complexity
108 Constant.
109
110 @par Exception Safety
111 Throws nothing.
112 */
113 6x any_request_body() = default;
114
115 /** Constructor.
116
117 Constructs a wrapper which owns a copy of
118 `body`, erasing its concrete type.
119
120 @par Postconditions
121 @code
122 this->has_value() == true
123 @endcode
124
125 @par Exception Safety
126 Calls to allocate may throw.
127
128 @param body The body object to take
129 ownership of.
130 */
131 template<
132 RequestBody T,
133 typename = std::enable_if_t<
134 !std::is_same_v<std::remove_cvref_t<T>, any_request_body>>>
135 46x any_request_body(T body)
136
1/1
✓ Branch 2 taken 46 times.
46x : impl_(std::make_unique<impl<T>>(std::move(body)))
137 {
138 46x }
139
140 /** Return true if the wrapper contains a body.
141
142 @par Complexity
143 Constant.
144
145 @par Exception Safety
146 Throws nothing.
147 */
148 bool
149 119x has_value() const noexcept
150 {
151 119x return impl_ != nullptr;
152 }
153
154 /** Return true if the wrapper contains a body.
155
156 @par Complexity
157 Constant.
158
159 @par Exception Safety
160 Throws nothing.
161 */
162 explicit
163 operator bool() const noexcept
164 {
165 return has_value();
166 }
167
168 /** Return the value for the `Content-Type` header.
169
170 An empty `optional` indicates that no
171 `Content-Type` header should be sent.
172
173 @par Preconditions
174 @code
175 this->has_value() == true
176 @endcode
177 */
178 std::optional<std::string>
179 44x content_type() const
180 {
181 44x return impl_->content_type();
182 }
183
184 /** Return the size of the body in bytes.
185
186 An empty `optional` indicates that the size
187 is not known ahead of time, and the body
188 must be sent with chunked transfer encoding.
189
190 @par Preconditions
191 @code
192 this->has_value() == true
193 @endcode
194 */
195 std::optional<std::uint64_t>
196 39x content_length() const
197 {
198 39x return impl_->content_length();
199 }
200
201 /** Asynchronously write the body to a sink.
202
203 Serializes the body to `sink` incrementally.
204 This writes the body bytes but does not
205 signal end-of-stream; the caller finalizes
206 the sink once the body has been written.
207
208 @par Preconditions
209 @code
210 this->has_value() == true
211 @endcode
212
213 @param sink The sink to write to.
214
215 @return An awaitable yielding `(error_code)`.
216 */
217 capy::io_task<>
218 221x write(capy::any_buffer_sink& sink) const
219 {
220 221x return impl_->write(sink);
221 }
222 };
223
224 } // namespace burl
225 } // namespace boost
226
227 #endif
228