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