Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) | ||
3 | // Copyright (c) 2024 Christian Mazakas | ||
4 | // | ||
5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
7 | // | ||
8 | // Official repository: https://github.com/cppalliance/http_proto | ||
9 | // | ||
10 | |||
11 | #include <boost/http_proto/serializer.hpp> | ||
12 | #include <boost/http_proto/message_view_base.hpp> | ||
13 | #include <boost/http_proto/detail/except.hpp> | ||
14 | #include <boost/buffers/algorithm.hpp> | ||
15 | #include <boost/buffers/buffer_copy.hpp> | ||
16 | #include <boost/buffers/buffer_size.hpp> | ||
17 | #include <boost/core/ignore_unused.hpp> | ||
18 | #include <stddef.h> | ||
19 | |||
20 | namespace boost { | ||
21 | namespace http_proto { | ||
22 | |||
23 | //------------------------------------------------ | ||
24 | |||
25 | void | ||
26 | ✗ | consume_buffers( | |
27 | buffers::const_buffer*& p, | ||
28 | std::size_t& n, | ||
29 | std::size_t bytes) | ||
30 | { | ||
31 | ✗ | while(n > 0) | |
32 | { | ||
33 | ✗ | if(bytes < p->size()) | |
34 | { | ||
35 | ✗ | *p += bytes; | |
36 | ✗ | return; | |
37 | } | ||
38 | ✗ | bytes -= p->size(); | |
39 | ✗ | ++p; | |
40 | ✗ | --n; | |
41 | } | ||
42 | |||
43 | // Precondition violation | ||
44 | ✗ | if(bytes > 0) | |
45 | ✗ | detail::throw_invalid_argument(); | |
46 | } | ||
47 | |||
48 | template<class MutableBuffers> | ||
49 | void | ||
50 | 54 | write_chunk_header( | |
51 | MutableBuffers const& dest0, | ||
52 | std::size_t size) noexcept | ||
53 | { | ||
54 | static constexpr char hexdig[] = | ||
55 | "0123456789ABCDEF"; | ||
56 | char buf[18]; | ||
57 | 54 | auto p = buf + 16; | |
58 |
2/2✓ Branch 0 taken 432 times.
✓ Branch 1 taken 27 times.
|
918 | for(std::size_t i = 16; i--;) |
59 | { | ||
60 | 864 | *--p = hexdig[size & 0xf]; | |
61 | 864 | size >>= 4; | |
62 | } | ||
63 | 54 | buf[16] = '\r'; | |
64 | 54 | buf[17] = '\n'; | |
65 | 54 | auto n = buffers::buffer_copy( | |
66 | dest0, | ||
67 | buffers::const_buffer( | ||
68 | buf, sizeof(buf))); | ||
69 | ignore_unused(n); | ||
70 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
|
54 | BOOST_ASSERT(n == 18); |
71 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
|
54 | BOOST_ASSERT( |
72 | buffers::buffer_size(dest0) == n); | ||
73 | 54 | } | |
74 | |||
75 | template<class DynamicBuffer> | ||
76 | void | ||
77 | 19 | write_chunk_close(DynamicBuffer& db) | |
78 | { | ||
79 | 38 | db.commit( | |
80 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | buffers::buffer_copy( |
81 | db.prepare(2), | ||
82 | buffers::const_buffer("\r\n", 2))); | ||
83 | 19 | } | |
84 | |||
85 | template<class DynamicBuffer> | ||
86 | void | ||
87 | 3 | write_last_chunk(DynamicBuffer& db) | |
88 | { | ||
89 | 6 | db.commit( | |
90 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | buffers::buffer_copy( |
91 | db.prepare(5), | ||
92 | buffers::const_buffer("0\r\n\r\n", 5))); | ||
93 | 3 | } | |
94 | |||
95 | //------------------------------------------------ | ||
96 | |||
97 | 20 | serializer:: | |
98 | 20 | ~serializer() | |
99 | { | ||
100 | 20 | } | |
101 | |||
102 | 9 | serializer:: | |
103 | 9 | serializer() | |
104 | 9 | : serializer(65536) | |
105 | { | ||
106 | 9 | } | |
107 | |||
108 | serializer:: | ||
109 | serializer( | ||
110 | serializer&&) noexcept = default; | ||
111 | |||
112 | 20 | serializer:: | |
113 | serializer( | ||
114 | 20 | std::size_t buffer_size) | |
115 | 20 | : ws_(buffer_size) | |
116 | { | ||
117 | 20 | } | |
118 | |||
119 | void | ||
120 | ✗ | serializer:: | |
121 | reset() noexcept | ||
122 | { | ||
123 | ✗ | } | |
124 | |||
125 | //------------------------------------------------ | ||
126 | |||
127 | auto | ||
128 | 67 | serializer:: | |
129 | prepare() -> | ||
130 | system::result< | ||
131 | const_buffers_type> | ||
132 | { | ||
133 | // Precondition violation | ||
134 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 66 times.
|
67 | if(is_done_) |
135 | 1 | detail::throw_logic_error(); | |
136 | |||
137 | // Expect: 100-continue | ||
138 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 62 times.
|
66 | if(is_expect_continue_) |
139 | { | ||
140 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
4 | if(out_.data() == hp_) |
141 | 2 | return const_buffers_type(hp_, 1); | |
142 | 2 | is_expect_continue_ = false; | |
143 | 2 | BOOST_HTTP_PROTO_RETURN_EC( | |
144 | error::expect_100_continue); | ||
145 | } | ||
146 | |||
147 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 59 times.
|
62 | if(st_ == style::empty) |
148 | { | ||
149 | 9 | return const_buffers_type( | |
150 | 3 | out_.data(), | |
151 | 3 | out_.size()); | |
152 | } | ||
153 | |||
154 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 56 times.
|
59 | if(st_ == style::buffers) |
155 | { | ||
156 | 9 | return const_buffers_type( | |
157 | 3 | out_.data(), | |
158 | 3 | out_.size()); | |
159 | } | ||
160 | |||
161 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 34 times.
|
56 | if(st_ == style::source) |
162 | { | ||
163 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 5 times.
|
22 | if(more_) |
164 | { | ||
165 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 8 times.
|
17 | if(! is_chunked_) |
166 | { | ||
167 | 9 | auto rv = src_->read( | |
168 |
2/4✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
|
9 | tmp0_.prepare(tmp0_.capacity())); |
169 | 9 | tmp0_.commit(rv.bytes); | |
170 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
|
9 | if(rv.ec.failed()) |
171 | ✗ | return rv.ec; | |
172 | 9 | more_ = ! rv.finished; | |
173 | } | ||
174 | else | ||
175 | { | ||
176 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | if(tmp0_.capacity() > chunked_overhead_) |
177 | { | ||
178 | auto dest = tmp0_.prepare( | ||
179 | 8 | tmp0_.capacity() - | |
180 | 2 - // CRLF | ||
181 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | 5); // final chunk |
182 | |||
183 | 8 | auto rv = src_->read( | |
184 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | buffers::sans_prefix(dest, 18)); |
185 | |||
186 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
|
8 | if(rv.ec.failed()) |
187 | ✗ | return rv.ec; | |
188 | |||
189 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
|
8 | if(rv.bytes != 0) |
190 | { | ||
191 | 7 | write_chunk_header( | |
192 | 7 | buffers::prefix(dest, 18), rv.bytes); | |
193 | 7 | tmp0_.commit(rv.bytes + 18); | |
194 | // terminate chunk | ||
195 | 7 | tmp0_.commit( | |
196 | buffers::buffer_copy( | ||
197 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | tmp0_.prepare(2), |
198 | 14 | buffers::const_buffer( | |
199 | "\r\n", 2))); | ||
200 | } | ||
201 | |||
202 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
|
8 | if(rv.finished) |
203 | { | ||
204 | 2 | tmp0_.commit( | |
205 | buffers::buffer_copy( | ||
206 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | tmp0_.prepare(5), |
207 | 2 | buffers::const_buffer( | |
208 | "0\r\n\r\n", 5))); | ||
209 | 2 | more_ = false; | |
210 | } | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | |||
215 | 22 | std::size_t n = 0; | |
216 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 17 times.
|
22 | if(out_.data() == hp_) |
217 | 5 | ++n; | |
218 |
2/2✓ Branch 3 taken 44 times.
✓ Branch 4 taken 22 times.
|
66 | for(buffers::const_buffer const& b : tmp0_.data()) |
219 | 44 | out_[n++] = b; | |
220 | |||
221 | 66 | return const_buffers_type( | |
222 | 22 | out_.data(), | |
223 | 22 | out_.size()); | |
224 | } | ||
225 | |||
226 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | if(st_ == style::stream) |
227 | { | ||
228 | 34 | std::size_t n = 0; | |
229 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 28 times.
|
34 | if(out_.data() == hp_) |
230 | 6 | ++n; | |
231 |
6/6✓ Branch 1 taken 2 times.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 33 times.
|
34 | if(tmp0_.size() == 0 && more_) |
232 | { | ||
233 | 1 | BOOST_HTTP_PROTO_RETURN_EC( | |
234 | error::need_data); | ||
235 | } | ||
236 |
2/2✓ Branch 3 taken 66 times.
✓ Branch 4 taken 33 times.
|
99 | for(buffers::const_buffer const& b : tmp0_.data()) |
237 | 66 | out_[n++] = b; | |
238 | |||
239 | 99 | return const_buffers_type( | |
240 | 33 | out_.data(), | |
241 | 33 | out_.size()); | |
242 | } | ||
243 | |||
244 | // should never get here | ||
245 | ✗ | detail::throw_logic_error(); | |
246 | } | ||
247 | |||
248 | void | ||
249 | 1745 | serializer:: | |
250 | consume( | ||
251 | std::size_t n) | ||
252 | { | ||
253 | // Precondition violation | ||
254 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1744 times.
|
1745 | if(is_done_) |
255 | 1 | detail::throw_logic_error(); | |
256 | |||
257 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1741 times.
|
1744 | if(is_expect_continue_) |
258 | { | ||
259 | // Cannot consume more than | ||
260 | // the header on 100-continue | ||
261 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
|
3 | if(n > hp_->size()) |
262 | 1 | detail::throw_invalid_argument(); | |
263 | |||
264 | 2 | out_.consume(n); | |
265 | 2 | return; | |
266 | } | ||
267 |
2/2✓ Branch 1 taken 26 times.
✓ Branch 2 taken 1715 times.
|
1741 | else if(out_.data() == hp_) |
268 | { | ||
269 | // consume header | ||
270 |
2/2✓ Branch 1 taken 11 times.
✓ Branch 2 taken 15 times.
|
26 | if(n < hp_->size()) |
271 | { | ||
272 | 11 | out_.consume(n); | |
273 | 11 | return; | |
274 | } | ||
275 | 15 | n -= hp_->size(); | |
276 | 15 | out_.consume(hp_->size()); | |
277 | } | ||
278 | |||
279 |
3/3✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1724 times.
|
1730 | switch(st_) |
280 | { | ||
281 | 3 | default: | |
282 | case style::empty: | ||
283 | 3 | out_.consume(n); | |
284 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | if(out_.empty()) |
285 | 3 | is_done_ = true; | |
286 | 3 | return; | |
287 | |||
288 | 3 | case style::buffers: | |
289 | 3 | out_.consume(n); | |
290 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | if(out_.empty()) |
291 | 3 | is_done_ = true; | |
292 | 3 | return; | |
293 | |||
294 | 1724 | case style::source: | |
295 | case style::stream: | ||
296 | 1724 | tmp0_.consume(n); | |
297 |
4/4✓ Branch 1 taken 39 times.
✓ Branch 2 taken 1685 times.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 1713 times.
|
1763 | if( tmp0_.size() == 0 && |
298 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 28 times.
|
39 | ! more_) |
299 | 11 | is_done_ = true; | |
300 | 1724 | return; | |
301 | } | ||
302 | } | ||
303 | |||
304 | //------------------------------------------------ | ||
305 | |||
306 | void | ||
307 | 14 | serializer:: | |
308 | copy( | ||
309 | buffers::const_buffer* dest, | ||
310 | buffers::const_buffer const* src, | ||
311 | std::size_t n) noexcept | ||
312 | { | ||
313 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
|
14 | while(n--) |
314 | 7 | *dest++ = *src++; | |
315 | 7 | } | |
316 | |||
317 | void | ||
318 | 26 | serializer:: | |
319 | start_init( | ||
320 | message_view_base const& m) | ||
321 | { | ||
322 | 26 | ws_.clear(); | |
323 | |||
324 | // VFALCO what do we do with | ||
325 | // metadata error code failures? | ||
326 | // m.ph_->md.maybe_throw(); | ||
327 | |||
328 | 26 | is_done_ = false; | |
329 | |||
330 | 26 | is_expect_continue_ = | |
331 | 26 | m.ph_->md.expect.is_100_continue; | |
332 | |||
333 | // Transfer-Encoding | ||
334 | { | ||
335 | 26 | auto const& te = | |
336 | 26 | m.ph_->md.transfer_encoding; | |
337 | 26 | is_chunked_ = te.is_chunked; | |
338 | } | ||
339 | 26 | } | |
340 | |||
341 | void | ||
342 | 4 | serializer:: | |
343 | start_empty( | ||
344 | message_view_base const& m) | ||
345 | { | ||
346 | 4 | start_init(m); | |
347 | |||
348 | 4 | st_ = style::empty; | |
349 | |||
350 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | if(! is_chunked_) |
351 | { | ||
352 | out_ = make_array( | ||
353 | 3 | 1); // header | |
354 | } | ||
355 | else | ||
356 | { | ||
357 | out_ = make_array( | ||
358 | 1 + // header | ||
359 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | 1); // final chunk |
360 | |||
361 | // Buffer is too small | ||
362 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if(ws_.size() < 5) |
363 | ✗ | detail::throw_length_error(); | |
364 | |||
365 | buffers::mutable_buffer dest( | ||
366 | 1 | ws_.data(), 5); | |
367 | 1 | buffers::buffer_copy( | |
368 | dest, | ||
369 | 1 | buffers::const_buffer( | |
370 | "0\r\n\r\n", 5)); | ||
371 | 1 | out_[1] = dest; | |
372 | } | ||
373 | |||
374 | 4 | hp_ = &out_[0]; | |
375 | 4 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
376 | 4 | } | |
377 | |||
378 | void | ||
379 | 7 | serializer:: | |
380 | start_buffers( | ||
381 | message_view_base const& m) | ||
382 | { | ||
383 | 7 | st_ = style::buffers; | |
384 | |||
385 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
|
7 | if(! is_chunked_) |
386 | { | ||
387 | //if(! cod_) | ||
388 | { | ||
389 | out_ = make_array( | ||
390 | 1 + // header | ||
391 | 6 | buf_.size()); // body | |
392 | 12 | copy(&out_[1], | |
393 | 6 | buf_.data(), buf_.size()); | |
394 | } | ||
395 | #if 0 | ||
396 | else | ||
397 | { | ||
398 | out_ = make_array( | ||
399 | 1 + // header | ||
400 | 2); // tmp1 | ||
401 | } | ||
402 | #endif | ||
403 | } | ||
404 | else | ||
405 | { | ||
406 | //if(! cod_) | ||
407 | { | ||
408 | out_ = make_array( | ||
409 | 1 + // header | ||
410 | 1 + // chunk size | ||
411 | 1 | buf_.size() + // body | |
412 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | 1); // final chunk |
413 | 2 | copy(&out_[2], | |
414 | 1 | buf_.data(), buf_.size()); | |
415 | |||
416 | // Buffer is too small | ||
417 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if(ws_.size() < 18 + 7) |
418 | ✗ | detail::throw_length_error(); | |
419 | 1 | buffers::mutable_buffer s1(ws_.data(), 18); | |
420 | 1 | buffers::mutable_buffer s2(ws_.data(), 18 + 7); | |
421 | 1 | s2 += 18; // VFALCO HACK | |
422 | 1 | write_chunk_header( | |
423 | s1, | ||
424 | 1 | buffers::buffer_size(buf_)); | |
425 | 1 | buffers::buffer_copy(s2, buffers::const_buffer( | |
426 | "\r\n" | ||
427 | "0\r\n" | ||
428 | "\r\n", 7)); | ||
429 | 1 | out_[1] = s1; | |
430 | 1 | out_[out_.size() - 1] = s2; | |
431 | } | ||
432 | #if 0 | ||
433 | else | ||
434 | { | ||
435 | out_ = make_array( | ||
436 | 1 + // header | ||
437 | 2); // tmp1 | ||
438 | } | ||
439 | #endif | ||
440 | } | ||
441 | |||
442 | 7 | hp_ = &out_[0]; | |
443 | 7 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
444 | 7 | } | |
445 | |||
446 | void | ||
447 | 8 | serializer:: | |
448 | start_source( | ||
449 | message_view_base const& m, | ||
450 | source* src) | ||
451 | { | ||
452 | 8 | st_ = style::source; | |
453 | 8 | src_ = src; | |
454 | out_ = make_array( | ||
455 | 1 + // header | ||
456 | 8 | 2); // tmp | |
457 | //if(! cod_) | ||
458 | { | ||
459 | 8 | tmp0_ = { ws_.data(), ws_.size() }; | |
460 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
|
8 | if(tmp0_.capacity() < |
461 | 18 + // chunk size | ||
462 | 1 + // body (1 byte) | ||
463 | 2 + // CRLF | ||
464 | 5) // final chunk | ||
465 | ✗ | detail::throw_length_error(); | |
466 | } | ||
467 | #if 0 | ||
468 | else | ||
469 | { | ||
470 | buffers::buffered_base::allocator a( | ||
471 | ws_.data(), ws_.size()/3, false); | ||
472 | src->init(a); | ||
473 | ws_.reserve(a.size_used()); | ||
474 | |||
475 | auto const n = ws_.size() / 2; | ||
476 | |||
477 | tmp0_ = { ws_.data(), ws_.size() / 2 }; | ||
478 | ws_.reserve(n); | ||
479 | |||
480 | // Buffer is too small | ||
481 | if(ws_.size() < 1) | ||
482 | detail::throw_length_error(); | ||
483 | |||
484 | tmp1_ = { ws_.data(), ws_.size() }; | ||
485 | } | ||
486 | #endif | ||
487 | |||
488 | 8 | hp_ = &out_[0]; | |
489 | 8 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
490 | 8 | more_ = true; | |
491 | 8 | } | |
492 | |||
493 | auto | ||
494 | 7 | serializer:: | |
495 | start_stream( | ||
496 | message_view_base const& m) -> | ||
497 | stream | ||
498 | { | ||
499 | 7 | start_init(m); | |
500 | |||
501 | 7 | st_ = style::stream; | |
502 | out_ = make_array( | ||
503 | 1 + // header | ||
504 | 7 | 2); // tmp | |
505 | //if(! cod_) | ||
506 | { | ||
507 | 7 | tmp0_ = { ws_.data(), ws_.size() }; | |
508 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | if(tmp0_.capacity() < |
509 | 18 + // chunk size | ||
510 | 1 + // body (1 byte) | ||
511 | 2 + // CRLF | ||
512 | 5) // final chunk | ||
513 | ✗ | detail::throw_length_error(); | |
514 | } | ||
515 | #if 0 | ||
516 | else | ||
517 | { | ||
518 | auto const n = ws_.size() / 2; | ||
519 | tmp0_ = { ws_.data(), n }; | ||
520 | ws_.reserve(n); | ||
521 | |||
522 | // Buffer is too small | ||
523 | if(ws_.size() < 1) | ||
524 | detail::throw_length_error(); | ||
525 | |||
526 | tmp1_ = { ws_.data(), ws_.size() }; | ||
527 | } | ||
528 | #endif | ||
529 | |||
530 | 7 | hp_ = &out_[0]; | |
531 | 7 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
532 | |||
533 | 7 | more_ = true; | |
534 | |||
535 | 7 | return stream{*this}; | |
536 | } | ||
537 | |||
538 | //------------------------------------------------ | ||
539 | |||
540 | std::size_t | ||
541 | 140 | serializer:: | |
542 | stream:: | ||
543 | capacity() const noexcept | ||
544 | { | ||
545 | 140 | return sr_->tmp0_.capacity(); | |
546 | } | ||
547 | |||
548 | std::size_t | ||
549 | 132 | serializer:: | |
550 | stream:: | ||
551 | size() const noexcept | ||
552 | { | ||
553 | 132 | return sr_->tmp0_.size(); | |
554 | } | ||
555 | |||
556 | bool | ||
557 | 66 | serializer:: | |
558 | stream:: | ||
559 | is_full() const noexcept | ||
560 | { | ||
561 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 30 times.
|
66 | if( sr_->is_chunked_ ) |
562 | 36 | return capacity() < chunked_overhead_ + 1; | |
563 | |||
564 | 30 | return capacity() == 0; | |
565 | } | ||
566 | |||
567 | auto | ||
568 | 36 | serializer:: | |
569 | stream:: | ||
570 | prepare() const -> | ||
571 | buffers_type | ||
572 | { | ||
573 | 36 | auto n = sr_->tmp0_.capacity(); | |
574 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 15 times.
|
36 | if( sr_->is_chunked_ ) |
575 | { | ||
576 | // for chunked encoding, we want to unconditionally | ||
577 | // reserve space for the complete chunk and the | ||
578 | // last-chunk | ||
579 | // this enables users to call: | ||
580 | // | ||
581 | // stream.commit(n); stream.close(); | ||
582 | // | ||
583 | // without needing to worry about draining the | ||
584 | // serializer via `consume()` calls | ||
585 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 20 times.
|
21 | if( n < chunked_overhead_ + 1 ) |
586 | 1 | detail::throw_length_error(); | |
587 | |||
588 | 20 | n -= chunked_overhead_; | |
589 | return buffers::sans_prefix( | ||
590 | 40 | sr_->tmp0_.prepare(chunk_header_len_ + n), | |
591 | 20 | chunk_header_len_); | |
592 | } | ||
593 | |||
594 | 15 | return sr_->tmp0_.prepare(n); | |
595 | } | ||
596 | |||
597 | void | ||
598 | 35 | serializer:: | |
599 | stream:: | ||
600 | commit(std::size_t n) const | ||
601 | { | ||
602 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 20 times.
|
35 | if(! sr_->is_chunked_ ) |
603 | { | ||
604 | 15 | sr_->tmp0_.commit(n); | |
605 | } | ||
606 | else | ||
607 | { | ||
608 | // Zero sized chunks are not valid. Call close() | ||
609 | // if the intent is to signal the end of the body. | ||
610 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 19 times.
|
20 | if( n == 0 ) |
611 | 1 | detail::throw_logic_error(); | |
612 | |||
613 | 19 | auto m = n + chunk_header_len_; | |
614 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | auto dest = sr_->tmp0_.prepare(m); |
615 | 19 | write_chunk_header( | |
616 | 19 | buffers::prefix(dest, chunk_header_len_), n); | |
617 | 19 | sr_->tmp0_.commit(m); | |
618 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | write_chunk_close(sr_->tmp0_); |
619 | } | ||
620 | 34 | } | |
621 | |||
622 | void | ||
623 | 9 | serializer:: | |
624 | stream:: | ||
625 | close() const | ||
626 | { | ||
627 | // Precondition violation | ||
628 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
|
9 | if(! sr_->more_ ) |
629 | 4 | detail::throw_logic_error(); | |
630 | |||
631 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
|
5 | if( sr_->is_chunked_ ) |
632 | 3 | write_last_chunk(sr_->tmp0_); | |
633 | |||
634 | 5 | sr_->more_ = false; | |
635 | 5 | } | |
636 | |||
637 | //------------------------------------------------ | ||
638 | |||
639 | } // http_proto | ||
640 | } // boost | ||
641 |