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/filter.hpp> | ||
14 | #include <boost/http_proto/detail/except.hpp> | ||
15 | #include <boost/buffers/algorithm.hpp> | ||
16 | #include <boost/buffers/buffer_copy.hpp> | ||
17 | #include <boost/buffers/buffer_size.hpp> | ||
18 | #include <boost/core/ignore_unused.hpp> | ||
19 | #include <stddef.h> | ||
20 | |||
21 | #include "zlib_service.hpp" | ||
22 | |||
23 | namespace boost { | ||
24 | namespace http_proto { | ||
25 | |||
26 | //------------------------------------------------ | ||
27 | |||
28 | void | ||
29 | ✗ | consume_buffers( | |
30 | buffers::const_buffer*& p, | ||
31 | std::size_t& n, | ||
32 | std::size_t bytes) | ||
33 | { | ||
34 | ✗ | while(n > 0) | |
35 | { | ||
36 | ✗ | if(bytes < p->size()) | |
37 | { | ||
38 | ✗ | *p += bytes; | |
39 | ✗ | return; | |
40 | } | ||
41 | ✗ | bytes -= p->size(); | |
42 | ✗ | ++p; | |
43 | ✗ | --n; | |
44 | } | ||
45 | |||
46 | // Precondition violation | ||
47 | ✗ | if(bytes > 0) | |
48 | ✗ | detail::throw_invalid_argument(); | |
49 | } | ||
50 | |||
51 | template<class MutableBuffers> | ||
52 | void | ||
53 | 6296 | write_chunk_header( | |
54 | MutableBuffers const& dest0, | ||
55 | std::size_t size) noexcept | ||
56 | { | ||
57 | static constexpr char hexdig[] = | ||
58 | "0123456789ABCDEF"; | ||
59 | char buf[18]; | ||
60 | 6296 | auto p = buf + 16; | |
61 |
2/2✓ Branch 0 taken 100736 times.
✓ Branch 1 taken 6296 times.
|
107032 | for(std::size_t i = 16; i--;) |
62 | { | ||
63 | 100736 | *--p = hexdig[size & 0xf]; | |
64 | 100736 | size >>= 4; | |
65 | } | ||
66 | 6296 | buf[16] = '\r'; | |
67 | 6296 | buf[17] = '\n'; | |
68 | 6296 | auto n = buffers::buffer_copy( | |
69 | dest0, | ||
70 | 12592 | buffers::const_buffer( | |
71 | buf, sizeof(buf))); | ||
72 | ignore_unused(n); | ||
73 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6296 times.
|
6296 | BOOST_ASSERT(n == 18); |
74 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6296 times.
|
6296 | BOOST_ASSERT( |
75 | buffers::buffer_size(dest0) == n); | ||
76 | 6296 | } | |
77 | |||
78 | template<class DynamicBuffer> | ||
79 | void | ||
80 | write_chunk_close(DynamicBuffer& db) | ||
81 | { | ||
82 | db.commit( | ||
83 | buffers::buffer_copy( | ||
84 | db.prepare(2), | ||
85 | buffers::const_buffer("\r\n", 2))); | ||
86 | } | ||
87 | |||
88 | template<class DynamicBuffer> | ||
89 | void | ||
90 | write_last_chunk(DynamicBuffer& db) | ||
91 | { | ||
92 | db.commit( | ||
93 | buffers::buffer_copy( | ||
94 | db.prepare(5), | ||
95 | buffers::const_buffer("0\r\n\r\n", 5))); | ||
96 | } | ||
97 | |||
98 | //------------------------------------------------ | ||
99 | |||
100 | 43 | serializer:: | |
101 | ~serializer() | ||
102 | { | ||
103 | 43 | } | |
104 | |||
105 | ✗ | serializer:: | |
106 | serializer( | ||
107 | serializer&&) noexcept = default; | ||
108 | |||
109 | 9 | serializer:: | |
110 | serializer( | ||
111 | 9 | context& ctx) | |
112 | 9 | : serializer(ctx, 65536) | |
113 | { | ||
114 | 9 | } | |
115 | |||
116 | 43 | serializer:: | |
117 | serializer( | ||
118 | context& ctx, | ||
119 | 43 | std::size_t buffer_size) | |
120 | 43 | : ws_(buffer_size) | |
121 | 43 | , ctx_(ctx) | |
122 | { | ||
123 | 43 | } | |
124 | |||
125 | void | ||
126 | 56 | serializer:: | |
127 | reset() noexcept | ||
128 | { | ||
129 | 56 | chunk_header_ = {}; | |
130 | 56 | chunk_close_ = {}; | |
131 | 56 | last_chunk_ = {}; | |
132 | 56 | filter_ = nullptr; | |
133 | 56 | more_ = false; | |
134 | 56 | is_done_ = false; | |
135 | 56 | is_chunked_ = false; | |
136 | 56 | is_expect_continue_ = false; | |
137 | 56 | is_compressed_ = false; | |
138 | 56 | filter_done_ = false; | |
139 | 56 | in_ = nullptr; | |
140 | 56 | out_ = nullptr; | |
141 | 56 | ws_.clear(); | |
142 | 56 | } | |
143 | |||
144 | //------------------------------------------------ | ||
145 | |||
146 | auto | ||
147 | 12572 | serializer:: | |
148 | prepare() -> | ||
149 | system::result< | ||
150 | const_buffers_type> | ||
151 | { | ||
152 | // Precondition violation | ||
153 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12571 times.
|
12572 | if( is_done_ ) |
154 | 1 | detail::throw_logic_error(); | |
155 | |||
156 | // Expect: 100-continue | ||
157 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12567 times.
|
12571 | if( is_expect_continue_ ) |
158 | { | ||
159 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if( !is_header_done_ ) |
160 | 2 | return const_buffers_type(hp_, 1); | |
161 | 2 | is_expect_continue_ = false; | |
162 | 2 | BOOST_HTTP_PROTO_RETURN_EC( | |
163 | error::expect_100_continue); | ||
164 | } | ||
165 | |||
166 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12564 times.
|
12567 | if( st_ == style::empty ) |
167 | 9 | return const_buffers_type( | |
168 | 6 | prepped_.data(), prepped_.size()); | |
169 | |||
170 |
4/4✓ Branch 0 taken 1543 times.
✓ Branch 1 taken 11021 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1540 times.
|
12564 | if( st_ == style::buffers && !filter_ ) |
171 | 9 | return const_buffers_type( | |
172 | 6 | prepped_.data(), prepped_.size()); | |
173 | |||
174 | // callers must consume() everything before invoking | ||
175 | // prepare() again | ||
176 |
4/6✓ Branch 0 taken 59 times.
✓ Branch 1 taken 12502 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 59 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12561 times.
|
12620 | if( !is_header_done_ && |
177 | 59 | buffers::buffer_size(prepped_) != prepped_[0].size() ) | |
178 | ✗ | detail::throw_logic_error(); | |
179 | |||
180 |
4/6✓ Branch 0 taken 12502 times.
✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12502 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12561 times.
|
25063 | if( is_header_done_ && |
181 | 12502 | buffers::buffer_size(prepped_) > 0 ) | |
182 | ✗ | detail::throw_logic_error(); | |
183 | |||
184 | 12561 | auto& input = *in_; | |
185 | 12561 | auto& output = *out_; | |
186 |
3/4✓ Branch 0 taken 5490 times.
✓ Branch 1 taken 7071 times.
✓ Branch 2 taken 5490 times.
✗ Branch 3 not taken.
|
12561 | if( st_ == style::source && more_ ) |
187 | { | ||
188 |
1/2✓ Branch 1 taken 5490 times.
✗ Branch 2 not taken.
|
5490 | auto results = src_->read( |
189 |
1/2✓ Branch 2 taken 5490 times.
✗ Branch 3 not taken.
|
5490 | input.prepare(input.capacity())); |
190 | 5490 | more_ = !results.finished; | |
191 | 5490 | input.commit(results.bytes); | |
192 | } | ||
193 | |||
194 | 30653 | if( st_ == style::stream && | |
195 |
8/8✓ Branch 0 taken 5531 times.
✓ Branch 1 taken 7030 times.
✓ Branch 2 taken 5510 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 5509 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 12560 times.
|
18071 | more_ && |
196 | 5510 | in_->size() == 0 ) | |
197 | 1 | BOOST_HTTP_PROTO_RETURN_EC(error::need_data); | |
198 | |||
199 | bool has_avail_out = | ||
200 |
6/6✓ Branch 0 taken 44 times.
✓ Branch 1 taken 12516 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 33 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 6 times.
|
25081 | ((!filter_ && (more_ || input.size() > 0)) || |
201 |
3/4✓ Branch 0 taken 12516 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 12516 times.
✗ Branch 3 not taken.
|
12521 | (filter_ && !filter_done_)); |
202 | |||
203 | 25248 | auto get_input = [&]() -> buffers::const_buffer | |
204 | { | ||
205 |
2/2✓ Branch 0 taken 3296 times.
✓ Branch 1 taken 21952 times.
|
25248 | if( st_ == style::buffers ) |
206 | { | ||
207 |
2/2✓ Branch 1 taken 64 times.
✓ Branch 2 taken 3232 times.
|
3296 | if( buffers::buffer_size(buf_) == 0 ) |
208 | 64 | return {}; | |
209 | |||
210 | 3232 | auto buf = *(buf_.data()); | |
211 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3232 times.
|
3232 | BOOST_ASSERT(buf.size() > 0); |
212 | 3232 | return buf; | |
213 | } | ||
214 | else | ||
215 | { | ||
216 |
2/2✓ Branch 1 taken 10992 times.
✓ Branch 2 taken 10960 times.
|
21952 | if( input.size() == 0 ) |
217 | 10992 | return {}; | |
218 | |||
219 | 10960 | auto cbs = input.data(); | |
220 | 10960 | auto buf = *cbs.begin(); | |
221 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10960 times.
|
10960 | if( buf.size() == 0 ) |
222 | { | ||
223 | ✗ | auto p = cbs.begin(); | |
224 | ✗ | ++p; | |
225 | ✗ | buf = *p; | |
226 | } | ||
227 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10960 times.
|
10960 | if( buf.size() == 0 ) |
228 | ✗ | detail::throw_logic_error(); | |
229 | 10960 | return buf; | |
230 | } | ||
231 | 12560 | }; | |
232 | |||
233 | 25248 | auto get_output = [&]() -> buffers::mutable_buffer | |
234 | { | ||
235 |
1/2✓ Branch 2 taken 25248 times.
✗ Branch 3 not taken.
|
25248 | auto mbs = output.prepare(output.capacity()); |
236 | 25248 | auto buf = *mbs.begin(); | |
237 |
2/2✓ Branch 1 taken 1524 times.
✓ Branch 2 taken 23724 times.
|
25248 | if( buf.size() == 0 ) |
238 | { | ||
239 | 1524 | auto p = mbs.begin(); | |
240 | 1524 | ++p; | |
241 | 1524 | buf = *p; | |
242 | } | ||
243 | 25248 | return buf; | |
244 | 12560 | }; | |
245 | |||
246 | 23724 | auto consume = [&](std::size_t n) | |
247 | { | ||
248 |
2/2✓ Branch 0 taken 1772 times.
✓ Branch 1 taken 21952 times.
|
23724 | if( st_ == style::buffers ) |
249 | { | ||
250 | 1772 | buf_.consume(n); | |
251 |
2/2✓ Branch 1 taken 64 times.
✓ Branch 2 taken 1708 times.
|
1772 | if( buffers::buffer_size(buf_) == 0 ) |
252 | 64 | more_ = false; | |
253 | } | ||
254 | else | ||
255 | 21952 | input.consume(n); | |
256 | 36284 | }; | |
257 | |||
258 | 12560 | std::size_t num_written = 0; | |
259 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 12516 times.
|
12560 | if( !filter_ ) |
260 | 44 | num_written += input.size(); | |
261 | else | ||
262 | { | ||
263 | for(;;) | ||
264 | { | ||
265 |
1/2✓ Branch 1 taken 25248 times.
✗ Branch 2 not taken.
|
25248 | auto in = get_input(); |
266 |
1/2✓ Branch 1 taken 25248 times.
✗ Branch 2 not taken.
|
25248 | auto out = get_output(); |
267 |
2/2✓ Branch 1 taken 1524 times.
✓ Branch 2 taken 23724 times.
|
25248 | if( out.size() == 0 ) |
268 | { | ||
269 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1524 times.
|
1524 | if( output.size() == 0 ) |
270 | ✗ | detail::throw_logic_error(); | |
271 | 12516 | break; | |
272 | } | ||
273 | |||
274 | 23724 | auto rs = filter_->on_process( | |
275 |
1/2✓ Branch 1 taken 23724 times.
✗ Branch 2 not taken.
|
23724 | out, in, more_); |
276 | |||
277 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 23628 times.
|
23724 | if( rs.finished ) |
278 | 96 | filter_done_ = true; | |
279 | |||
280 |
1/2✓ Branch 1 taken 23724 times.
✗ Branch 2 not taken.
|
23724 | consume(rs.in_bytes); |
281 | |||
282 |
2/2✓ Branch 0 taken 10992 times.
✓ Branch 1 taken 12732 times.
|
23724 | if( rs.out_bytes == 0 ) |
283 | 10992 | break; | |
284 | |||
285 | 12732 | num_written += rs.out_bytes; | |
286 | 12732 | output.commit(rs.out_bytes); | |
287 | 12732 | } | |
288 | } | ||
289 | |||
290 | // end: | ||
291 | 12560 | std::size_t n = 0; | |
292 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 12502 times.
|
12560 | if( !is_header_done_ ) |
293 | { | ||
294 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 58 times.
|
58 | BOOST_ASSERT(hp_ == &prepped_[0]); |
295 | 58 | ++n; | |
296 | } | ||
297 | else | ||
298 | 12502 | prepped_.reset(prepped_.capacity()); | |
299 | |||
300 |
2/2✓ Branch 0 taken 6262 times.
✓ Branch 1 taken 6298 times.
|
12560 | if( !is_chunked_ ) |
301 | { | ||
302 |
2/2✓ Branch 3 taken 12524 times.
✓ Branch 4 taken 6262 times.
|
18786 | for(buffers::const_buffer const& b : output.data()) |
303 | 12524 | prepped_[n++] = b; | |
304 | } | ||
305 | else | ||
306 | { | ||
307 |
2/2✓ Branch 0 taken 6295 times.
✓ Branch 1 taken 3 times.
|
6298 | if( has_avail_out ) |
308 | { | ||
309 | 6295 | write_chunk_header( | |
310 | 6295 | chunk_header_, num_written); | |
311 | 6295 | prepped_[n++] = chunk_header_; | |
312 | |||
313 |
2/2✓ Branch 3 taken 12590 times.
✓ Branch 4 taken 6295 times.
|
18885 | for(buffers::const_buffer const& b : output.data()) |
314 | 12590 | prepped_[n++] = b; | |
315 | |||
316 | 6295 | prepped_[n++] = chunk_close_; | |
317 | } | ||
318 | |||
319 |
4/4✓ Branch 0 taken 6276 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 6252 times.
✓ Branch 3 taken 24 times.
|
6298 | if( (filter_ && filter_done_) || |
320 |
4/4✓ Branch 0 taken 22 times.
✓ Branch 1 taken 6252 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 17 times.
|
6274 | (!filter_ && !more_) ) |
321 | 29 | prepped_[n++] = last_chunk_; | |
322 | } | ||
323 | |||
324 | auto cbs = const_buffers_type( | ||
325 | 12560 | prepped_.data(), prepped_.size()); | |
326 | |||
327 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 12560 times.
|
12560 | BOOST_ASSERT(buffers::buffer_size(cbs) > 0); |
328 | 12560 | return cbs; | |
329 | } | ||
330 | |||
331 | void | ||
332 | 14313 | serializer:: | |
333 | consume( | ||
334 | std::size_t n) | ||
335 | { | ||
336 | // Precondition violation | ||
337 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 14312 times.
|
14313 | if( is_done_ ) |
338 | 1 | detail::throw_logic_error(); | |
339 | |||
340 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 14309 times.
|
14312 | if( is_expect_continue_ ) |
341 | { | ||
342 | // Cannot consume more than | ||
343 | // the header on 100-continue | ||
344 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
|
3 | if( n > hp_->size() ) |
345 | 1 | detail::throw_invalid_argument(); | |
346 | } | ||
347 | |||
348 |
2/2✓ Branch 0 taken 76 times.
✓ Branch 1 taken 14235 times.
|
14311 | if( !is_header_done_ ) |
349 | { | ||
350 | // consume header | ||
351 |
2/2✓ Branch 1 taken 11 times.
✓ Branch 2 taken 65 times.
|
76 | if( n < hp_->size() ) |
352 | { | ||
353 | 11 | prepped_.consume(n); | |
354 | 11 | return; | |
355 | } | ||
356 | 65 | n -= hp_->size(); | |
357 | 65 | prepped_.consume(hp_->size()); | |
358 | 65 | is_header_done_ = true; | |
359 | } | ||
360 | |||
361 | 14300 | prepped_.consume(n); | |
362 | 14300 | auto is_empty = (buffers::buffer_size(prepped_) == 0); | |
363 | |||
364 |
6/6✓ Branch 0 taken 1548 times.
✓ Branch 1 taken 12752 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 1540 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 5 times.
|
14300 | if( st_ == style::buffers && !filter_ && is_empty ) |
365 | 3 | more_ = false; | |
366 | |||
367 |
4/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 14295 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 times.
|
14300 | if( st_ == style::empty && |
368 | 4 | is_empty && | |
369 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | !is_expect_continue_ ) |
370 | 3 | more_ = false; | |
371 | |||
372 |
2/2✓ Branch 0 taken 12568 times.
✓ Branch 1 taken 1732 times.
|
14300 | if( is_empty ) |
373 | { | ||
374 |
6/6✓ Branch 0 taken 12561 times.
✓ Branch 1 taken 7 times.
✓ Branch 3 taken 12555 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 12555 times.
✓ Branch 6 taken 13 times.
|
12568 | if( out_ && out_->size() ) |
375 | { | ||
376 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12555 times.
|
12555 | BOOST_ASSERT(st_ != style::empty); |
377 | 12555 | out_->consume(out_->size()); | |
378 | } | ||
379 |
2/2✓ Branch 0 taken 12516 times.
✓ Branch 1 taken 52 times.
|
12568 | is_done_ = filter_ ? filter_done_ : !more_; |
380 | } | ||
381 | } | ||
382 | |||
383 | void | ||
384 | 24 | serializer:: | |
385 | use_deflate_encoding() | ||
386 | { | ||
387 | // can only apply one encoding | ||
388 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | if( filter_ ) |
389 | ✗ | detail::throw_logic_error(); | |
390 | |||
391 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | BOOST_ASSERT(!filter_); |
392 | |||
393 | 24 | is_compressed_ = true; | |
394 | auto& svc = | ||
395 | 24 | ctx_.get_service< | |
396 | 24 | zlib::detail::deflate_decoder_service>(); | |
397 | 24 | filter_ = &svc.make_deflate_filter(ws_); | |
398 | 24 | } | |
399 | |||
400 | void | ||
401 | 24 | serializer:: | |
402 | use_gzip_encoding() | ||
403 | { | ||
404 | // can only apply one encoding | ||
405 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | if( filter_ ) |
406 | ✗ | detail::throw_logic_error(); | |
407 | |||
408 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | BOOST_ASSERT(!filter_); |
409 | |||
410 | 24 | is_compressed_ = true; | |
411 | auto& svc = | ||
412 | 24 | ctx_.get_service< | |
413 | 24 | zlib::detail::deflate_decoder_service>(); | |
414 | 24 | filter_ = &svc.make_gzip_filter(ws_); | |
415 | 24 | } | |
416 | |||
417 | //------------------------------------------------ | ||
418 | |||
419 | void | ||
420 | 7 | serializer:: | |
421 | copy( | ||
422 | buffers::const_buffer* dest, | ||
423 | buffers::const_buffer const* src, | ||
424 | std::size_t n) noexcept | ||
425 | { | ||
426 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
|
14 | while(n--) |
427 | 7 | *dest++ = *src++; | |
428 | 7 | } | |
429 | |||
430 | void | ||
431 | 73 | serializer:: | |
432 | start_init( | ||
433 | message_view_base const& m) | ||
434 | { | ||
435 | // VFALCO what do we do with | ||
436 | // metadata error code failures? | ||
437 | // m.ph_->md.maybe_throw(); | ||
438 | |||
439 | 73 | auto const& md = m.metadata(); | |
440 | |||
441 | 73 | is_done_ = false; | |
442 | 73 | is_header_done_ = false; | |
443 | 73 | is_expect_continue_ = md.expect.is_100_continue; | |
444 | |||
445 | // Transfer-Encoding | ||
446 | { | ||
447 | 73 | auto const& te = md.transfer_encoding; | |
448 | 73 | is_chunked_ = te.is_chunked; | |
449 | } | ||
450 | |||
451 |
2/2✓ Branch 0 taken 31 times.
✓ Branch 1 taken 42 times.
|
73 | if( is_chunked_) |
452 | { | ||
453 | 31 | auto* p = ws_.reserve_front(chunked_overhead_); | |
454 | 31 | chunk_header_ = | |
455 | 31 | buffers::mutable_buffer(p, chunk_header_len_); | |
456 | 31 | chunk_close_ = | |
457 | 62 | buffers::mutable_buffer( | |
458 | 31 | p + chunk_header_len_, crlf_len_); | |
459 | 31 | last_chunk_ = | |
460 | 62 | buffers::mutable_buffer( | |
461 | 31 | p + chunk_header_len_ + crlf_len_, | |
462 | last_chunk_len_); | ||
463 | |||
464 | 31 | buffers::buffer_copy( | |
465 | 31 | chunk_close_, buffers::const_buffer("\r\n", 2)); | |
466 | 31 | buffers::buffer_copy( | |
467 | 31 | last_chunk_, | |
468 | 62 | buffers::const_buffer("0\r\n\r\n", 5)); | |
469 | } | ||
470 | 73 | } | |
471 | |||
472 | void | ||
473 | 4 | serializer:: | |
474 | start_empty( | ||
475 | message_view_base const& m) | ||
476 | { | ||
477 | 4 | start_init(m); | |
478 | |||
479 | 4 | st_ = style::empty; | |
480 | 4 | more_ = true; | |
481 | |||
482 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | if(! is_chunked_) |
483 | { | ||
484 | 3 | prepped_ = make_array( | |
485 | 1); // header | ||
486 | } | ||
487 | else | ||
488 | { | ||
489 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | prepped_ = make_array( |
490 | 1 + // header | ||
491 | 1); // final chunk | ||
492 | |||
493 | // Buffer is too small | ||
494 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if(ws_.size() < 5) |
495 | ✗ | detail::throw_length_error(); | |
496 | |||
497 | buffers::mutable_buffer dest( | ||
498 | 1 | ws_.data(), 5); | |
499 | 1 | buffers::buffer_copy( | |
500 | dest, | ||
501 | 1 | buffers::const_buffer( | |
502 | "0\r\n\r\n", 5)); | ||
503 | 1 | prepped_[1] = dest; | |
504 | } | ||
505 | |||
506 | 4 | hp_ = &prepped_[0]; | |
507 | 4 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
508 | 4 | } | |
509 | |||
510 | void | ||
511 | 23 | serializer:: | |
512 | start_buffers( | ||
513 | message_view_base const& m) | ||
514 | { | ||
515 | 23 | st_ = style::buffers; | |
516 | 23 | tmp1_ = {}; | |
517 | |||
518 |
4/4✓ Branch 0 taken 7 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1 times.
|
23 | if( !filter_ && !is_chunked_ ) |
519 | { | ||
520 | 6 | prepped_ = make_array( | |
521 | 1 + // header | ||
522 | 6 | buf_.size()); // user input | |
523 | |||
524 | 6 | hp_ = &prepped_[0]; | |
525 | 6 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
526 | |||
527 | 6 | copy(&prepped_[1], buf_.data(), buf_.size()); | |
528 | |||
529 | 6 | more_ = (buffers::buffer_size(buf_) > 0); | |
530 | 6 | return; | |
531 | } | ||
532 | |||
533 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
17 | if( !filter_ && is_chunked_ ) |
534 | { | ||
535 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if( buffers::buffer_size(buf_) == 0 ) |
536 | { | ||
537 | ✗ | prepped_ = make_array( | |
538 | 1 + // header | ||
539 | 1); // last chunk | ||
540 | |||
541 | ✗ | hp_ = &prepped_[0]; | |
542 | ✗ | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
543 | ✗ | prepped_[1] = last_chunk_; | |
544 | ✗ | more_ = false; | |
545 | ✗ | return; | |
546 | } | ||
547 | |||
548 | 2 | write_chunk_header( | |
549 | 1 | chunk_header_, buffers::buffer_size(buf_)); | |
550 | |||
551 | 1 | prepped_ = make_array( | |
552 | 1 + // header | ||
553 | 1 + // chunk header | ||
554 | 1 | buf_.size() + // user input | |
555 | 1 + // chunk close | ||
556 | 1); // last chunk | ||
557 | |||
558 | 1 | hp_ = &prepped_[0]; | |
559 | 1 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
560 | 1 | prepped_[1] = chunk_header_; | |
561 | 1 | copy(&prepped_[2], buf_.data(), buf_.size()); | |
562 | |||
563 | 1 | prepped_[prepped_.size() - 2] = chunk_close_; | |
564 | 1 | prepped_[prepped_.size() - 1] = last_chunk_; | |
565 | 1 | more_ = true; | |
566 | 1 | return; | |
567 | } | ||
568 | |||
569 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
|
16 | if( is_chunked_ ) |
570 | { | ||
571 | 8 | prepped_ = make_array( | |
572 | 1 + // header | ||
573 | 1 + // chunk header | ||
574 | 2 + // tmp | ||
575 | 1 + // chunk close | ||
576 | 1); // last chunk | ||
577 | } | ||
578 | else | ||
579 | 8 | prepped_ = make_array( | |
580 | 1 + // header | ||
581 | 2); // tmp | ||
582 | |||
583 | 16 | hp_ = &prepped_[0]; | |
584 | 16 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
585 | 16 | tmp0_ = { ws_.data(), ws_.size() }; | |
586 | 16 | out_ = &tmp0_; | |
587 | 16 | in_ = out_; | |
588 | 16 | more_ = true; | |
589 | } | ||
590 | |||
591 | void | ||
592 | 24 | serializer:: | |
593 | start_source( | ||
594 | message_view_base const& m, | ||
595 | source* src) | ||
596 | { | ||
597 | 24 | st_ = style::source; | |
598 | 24 | src_ = src; | |
599 | |||
600 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 14 times.
|
24 | if( is_chunked_ ) |
601 | { | ||
602 | 10 | prepped_ = make_array( | |
603 | 1 + // header | ||
604 | 1 + // chunk header | ||
605 | 2 + // tmp | ||
606 | 1 + // chunk close | ||
607 | 1); // last chunk | ||
608 | } | ||
609 | else | ||
610 | 14 | prepped_ = make_array( | |
611 | 1 + // header | ||
612 | 2); // tmp | ||
613 | |||
614 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 16 times.
|
24 | if( !filter_ ) |
615 | { | ||
616 | 8 | tmp0_ = { ws_.data(), ws_.size() }; | |
617 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
|
8 | if( tmp0_.capacity() < 1 ) |
618 | ✗ | detail::throw_length_error(); | |
619 | |||
620 | 8 | in_ = &tmp0_; | |
621 | 8 | out_ = &tmp0_; | |
622 | } | ||
623 | else | ||
624 | { | ||
625 | 16 | auto n = ws_.size() / 2; | |
626 | 16 | auto* p = ws_.reserve_front(n); | |
627 | 16 | tmp1_ = buffers::circular_buffer(p, n); | |
628 | |||
629 | 16 | tmp0_ = { ws_.data(), ws_.size() }; | |
630 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
|
16 | if( tmp0_.capacity() < 1 ) |
631 | ✗ | detail::throw_length_error(); | |
632 | |||
633 | 16 | in_ = &tmp1_; | |
634 | 16 | out_ = &tmp0_; | |
635 | } | ||
636 | |||
637 | 24 | hp_ = &prepped_[0]; | |
638 | 24 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
639 | 24 | more_ = true; | |
640 | 24 | } | |
641 | |||
642 | auto | ||
643 | 22 | serializer:: | |
644 | start_stream( | ||
645 | message_view_base const& m) -> | ||
646 | stream | ||
647 | { | ||
648 | 22 | start_init(m); | |
649 | |||
650 | 22 | st_ = style::stream; | |
651 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
|
22 | if( is_chunked_ ) |
652 | { | ||
653 | 11 | prepped_ = make_array( | |
654 | 1 + // header | ||
655 | 1 + // chunk header | ||
656 | 2 + // tmp | ||
657 | 1 + // chunk close | ||
658 | 1); // last chunk | ||
659 | } | ||
660 | else | ||
661 | 11 | prepped_ = make_array( | |
662 | 1 + // header | ||
663 | 2); // tmp | ||
664 | |||
665 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
|
22 | if( !filter_ ) |
666 | { | ||
667 | 6 | tmp0_ = { ws_.data(), ws_.size() }; | |
668 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
|
6 | if( tmp0_.capacity() < 1 ) |
669 | ✗ | detail::throw_length_error(); | |
670 | |||
671 | 6 | in_ = &tmp0_; | |
672 | 6 | out_ = &tmp0_; | |
673 | } | ||
674 | else | ||
675 | { | ||
676 | 16 | auto n = ws_.size() / 2; | |
677 | 16 | auto* p = ws_.reserve_front(n); | |
678 | 16 | tmp1_ = buffers::circular_buffer(p, n); | |
679 | |||
680 | 16 | tmp0_ = { ws_.data(), ws_.size() }; | |
681 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
|
16 | if( tmp0_.capacity() < 1 ) |
682 | ✗ | detail::throw_length_error(); | |
683 | |||
684 | 16 | in_ = &tmp1_; | |
685 | 16 | out_ = &tmp0_; | |
686 | } | ||
687 | |||
688 | 22 | hp_ = &prepped_[0]; | |
689 | 22 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
690 | 22 | more_ = true; | |
691 | 22 | return stream{*this}; | |
692 | } | ||
693 | |||
694 | //------------------------------------------------ | ||
695 | |||
696 | std::size_t | ||
697 | 139 | serializer:: | |
698 | stream:: | ||
699 | capacity() const noexcept | ||
700 | { | ||
701 | 139 | return sr_->in_->capacity(); | |
702 | } | ||
703 | |||
704 | std::size_t | ||
705 | 72 | serializer:: | |
706 | stream:: | ||
707 | size() const noexcept | ||
708 | { | ||
709 | 72 | return sr_->in_->size(); | |
710 | } | ||
711 | |||
712 | bool | ||
713 | 63 | serializer:: | |
714 | stream:: | ||
715 | is_full() const noexcept | ||
716 | { | ||
717 | 63 | return capacity() == 0; | |
718 | } | ||
719 | |||
720 | auto | ||
721 | 5512 | serializer:: | |
722 | stream:: | ||
723 | prepare() const -> | ||
724 | buffers_type | ||
725 | { | ||
726 | 5512 | return sr_->in_->prepare(sr_->in_->capacity()); | |
727 | } | ||
728 | |||
729 | void | ||
730 | 5512 | serializer:: | |
731 | stream:: | ||
732 | commit(std::size_t n) const | ||
733 | { | ||
734 | // the stream must make a non-zero amount of bytes | ||
735 | // available to the serializer | ||
736 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5511 times.
|
5512 | if( n == 0 ) |
737 | 1 | detail::throw_logic_error(); | |
738 | |||
739 | 5511 | sr_->in_->commit(n); | |
740 | 5511 | } | |
741 | |||
742 | void | ||
743 | 25 | serializer:: | |
744 | stream:: | ||
745 | close() const | ||
746 | { | ||
747 | // Precondition violation | ||
748 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 21 times.
|
25 | if(! sr_->more_ ) |
749 | 4 | detail::throw_logic_error(); | |
750 | 21 | sr_->more_ = false; | |
751 | 21 | } | |
752 | |||
753 | //------------------------------------------------ | ||
754 | |||
755 | } // http_proto | ||
756 | } // boost | ||
757 |