GCC Code Coverage Report


Directory: libs/http_proto/
File: boost/http_proto/serializer.hpp
Date: 2024-04-04 20:17:10
Exec Total Coverage
Lines: 37 38 97.4%
Functions: 16 17 94.1%
Branches: 3 4 75.0%

Line Branch Exec Source
1 //
2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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/cppalliance/http_proto
8 //
9
10 #ifndef BOOST_HTTP_PROTO_SERIALIZER_HPP
11 #define BOOST_HTTP_PROTO_SERIALIZER_HPP
12
13 #include <boost/http_proto/detail/config.hpp>
14 #include <boost/http_proto/source.hpp>
15 #include <boost/http_proto/detail/array_of_buffers.hpp>
16 #include <boost/http_proto/detail/except.hpp>
17 #include <boost/http_proto/detail/header.hpp>
18 #include <boost/http_proto/detail/workspace.hpp>
19 #include <boost/buffers/circular_buffer.hpp>
20 #include <boost/buffers/range.hpp>
21 #include <boost/buffers/type_traits.hpp>
22 #include <boost/system/result.hpp>
23 #include <cstdint>
24 #include <memory>
25 #include <type_traits>
26 #include <utility>
27
28 namespace boost {
29 namespace http_proto {
30
31 #ifndef BOOST_HTTP_PROTO_DOCS
32 class request;
33 class response;
34 class request_view;
35 class response_view;
36 class message_view_base;
37 #endif
38
39 /** A serializer for HTTP/1 messages
40
41 This is used to serialize one or more complete
42 HTTP/1 messages. Each message consists of a
43 required header followed by an optional body.
44 */
45 class BOOST_SYMBOL_VISIBLE
46 serializer
47 {
48 public:
49 /** A ConstBuffers representing the output
50 */
51 class const_buffers_type;
52
53 struct stream;
54
55 /** Destructor
56 */
57 BOOST_HTTP_PROTO_DECL
58 ~serializer();
59
60 /** Constructor
61 */
62 BOOST_HTTP_PROTO_DECL
63 serializer();
64
65 /** Constructor
66 */
67 BOOST_HTTP_PROTO_DECL
68 serializer(
69 serializer&&) noexcept;
70
71 /** Constructor
72 */
73 BOOST_HTTP_PROTO_DECL
74 explicit
75 serializer(
76 std::size_t buffer_size);
77
78 //--------------------------------------------
79
80 /** Prepare the serializer for a new stream
81 */
82 BOOST_HTTP_PROTO_DECL
83 void
84 reset() noexcept;
85
86 /** Prepare the serializer for a new message
87
88 The message will not contain a body.
89 Changing the contents of the message
90 after calling this function and before
91 @ref is_done returns `true` results in
92 undefined behavior.
93 */
94 void
95 4 start(
96 message_view_base const& m)
97 {
98 4 start_empty(m);
99 4 }
100
101 /** Prepare the serializer for a new message
102
103 Changing the contents of the message
104 after calling this function and before
105 @ref is_done returns `true` results in
106 undefined behavior.
107
108 @par Constraints
109 @code
110 is_const_buffers< ConstBuffers >::value == true
111 @endcode
112 */
113 template<
114 class ConstBufferSequence
115 #ifndef BOOST_HTTP_PROTO_DOCS
116 ,class = typename
117 std::enable_if<
118 buffers::is_const_buffer_sequence<
119 ConstBufferSequence>::value
120 >::type
121 #endif
122 >
123 void
124 start(
125 message_view_base const& m,
126 ConstBufferSequence&& body);
127
128 /** Prepare the serializer for a new message
129
130 Changing the contents of the message
131 after calling this function and before
132 @ref is_done returns `true` results in
133 undefined behavior.
134 */
135 template<
136 class Source,
137 class... Args
138 #ifndef BOOST_HTTP_PROTO_DOCS
139 ,class = typename std::enable_if<
140 is_source<Source>::value>::type
141 #endif
142 >
143 Source&
144 start(
145 message_view_base const& m,
146 Args&&... args);
147
148 //--------------------------------------------
149
150 BOOST_HTTP_PROTO_DECL
151 stream
152 start_stream(
153 message_view_base const& m);
154
155 //--------------------------------------------
156
157 /** Return true if serialization is complete.
158 */
159 bool
160 88 is_done() const noexcept
161 {
162 88 return is_done_;
163 }
164
165 /** Return the output area.
166
167 This function will serialize some or
168 all of the content and return the
169 corresponding output buffers.
170
171 @par Preconditions
172 @code
173 this->is_done() == false
174 @endcode
175 */
176 BOOST_HTTP_PROTO_DECL
177 auto
178 prepare() ->
179 system::result<
180 const_buffers_type>;
181
182 /** Consume bytes from the output area.
183 */
184 BOOST_HTTP_PROTO_DECL
185 void
186 consume(std::size_t n);
187
188 private:
189 static void copy(
190 buffers::const_buffer*,
191 buffers::const_buffer const*,
192 std::size_t n) noexcept;
193 auto
194 make_array(std::size_t n) ->
195 detail::array_of_const_buffers;
196
197 template<
198 class Source,
199 class... Args,
200 typename std::enable_if<
201 std::is_constructible<
202 Source,
203 Args...>::value>::type* = nullptr>
204 Source&
205 16 construct_source(Args&&... args)
206 {
207 return ws_.emplace<Source>(
208 16 std::forward<Args>(args)...);
209 }
210
211 template<
212 class Source,
213 class... Args,
214 typename std::enable_if<
215 std::is_constructible<
216 Source,
217 buffered_base::allocator&,
218 Args...>::value>::type* = nullptr>
219 Source&
220 construct_source(Args&&... args)
221 {
222 buffered_base::allocator a(
223 ws_.data(),
224 (ws_.size() - ws_.space_needed<Source>()) / 2,
225 false);
226 auto& src = ws_.emplace<Source>(
227 a, std::forward<Args>(args)...);
228 ws_.reserve_front(a.size_used());
229 return src;
230 }
231
232 BOOST_HTTP_PROTO_DECL void start_init(message_view_base const&);
233 BOOST_HTTP_PROTO_DECL void start_empty(message_view_base const&);
234 BOOST_HTTP_PROTO_DECL void start_buffers(message_view_base const&);
235 BOOST_HTTP_PROTO_DECL void start_source(message_view_base const&, source*);
236
237 enum class style
238 {
239 empty,
240 buffers,
241 source,
242 stream
243 };
244
245 // chunked-body = *chunk
246 // last-chunk
247 // trailer-section
248 // CRLF
249
250 // chunk = chunk-size [ chunk-ext ] CRLF
251 // chunk-data CRLF
252 static
253 constexpr
254 std::size_t
255 chunk_header_len_ = 16 + 2; // chunk-size + CRLF
256
257 // last-chunk = 1*("0") [ chunk-ext ] CRLF
258 static
259 constexpr
260 std::size_t
261 last_chunk_len_ = 1 + 2 + 2; // chunked-body termination requires an extra CRLF
262
263 static
264 constexpr
265 std::size_t
266 chunked_overhead_ =
267 chunk_header_len_ +
268 2 + // CRLF
269 last_chunk_len_;
270
271 detail::workspace ws_;
272 detail::array_of_const_buffers buf_;
273 source* src_;
274
275 buffers::circular_buffer tmp0_;
276 buffers::circular_buffer tmp1_;
277 detail::array_of_const_buffers out_;
278
279 buffers::const_buffer* hp_; // header
280
281 style st_;
282 bool more_;
283 bool is_done_;
284 bool is_chunked_;
285 bool is_expect_continue_;
286 };
287
288 //------------------------------------------------
289
290 struct serializer::stream
291 {
292 /** Constructor.
293 */
294 stream() = default;
295
296 /** Constructor.
297 */
298 stream(stream const&) = default;
299
300 /** Constructor.
301 */
302 stream& operator=
303 (stream const&) = default;
304
305 using buffers_type =
306 buffers::mutable_buffer_pair;
307
308 BOOST_HTTP_PROTO_DECL
309 std::size_t
310 capacity() const;
311
312 BOOST_HTTP_PROTO_DECL
313 std::size_t
314 size() const;
315
316 BOOST_HTTP_PROTO_DECL
317 buffers_type
318 prepare(std::size_t n) const;
319
320 BOOST_HTTP_PROTO_DECL
321 void
322 commit(std::size_t n) const;
323
324 BOOST_HTTP_PROTO_DECL
325 void
326 close() const;
327
328 private:
329 friend class serializer;
330
331 explicit
332 6 stream(
333 serializer& sr) noexcept
334 6 : sr_(&sr)
335 {
336 6 }
337
338 serializer* sr_ = nullptr;
339 };
340
341 //---------------------------------------------------------
342
343 class serializer::
344 const_buffers_type
345 {
346 std::size_t n_ = 0;
347 buffers::const_buffer const* p_ = nullptr;
348
349 friend class serializer;
350
351 74 const_buffers_type(
352 buffers::const_buffer const* p,
353 std::size_t n) noexcept
354 74 : n_(n)
355 74 , p_(p)
356 {
357 74 }
358
359 public:
360 using iterator = buffers::const_buffer const*;
361 using const_iterator = iterator;
362 using value_type = buffers::const_buffer;
363 using reference = buffers::const_buffer;
364 using const_reference = buffers::const_buffer;
365 using size_type = std::size_t;
366 using difference_type = std::ptrdiff_t;
367
368 const_buffers_type() = default;
369 const_buffers_type(
370 const_buffers_type const&) = default;
371 const_buffers_type& operator=(
372 const_buffers_type const&) = default;
373
374 iterator
375 148 begin() const noexcept
376 {
377 148 return p_;
378 }
379
380 iterator
381 148 end() const noexcept
382 {
383 148 return p_ + n_;
384 }
385 };
386
387 //------------------------------------------------
388
389 template<
390 class ConstBufferSequence,
391 class>
392 void
393 14 serializer::
394 start(
395 message_view_base const& m,
396 ConstBufferSequence&& body)
397 {
398 14 start_init(m);
399 14 auto const& bs =
400 ws_.emplace<ConstBufferSequence>(
401 std::forward<ConstBufferSequence>(body));
402 14 std::size_t n = std::distance(
403 buffers::begin(bs),
404 buffers::end(bs));
405 14 buf_ = make_array(n);
406 14 auto p = buf_.data();
407
2/2
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 7 times.
28 for(buffers::const_buffer b :
408 14 buffers::range(bs))
409 14 *p++ = b;
410 14 start_buffers(m);
411 14 }
412
413 template<
414 class Source,
415 class... Args,
416 class>
417 Source&
418 16 serializer::
419 start(
420 message_view_base const& m,
421 Args&&... args)
422 {
423 static_assert(
424 std::is_constructible<Source, Args...>::value ||
425 std::is_constructible<Source, buffered_base::allocator&, Args...>::value,
426 "The Source cannot be constructed with the given arguments");
427
428 16 start_init(m);
429 16 auto& src = construct_source<Source>(
430 std::forward<Args>(args)...);
431 16 start_source(m, std::addressof(src));
432 16 return src;
433 }
434
435 //------------------------------------------------
436
437 inline
438 auto
439 32 serializer::
440 make_array(std::size_t n) ->
441 detail::array_of_const_buffers
442 {
443 return {
444 ws_.push_array(n,
445 64 buffers::const_buffer{}),
446
1/2
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
32 n };
447 }
448
449 } // http_proto
450 } // boost
451
452 #endif
453