Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) | ||
3 | // Copyright (c) 2024 Mohammad Nejati | ||
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/error.hpp> | ||
13 | #include <boost/http_proto/parser.hpp> | ||
14 | #include <boost/http_proto/static_request.hpp> | ||
15 | #include <boost/http_proto/static_response.hpp> | ||
16 | |||
17 | #include <boost/assert.hpp> | ||
18 | #include <boost/buffers/circular_buffer.hpp> | ||
19 | #include <boost/buffers/copy.hpp> | ||
20 | #include <boost/buffers/flat_buffer.hpp> | ||
21 | #include <boost/buffers/front.hpp> | ||
22 | #include <boost/buffers/slice.hpp> | ||
23 | #include <boost/rts/brotli/decode.hpp> | ||
24 | #include <boost/rts/context.hpp> | ||
25 | #include <boost/rts/zlib/error.hpp> | ||
26 | #include <boost/rts/zlib/inflate.hpp> | ||
27 | #include <boost/url/grammar/ci_string.hpp> | ||
28 | #include <boost/url/grammar/error.hpp> | ||
29 | #include <boost/url/grammar/hexdig_chars.hpp> | ||
30 | |||
31 | #include "src/detail/brotli_filter_base.hpp" | ||
32 | #include "src/detail/buffer_utils.hpp" | ||
33 | #include "src/detail/zlib_filter_base.hpp" | ||
34 | |||
35 | namespace boost { | ||
36 | namespace http_proto { | ||
37 | |||
38 | /* | ||
39 | Principles for fixed-size buffer design | ||
40 | |||
41 | axiom 1: | ||
42 | To read data you must have a buffer. | ||
43 | |||
44 | axiom 2: | ||
45 | The size of the HTTP header is not | ||
46 | known in advance. | ||
47 | |||
48 | conclusion 3: | ||
49 | A single I/O can produce a complete | ||
50 | HTTP header and additional payload | ||
51 | data. | ||
52 | |||
53 | conclusion 4: | ||
54 | A single I/O can produce multiple | ||
55 | complete HTTP headers, complete | ||
56 | payloads, and a partial header or | ||
57 | payload. | ||
58 | |||
59 | axiom 5: | ||
60 | A process is in one of two states: | ||
61 | 1. at or below capacity | ||
62 | 2. above capacity | ||
63 | |||
64 | axiom 6: | ||
65 | A program which can allocate an | ||
66 | unbounded number of resources can | ||
67 | go above capacity. | ||
68 | |||
69 | conclusion 7: | ||
70 | A program can guarantee never going | ||
71 | above capacity if all resources are | ||
72 | provisioned at program startup. | ||
73 | |||
74 | corollary 8: | ||
75 | `parser` and `serializer` should each | ||
76 | allocate a single buffer of calculated | ||
77 | size, and never resize it. | ||
78 | |||
79 | axiom #: | ||
80 | A parser and a serializer are always | ||
81 | used in pairs. | ||
82 | |||
83 | Buffer Usage | ||
84 | |||
85 | | | begin | ||
86 | | H | p | | f | read headers | ||
87 | | H | p | | T | f | set T body | ||
88 | | H | p | | C | T | f | make codec C | ||
89 | | H | p | b | C | T | f | decode p into b | ||
90 | | H | p | b | C | T | f | read/parse loop | ||
91 | | H | | T | f | destroy codec | ||
92 | | H | | T | f | finished | ||
93 | |||
94 | H headers | ||
95 | C codec | ||
96 | T body | ||
97 | f table | ||
98 | p partial payload | ||
99 | b body data | ||
100 | |||
101 | "payload" is the bytes coming in from | ||
102 | the stream. | ||
103 | |||
104 | "body" is the logical body, after transfer | ||
105 | encoding is removed. This can be the | ||
106 | same as the payload. | ||
107 | |||
108 | A "plain payload" is when the payload and | ||
109 | body are identical (no transfer encodings). | ||
110 | |||
111 | A "buffered payload" is any payload which is | ||
112 | not plain. A second buffer is required | ||
113 | for reading. | ||
114 | |||
115 | "overread" is additional data received past | ||
116 | the end of the headers when reading headers, | ||
117 | or additional data received past the end of | ||
118 | the message payload. | ||
119 | */ | ||
120 | |||
121 | namespace { | ||
122 | |||
123 | class chained_sequence | ||
124 | { | ||
125 | char const* pos_; | ||
126 | char const* end_; | ||
127 | char const* begin_b_; | ||
128 | char const* end_b_; | ||
129 | |||
130 | public: | ||
131 | 120206 | chained_sequence(buffers::const_buffer_pair const& cbp) | |
132 | 120206 | : pos_(static_cast<char const*>(cbp[0].data())) | |
133 | 120206 | , end_(pos_ + cbp[0].size()) | |
134 | 120206 | , begin_b_(static_cast<char const*>(cbp[1].data())) | |
135 | 120206 | , end_b_(begin_b_ + cbp[1].size()) | |
136 | { | ||
137 | 120206 | } | |
138 | |||
139 | char const* | ||
140 | 618798 | next() noexcept | |
141 | { | ||
142 | 618798 | ++pos_; | |
143 | // most frequently taken branch | ||
144 |
2/2✓ Branch 0 taken 597477 times.
✓ Branch 1 taken 21321 times.
|
618798 | if(pos_ < end_) |
145 | 597477 | return pos_; | |
146 | |||
147 | // bring the second range | ||
148 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 21283 times.
|
21321 | if(begin_b_ != end_b_) |
149 | { | ||
150 | 38 | pos_ = begin_b_; | |
151 | 38 | end_ = end_b_; | |
152 | 38 | begin_b_ = end_b_; | |
153 | 38 | return pos_; | |
154 | } | ||
155 | |||
156 | // undo the increament | ||
157 | 21283 | pos_ = end_; | |
158 | 21283 | return nullptr; | |
159 | } | ||
160 | |||
161 | bool | ||
162 | 411032 | is_empty() const noexcept | |
163 | { | ||
164 | 411032 | return pos_ == end_; | |
165 | } | ||
166 | |||
167 | char | ||
168 | 604291 | value() const noexcept | |
169 | { | ||
170 | 604291 | return *pos_; | |
171 | } | ||
172 | |||
173 | std::size_t | ||
174 | 425010 | size() const noexcept | |
175 | { | ||
176 | 425010 | return (end_ - pos_) + (end_b_ - begin_b_); | |
177 | } | ||
178 | }; | ||
179 | |||
180 | std::uint64_t | ||
181 | 115966 | parse_hex( | |
182 | chained_sequence& cs, | ||
183 | system::error_code& ec) noexcept | ||
184 | { | ||
185 | 115966 | std::uint64_t v = 0; | |
186 | 115966 | std::size_t init_size = cs.size(); | |
187 |
2/2✓ Branch 1 taken 283520 times.
✓ Branch 2 taken 19282 times.
|
302802 | while(!cs.is_empty()) |
188 | { | ||
189 | 283520 | auto n = grammar::hexdig_value(cs.value()); | |
190 |
2/2✓ Branch 0 taken 96683 times.
✓ Branch 1 taken 186837 times.
|
283520 | if(n < 0) |
191 | { | ||
192 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 96682 times.
|
96683 | if(init_size == cs.size()) |
193 | { | ||
194 | 2 | ec = BOOST_HTTP_PROTO_ERR( | |
195 | error::bad_payload); | ||
196 | 1 | return 0; | |
197 | } | ||
198 | 96682 | return v; | |
199 | } | ||
200 | |||
201 | // at least 4 significant bits are free | ||
202 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 186836 times.
|
186837 | if(v > (std::numeric_limits<std::uint64_t>::max)() >> 4) |
203 | { | ||
204 | 2 | ec = BOOST_HTTP_PROTO_ERR( | |
205 | error::bad_payload); | ||
206 | 1 | return 0; | |
207 | } | ||
208 | |||
209 | 186836 | v = (v << 4) | static_cast<std::uint64_t>(n); | |
210 | 186836 | cs.next(); | |
211 | } | ||
212 | 38564 | ec = BOOST_HTTP_PROTO_ERR( | |
213 | error::need_data); | ||
214 | 19282 | return 0; | |
215 | } | ||
216 | |||
217 | void | ||
218 | 97034 | find_eol( | |
219 | chained_sequence& cs, | ||
220 | system::error_code& ec) noexcept | ||
221 | { | ||
222 |
2/2✓ Branch 1 taken 103635 times.
✓ Branch 2 taken 88 times.
|
103723 | while(!cs.is_empty()) |
223 | { | ||
224 |
2/2✓ Branch 1 taken 96946 times.
✓ Branch 2 taken 6689 times.
|
103635 | if(cs.value() == '\r') |
225 | { | ||
226 |
2/2✓ Branch 1 taken 10 times.
✓ Branch 2 taken 96936 times.
|
96946 | if(!cs.next()) |
227 | 10 | break; | |
228 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 96934 times.
|
96936 | if(cs.value() != '\n') |
229 | { | ||
230 | 4 | ec = BOOST_HTTP_PROTO_ERR( | |
231 | error::bad_payload); | ||
232 | 2 | return; | |
233 | } | ||
234 | 96934 | cs.next(); | |
235 | 96934 | return; | |
236 | } | ||
237 | 6689 | cs.next(); | |
238 | } | ||
239 | 196 | ec = BOOST_HTTP_PROTO_ERR( | |
240 | error::need_data); | ||
241 | } | ||
242 | |||
243 | void | ||
244 | 111566 | parse_eol( | |
245 | chained_sequence& cs, | ||
246 | system::error_code& ec) noexcept | ||
247 | { | ||
248 |
2/2✓ Branch 1 taken 111552 times.
✓ Branch 2 taken 14 times.
|
111566 | if(cs.size() >= 2) |
249 | { | ||
250 | // we are sure size is at least 2 | ||
251 |
6/6✓ Branch 1 taken 111550 times.
✓ Branch 2 taken 2 times.
✓ Branch 4 taken 111549 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 111549 times.
✓ Branch 7 taken 3 times.
|
111552 | if(cs.value() == '\r' && *cs.next() == '\n') |
252 | { | ||
253 | 111549 | cs.next(); | |
254 | 111549 | return; | |
255 | } | ||
256 | 6 | ec = BOOST_HTTP_PROTO_ERR( | |
257 | error::bad_payload); | ||
258 | 3 | return; | |
259 | } | ||
260 | 28 | ec = BOOST_HTTP_PROTO_ERR( | |
261 | error::need_data); | ||
262 | } | ||
263 | |||
264 | void | ||
265 | 4223 | skip_trailer_headers( | |
266 | chained_sequence& cs, | ||
267 | system::error_code& ec) noexcept | ||
268 | { | ||
269 |
2/2✓ Branch 1 taken 4501 times.
✓ Branch 2 taken 6 times.
|
4507 | while(!cs.is_empty()) |
270 | { | ||
271 |
2/2✓ Branch 1 taken 4149 times.
✓ Branch 2 taken 352 times.
|
4501 | if(cs.value() == '\r') |
272 | { | ||
273 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4147 times.
|
4149 | if(!cs.next()) |
274 | 2 | break; | |
275 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4145 times.
|
4147 | if(cs.value() != '\n') |
276 | { | ||
277 | 4 | ec = BOOST_HTTP_PROTO_ERR( | |
278 | error::bad_payload); | ||
279 | 2 | return; | |
280 | } | ||
281 | 4145 | cs.next(); | |
282 | 4145 | return; | |
283 | } | ||
284 | // skip to the end of field | ||
285 | 352 | find_eol(cs, ec); | |
286 |
2/2✓ Branch 1 taken 68 times.
✓ Branch 2 taken 284 times.
|
352 | if(ec) |
287 | 68 | return; | |
288 | } | ||
289 | 16 | ec = BOOST_HTTP_PROTO_ERR( | |
290 | error::need_data); | ||
291 | } | ||
292 | |||
293 | template<class UInt> | ||
294 | std::size_t | ||
295 | 360963 | clamp( | |
296 | UInt x, | ||
297 | std::size_t limit = (std::numeric_limits< | ||
298 | std::size_t>::max)()) noexcept | ||
299 | { | ||
300 |
2/2✓ Branch 0 taken 101557 times.
✓ Branch 1 taken 259406 times.
|
360963 | if(x >= limit) |
301 | 101557 | return limit; | |
302 | 259406 | return static_cast<std::size_t>(x); | |
303 | } | ||
304 | |||
305 | class zlib_filter | ||
306 | : public detail::zlib_filter_base | ||
307 | { | ||
308 | rts::zlib::inflate_service& svc_; | ||
309 | |||
310 | public: | ||
311 | 72 | zlib_filter( | |
312 | const rts::context& ctx, | ||
313 | http_proto::detail::workspace& ws, | ||
314 | int window_bits) | ||
315 | 72 | : zlib_filter_base(ws) | |
316 | 72 | , svc_(ctx.get_service<rts::zlib::inflate_service>()) | |
317 | { | ||
318 | system::error_code ec = static_cast<rts::zlib::error>( | ||
319 |
1/2✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
|
72 | svc_.init2(strm_, window_bits)); |
320 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 72 times.
|
72 | if(ec != rts::zlib::error::ok) |
321 | ✗ | detail::throw_system_error(ec); | |
322 | 72 | } | |
323 | |||
324 | private: | ||
325 | virtual | ||
326 | results | ||
327 | 56591 | do_process( | |
328 | buffers::mutable_buffer out, | ||
329 | buffers::const_buffer in, | ||
330 | bool more) noexcept override | ||
331 | { | ||
332 | 56591 | strm_.next_out = static_cast<unsigned char*>(out.data()); | |
333 | 56591 | strm_.avail_out = saturate_cast(out.size()); | |
334 | 56591 | strm_.next_in = static_cast<unsigned char*>(const_cast<void *>(in.data())); | |
335 | 56591 | strm_.avail_in = saturate_cast(in.size()); | |
336 | |||
337 | auto rs = static_cast<rts::zlib::error>( | ||
338 |
2/2✓ Branch 0 taken 56499 times.
✓ Branch 1 taken 92 times.
|
56591 | svc_.inflate( |
339 | 56591 | strm_, | |
340 | more ? rts::zlib::no_flush : rts::zlib::finish)); | ||
341 | |||
342 | 56591 | results rv; | |
343 | 56591 | rv.out_bytes = saturate_cast(out.size()) - strm_.avail_out; | |
344 | 56591 | rv.in_bytes = saturate_cast(in.size()) - strm_.avail_in; | |
345 | 56591 | rv.finished = (rs == rts::zlib::error::stream_end); | |
346 | |||
347 |
3/4✓ Branch 0 taken 1636 times.
✓ Branch 1 taken 54955 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1636 times.
|
56591 | if(rs < rts::zlib::error::ok && rs != rts::zlib::error::buf_err) |
348 | ✗ | rv.ec = rs; | |
349 | |||
350 | 56591 | return rv; | |
351 | } | ||
352 | }; | ||
353 | |||
354 | class brotli_filter | ||
355 | : public detail::brotli_filter_base | ||
356 | { | ||
357 | rts::brotli::decode_service& svc_; | ||
358 | rts::brotli::decoder_state* state_; | ||
359 | |||
360 | public: | ||
361 | ✗ | brotli_filter( | |
362 | const rts::context& ctx, | ||
363 | http_proto::detail::workspace&) | ||
364 | ✗ | : svc_(ctx.get_service<rts::brotli::decode_service>()) | |
365 | { | ||
366 | // TODO: use custom allocator | ||
367 | ✗ | state_ = svc_.create_instance(nullptr, nullptr, nullptr); | |
368 | |||
369 | ✗ | if(!state_) | |
370 | ✗ | detail::throw_bad_alloc(); | |
371 | ✗ | } | |
372 | |||
373 | ✗ | ~brotli_filter() | |
374 | ✗ | { | |
375 | ✗ | svc_.destroy_instance(state_); | |
376 | ✗ | } | |
377 | |||
378 | private: | ||
379 | virtual | ||
380 | results | ||
381 | ✗ | do_process( | |
382 | buffers::mutable_buffer out, | ||
383 | buffers::const_buffer in, | ||
384 | bool more) noexcept override | ||
385 | { | ||
386 | ✗ | auto* next_in = reinterpret_cast<const std::uint8_t*>(in.data()); | |
387 | ✗ | auto available_in = in.size(); | |
388 | ✗ | auto* next_out = reinterpret_cast<std::uint8_t*>(out.data()); | |
389 | ✗ | auto available_out = out.size(); | |
390 | |||
391 | ✗ | auto rs = svc_.decompress_stream( | |
392 | state_, | ||
393 | &available_in, | ||
394 | &next_in, | ||
395 | &available_out, | ||
396 | &next_out, | ||
397 | nullptr); | ||
398 | |||
399 | ✗ | results rv; | |
400 | ✗ | rv.in_bytes = in.size() - available_in; | |
401 | ✗ | rv.out_bytes = out.size() - available_out; | |
402 | ✗ | rv.finished = svc_.is_finished(state_); | |
403 | |||
404 | ✗ | if(!more && rs == rts::brotli::decoder_result::needs_more_input) | |
405 | ✗ | rv.ec = BOOST_HTTP_PROTO_ERR(error::bad_payload); | |
406 | |||
407 | ✗ | if(rs == rts::brotli::decoder_result::error) | |
408 | ✗ | rv.ec = BOOST_HTTP_PROTO_ERR( | |
409 | svc_.get_error_code(state_)); | ||
410 | |||
411 | ✗ | return rv; | |
412 | } | ||
413 | }; | ||
414 | |||
415 | class parser_service | ||
416 | : public rts::service | ||
417 | { | ||
418 | public: | ||
419 | parser::config_base cfg; | ||
420 | std::size_t space_needed = 0; | ||
421 | std::size_t max_codec = 0; | ||
422 | |||
423 | 41 | parser_service( | |
424 | const rts::context&, | ||
425 | parser::config_base const& cfg_) | ||
426 | 41 | : cfg(cfg_) | |
427 | { | ||
428 | /* | ||
429 | | fb | cb0 | cb1 | C | T | f | | ||
430 | |||
431 | fb flat_buffer headers.max_size | ||
432 | cb0 circular_buffer min_buffer | ||
433 | cb1 circular_buffer min_buffer | ||
434 | C codec max_codec | ||
435 | T body max_type_erase | ||
436 | f table max_table_space | ||
437 | |||
438 | */ | ||
439 | // validate | ||
440 | //if(cfg.min_prepare > cfg.max_prepare) | ||
441 | //detail::throw_invalid_argument(); | ||
442 | |||
443 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
|
41 | if(cfg.max_prepare < 1) |
444 | ✗ | detail::throw_invalid_argument(); | |
445 | |||
446 | // VFALCO TODO OVERFLOW CHECING | ||
447 | { | ||
448 | //fb_.size() - h_.size + | ||
449 | //svc_.cfg.min_buffer + | ||
450 | //svc_.cfg.min_buffer + | ||
451 | //svc_.max_codec; | ||
452 | } | ||
453 | |||
454 | // VFALCO OVERFLOW CHECKING ON THIS | ||
455 | 41 | space_needed += | |
456 |
1/2✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
|
41 | cfg.headers.valid_space_needed(); |
457 | |||
458 | // cb0_, cb1_ | ||
459 | // VFALCO OVERFLOW CHECKING ON THIS | ||
460 | 41 | space_needed += | |
461 | 41 | cfg.min_buffer + | |
462 | cfg.min_buffer; | ||
463 | |||
464 | // T | ||
465 | 41 | space_needed += cfg.max_type_erase; | |
466 | |||
467 | // max_codec | ||
468 |
3/4✓ Branch 0 taken 40 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
|
41 | if(cfg.apply_deflate_decoder || cfg.apply_gzip_decoder) |
469 | { | ||
470 | // TODO: Account for the number of allocations and | ||
471 | // their overhead in the workspace. | ||
472 | |||
473 | // https://www.zlib.net/zlib_tech.html | ||
474 | std::size_t n = | ||
475 | 1 | (1 << cfg.zlib_window_bits) + | |
476 | (7 * 1024) + | ||
477 | #ifdef __s390x__ | ||
478 | 5768 + | ||
479 | #endif | ||
480 | detail::workspace::space_needed< | ||
481 | 1 | zlib_filter>(); | |
482 | |||
483 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if(max_codec < n) |
484 | 1 | max_codec = n; | |
485 | } | ||
486 | 41 | space_needed += max_codec; | |
487 | |||
488 | // round up to alignof(detail::header::entry) | ||
489 | 41 | auto const al = alignof( | |
490 | detail::header::entry); | ||
491 | 41 | space_needed = al * (( | |
492 | 41 | space_needed + al - 1) / al); | |
493 | 41 | } | |
494 | |||
495 | std::size_t | ||
496 | 55255 | max_overread() const noexcept | |
497 | { | ||
498 | return | ||
499 | 55255 | cfg.headers.max_size + | |
500 | 55255 | cfg.min_buffer; | |
501 | } | ||
502 | }; | ||
503 | |||
504 | } // namespace | ||
505 | |||
506 | //------------------------------------------------ | ||
507 | |||
508 | void | ||
509 | 41 | install_parser_service( | |
510 | rts::context& ctx, | ||
511 | parser::config_base const& cfg) | ||
512 | { | ||
513 | 41 | ctx.make_service<parser_service>(cfg); | |
514 | 41 | } | |
515 | |||
516 | //------------------------------------------------ | ||
517 | |||
518 | class parser::impl | ||
519 | { | ||
520 | enum class state | ||
521 | { | ||
522 | reset, | ||
523 | start, | ||
524 | header, | ||
525 | header_done, | ||
526 | body, | ||
527 | set_body, | ||
528 | complete_in_place, | ||
529 | complete | ||
530 | }; | ||
531 | |||
532 | enum class style | ||
533 | { | ||
534 | in_place, | ||
535 | sink, | ||
536 | elastic, | ||
537 | }; | ||
538 | |||
539 | const rts::context& ctx_; | ||
540 | parser_service& svc_; | ||
541 | |||
542 | detail::workspace ws_; | ||
543 | static_request m_; | ||
544 | std::uint64_t body_limit_; | ||
545 | std::uint64_t body_total_; | ||
546 | std::uint64_t payload_remain_; | ||
547 | std::uint64_t chunk_remain_; | ||
548 | std::size_t body_avail_; | ||
549 | std::size_t nprepare_; | ||
550 | |||
551 | buffers::flat_buffer fb_; | ||
552 | buffers::circular_buffer cb0_; | ||
553 | buffers::circular_buffer cb1_; | ||
554 | |||
555 | buffers::mutable_buffer_pair mbp_; | ||
556 | buffers::const_buffer_pair cbp_; | ||
557 | |||
558 | detail::filter* filter_; | ||
559 | buffers::any_dynamic_buffer* eb_; | ||
560 | sink* sink_; | ||
561 | |||
562 | state state_; | ||
563 | style style_; | ||
564 | bool got_header_; | ||
565 | bool got_eof_; | ||
566 | bool head_response_; | ||
567 | bool needs_chunk_close_; | ||
568 | bool trailer_headers_; | ||
569 | bool chunked_body_ended; | ||
570 | |||
571 | public: | ||
572 | 1054 | impl(const rts::context& ctx, detail::kind k) | |
573 | 1054 | : ctx_(ctx) | |
574 | 1054 | , svc_(ctx.get_service<parser_service>()) | |
575 | 1054 | , ws_(svc_.space_needed) | |
576 | 1054 | , m_(ws_.data(), ws_.size()) | |
577 | 1054 | , state_(state::reset) | |
578 | 1054 | , got_header_(false) | |
579 | { | ||
580 | 1054 | m_.h_ = detail::header(detail::empty{ k }); | |
581 | 1054 | } | |
582 | |||
583 | bool | ||
584 | 11938 | got_header() const noexcept | |
585 | { | ||
586 | 11938 | return got_header_; | |
587 | } | ||
588 | |||
589 | bool | ||
590 | 51344 | is_complete() const noexcept | |
591 | { | ||
592 | 51344 | return state_ >= state::complete_in_place; | |
593 | } | ||
594 | |||
595 | static_request const& | ||
596 | 315 | safe_get_request() const | |
597 | { | ||
598 | // headers must be received | ||
599 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 315 times.
|
315 | if(! got_header_) |
600 | ✗ | detail::throw_logic_error(); | |
601 | |||
602 | 315 | return m_; | |
603 | } | ||
604 | |||
605 | static_response const& | ||
606 | 1 | safe_get_response() const | |
607 | { | ||
608 | // headers must be received | ||
609 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if(! got_header_) |
610 | ✗ | detail::throw_logic_error(); | |
611 | |||
612 | // TODO: use a union | ||
613 | 1 | return reinterpret_cast<static_response const&>(m_); | |
614 | } | ||
615 | |||
616 | bool | ||
617 | 755 | is_body_set() const noexcept | |
618 | { | ||
619 | 755 | return style_ != style::in_place; | |
620 | } | ||
621 | |||
622 | void | ||
623 | 2480 | reset() noexcept | |
624 | { | ||
625 | 2480 | ws_.clear(); | |
626 | 2480 | state_ = state::start; | |
627 | 2480 | got_header_ = false; | |
628 | 2480 | got_eof_ = false; | |
629 | 2480 | } | |
630 | |||
631 | void | ||
632 | 10307 | start( | |
633 | bool head_response) | ||
634 | { | ||
635 | 10307 | std::size_t leftover = 0; | |
636 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2255 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 8015 times.
✓ Branch 5 taken 32 times.
|
10307 | switch(state_) |
637 | { | ||
638 | 1 | default: | |
639 | case state::reset: | ||
640 | // reset must be called first | ||
641 | 1 | detail::throw_logic_error(); | |
642 | |||
643 | 2255 | case state::start: | |
644 | // reset required on eof | ||
645 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2255 times.
|
2255 | if(got_eof_) |
646 | ✗ | detail::throw_logic_error(); | |
647 | 2255 | break; | |
648 | |||
649 | 3 | case state::header: | |
650 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
|
3 | if(fb_.size() == 0) |
651 | { | ||
652 | // start() called twice | ||
653 | 2 | detail::throw_logic_error(); | |
654 | } | ||
655 | BOOST_FALLTHROUGH; | ||
656 | |||
657 | case state::header_done: | ||
658 | case state::body: | ||
659 | case state::set_body: | ||
660 | // current message is incomplete | ||
661 | 2 | detail::throw_logic_error(); | |
662 | |||
663 | 8015 | case state::complete_in_place: | |
664 | // remove available body. | ||
665 |
2/2✓ Branch 1 taken 4000 times.
✓ Branch 2 taken 4015 times.
|
8015 | if(is_plain()) |
666 | 4000 | cb0_.consume(body_avail_); | |
667 | BOOST_FALLTHROUGH; | ||
668 | |||
669 | case state::complete: | ||
670 | { | ||
671 | // move leftovers to front | ||
672 | |||
673 | 8047 | ws_.clear(); | |
674 | 8047 | leftover = cb0_.size(); | |
675 | |||
676 | 8047 | auto* dest = reinterpret_cast<char*>(ws_.data()); | |
677 | 8047 | auto cbp = cb0_.data(); | |
678 | 8047 | auto* a = static_cast<char const*>(cbp[0].data()); | |
679 | 8047 | auto* b = static_cast<char const*>(cbp[1].data()); | |
680 | 8047 | auto an = cbp[0].size(); | |
681 | 8047 | auto bn = cbp[1].size(); | |
682 | |||
683 |
2/2✓ Branch 0 taken 7609 times.
✓ Branch 1 taken 438 times.
|
8047 | if(bn == 0) |
684 | { | ||
685 | 7609 | std::memmove(dest, a, an); | |
686 | } | ||
687 | else | ||
688 | { | ||
689 | // if `a` can fit between `dest` and `b`, shift `b` to the left | ||
690 | // and copy `a` to its position. if `a` fits perfectly, the | ||
691 | // shift will be of size 0. | ||
692 | // if `a` requires more space, shift `b` to the right and | ||
693 | // copy `a` to its position. this process may require multiple | ||
694 | // iterations and should be done chunk by chunk to prevent `b` | ||
695 | // from overlapping with `a`. | ||
696 | do | ||
697 | { | ||
698 | // clamp right shifts to prevent overlap with `a` | ||
699 | 438 | auto* bp = (std::min)(dest + an, const_cast<char*>(a) - bn); | |
700 | 438 | b = static_cast<char const*>(std::memmove(bp, b, bn)); | |
701 | |||
702 | // a chunk or all of `a` based on available space | ||
703 | 438 | auto chunk_a = static_cast<std::size_t>(b - dest); | |
704 | 438 | std::memcpy(dest, a, chunk_a); // never overlap | |
705 | 438 | an -= chunk_a; | |
706 | 438 | dest += chunk_a; | |
707 | 438 | a += chunk_a; | |
708 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 438 times.
|
438 | } while(an); |
709 | } | ||
710 | |||
711 | 8047 | break; | |
712 | } | ||
713 | } | ||
714 | |||
715 | 10302 | ws_.clear(); | |
716 | |||
717 | 20604 | fb_ = { | |
718 | 10302 | ws_.data(), | |
719 |
1/2✓ Branch 1 taken 10302 times.
✗ Branch 2 not taken.
|
10302 | svc_.cfg.headers.max_size + svc_.cfg.min_buffer, |
720 | leftover }; | ||
721 | |||
722 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 10302 times.
|
10302 | BOOST_ASSERT( |
723 | fb_.capacity() == svc_.max_overread() - leftover); | ||
724 | |||
725 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 10302 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
10302 | BOOST_ASSERT( |
726 | head_response == false || | ||
727 | m_.h_.kind == detail::kind::response); | ||
728 | |||
729 | 10302 | m_.h_ = detail::header(detail::empty{m_.h_.kind}); | |
730 | 10302 | m_.h_.buf = reinterpret_cast<char*>(ws_.data()); | |
731 | 10302 | m_.h_.cbuf = m_.h_.buf; | |
732 | 10302 | m_.h_.cap = ws_.size(); | |
733 | |||
734 | 10302 | state_ = state::header; | |
735 | 10302 | style_ = style::in_place; | |
736 | |||
737 | // reset to the configured default | ||
738 | 10302 | body_limit_ = svc_.cfg.body_limit; | |
739 | |||
740 | 10302 | body_total_ = 0; | |
741 | 10302 | payload_remain_ = 0; | |
742 | 10302 | chunk_remain_ = 0; | |
743 | 10302 | body_avail_ = 0; | |
744 | 10302 | nprepare_ = 0; | |
745 | |||
746 | 10302 | filter_ = nullptr; | |
747 | 10302 | eb_ = nullptr; | |
748 | 10302 | sink_ = nullptr; | |
749 | |||
750 | 10302 | got_header_ = false; | |
751 | 10302 | head_response_ = head_response; | |
752 | 10302 | needs_chunk_close_ = false; | |
753 | 10302 | trailer_headers_ = false; | |
754 | 10302 | chunked_body_ended = false; | |
755 | 10302 | } | |
756 | |||
757 | auto | ||
758 | 51003 | prepare() -> | |
759 | mutable_buffers_type | ||
760 | { | ||
761 | 51003 | nprepare_ = 0; | |
762 | |||
763 |
5/7✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 10374 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 40626 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
|
51003 | switch(state_) |
764 | { | ||
765 | 1 | default: | |
766 | case state::reset: | ||
767 | // reset must be called first | ||
768 | 1 | detail::throw_logic_error(); | |
769 | |||
770 | 1 | case state::start: | |
771 | // start must be called first | ||
772 | 1 | detail::throw_logic_error(); | |
773 | |||
774 | 10374 | case state::header: | |
775 | { | ||
776 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10374 times.
|
10374 | BOOST_ASSERT( |
777 | m_.h_.size < svc_.cfg.headers.max_size); | ||
778 | 10374 | std::size_t n = fb_.capacity() - fb_.size(); | |
779 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10374 times.
|
10374 | BOOST_ASSERT(n <= svc_.max_overread()); |
780 | 10374 | n = clamp(n, svc_.cfg.max_prepare); | |
781 | 10374 | mbp_[0] = fb_.prepare(n); | |
782 | 10374 | nprepare_ = n; | |
783 | 10374 | return mutable_buffers_type(&mbp_[0], 1); | |
784 | } | ||
785 | |||
786 | ✗ | case state::header_done: | |
787 | // forgot to call parse() | ||
788 | ✗ | detail::throw_logic_error(); | |
789 | |||
790 | 40626 | case state::body: | |
791 | { | ||
792 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40626 times.
|
40626 | if(got_eof_) |
793 | { | ||
794 | // forgot to call parse() | ||
795 | ✗ | detail::throw_logic_error(); | |
796 | } | ||
797 | |||
798 |
2/2✓ Branch 1 taken 21575 times.
✓ Branch 2 taken 19051 times.
|
40626 | if(! is_plain()) |
799 | { | ||
800 | // buffered payload | ||
801 | 21575 | std::size_t n = cb0_.capacity(); | |
802 | 21575 | n = clamp(n, svc_.cfg.max_prepare); | |
803 | 21575 | nprepare_ = n; | |
804 | 21575 | mbp_ = cb0_.prepare(n); | |
805 | 21575 | return detail::make_span(mbp_); | |
806 | } | ||
807 | else | ||
808 | { | ||
809 |
2/2✓ Branch 0 taken 19030 times.
✓ Branch 1 taken 21 times.
|
19051 | switch(style_) |
810 | { | ||
811 | 19030 | default: | |
812 | case style::in_place: | ||
813 | case style::sink: | ||
814 | { | ||
815 | 19030 | std::size_t n = cb0_.capacity(); | |
816 | 19030 | n = clamp(n, svc_.cfg.max_prepare); | |
817 | |||
818 |
2/2✓ Branch 1 taken 19005 times.
✓ Branch 2 taken 25 times.
|
19030 | if(m_.payload() == payload::size) |
819 | { | ||
820 |
2/2✓ Branch 0 taken 17798 times.
✓ Branch 1 taken 1207 times.
|
19005 | if(n > payload_remain_) |
821 | { | ||
822 | 17798 | std::size_t overread = | |
823 | 17798 | n - static_cast<std::size_t>(payload_remain_); | |
824 |
2/2✓ Branch 1 taken 7878 times.
✓ Branch 2 taken 9920 times.
|
17798 | if(overread > svc_.max_overread()) |
825 | 7878 | n = static_cast<std::size_t>(payload_remain_) + | |
826 | 7878 | svc_.max_overread(); | |
827 | } | ||
828 | } | ||
829 | else | ||
830 | { | ||
831 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
|
25 | BOOST_ASSERT( |
832 | m_.payload() == payload::to_eof); | ||
833 | // No more messages can be pipelined, so | ||
834 | // limit the output buffer to the remaining | ||
835 | // body limit plus one byte to detect | ||
836 | // exhaustion. | ||
837 | 25 | std::uint64_t r = body_limit_remain(); | |
838 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | if(r != std::uint64_t(-1)) |
839 | 25 | r += 1; | |
840 | 25 | n = clamp(r, n); | |
841 | } | ||
842 | |||
843 | 19030 | nprepare_ = n; | |
844 | 19030 | mbp_ = cb0_.prepare(n); | |
845 | 19030 | return detail::make_span(mbp_); | |
846 | } | ||
847 | 21 | case style::elastic: | |
848 | { | ||
849 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
|
21 | BOOST_ASSERT(cb0_.size() == 0); |
850 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | BOOST_ASSERT(body_avail_ == 0); |
851 | |||
852 | 21 | std::size_t n = svc_.cfg.min_buffer; | |
853 | |||
854 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 15 times.
|
21 | if(m_.payload() == payload::size) |
855 | { | ||
856 | // Overreads are not allowed, or | ||
857 | // else the caller will see extra | ||
858 | // unrelated data. | ||
859 | 6 | n = clamp(payload_remain_, n); | |
860 | } | ||
861 | else | ||
862 | { | ||
863 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
|
15 | BOOST_ASSERT( |
864 | m_.payload() == payload::to_eof); | ||
865 | // No more messages can be pipelined, so | ||
866 | // limit the output buffer to the remaining | ||
867 | // body limit plus one byte to detect | ||
868 | // exhaustion. | ||
869 | 15 | std::uint64_t r = body_limit_remain(); | |
870 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | if(r != std::uint64_t(-1)) |
871 | 15 | r += 1; | |
872 | 15 | n = clamp(r, n); | |
873 | 15 | n = clamp(n, eb_->max_size() - eb_->size()); | |
874 | // fill capacity first to avoid an allocation | ||
875 | std::size_t avail = | ||
876 | 15 | eb_->capacity() - eb_->size(); | |
877 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | if(avail != 0) |
878 | 15 | n = clamp(n, avail); | |
879 | |||
880 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 14 times.
|
15 | if(n == 0) |
881 | { | ||
882 | // dynamic buffer is full | ||
883 | // attempt a 1 byte read so | ||
884 | // we can detect overflow | ||
885 | 1 | nprepare_ = 1; | |
886 | 1 | mbp_ = cb0_.prepare(1); | |
887 | 1 | return detail::make_span(mbp_); | |
888 | } | ||
889 | } | ||
890 | |||
891 | 20 | n = clamp(n, svc_.cfg.max_prepare); | |
892 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | BOOST_ASSERT(n != 0); |
893 | 20 | nprepare_ = n; | |
894 | 20 | return eb_->prepare(n); | |
895 | } | ||
896 | } | ||
897 | } | ||
898 | } | ||
899 | |||
900 | ✗ | case state::set_body: | |
901 | // forgot to call parse() | ||
902 | ✗ | detail::throw_logic_error(); | |
903 | |||
904 | 1 | case state::complete_in_place: | |
905 | case state::complete: | ||
906 | // already complete | ||
907 | 1 | detail::throw_logic_error(); | |
908 | } | ||
909 | } | ||
910 | |||
911 | void | ||
912 | 51000 | commit( | |
913 | std::size_t n) | ||
914 | { | ||
915 |
5/7✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 10374 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 40623 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
|
51000 | switch(state_) |
916 | { | ||
917 | 1 | default: | |
918 | case state::reset: | ||
919 | { | ||
920 | // reset must be called first | ||
921 | 1 | detail::throw_logic_error(); | |
922 | } | ||
923 | |||
924 | 1 | case state::start: | |
925 | { | ||
926 | // forgot to call start() | ||
927 | 1 | detail::throw_logic_error(); | |
928 | } | ||
929 | |||
930 | 10374 | case state::header: | |
931 | { | ||
932 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10373 times.
|
10374 | if(n > nprepare_) |
933 | { | ||
934 | // n can't be greater than size of | ||
935 | // the buffers returned by prepare() | ||
936 | 1 | detail::throw_invalid_argument(); | |
937 | } | ||
938 | |||
939 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10372 times.
|
10373 | if(got_eof_) |
940 | { | ||
941 | // can't commit after EOF | ||
942 | 1 | detail::throw_logic_error(); | |
943 | } | ||
944 | |||
945 | 10372 | nprepare_ = 0; // invalidate | |
946 | 10372 | fb_.commit(n); | |
947 | 10372 | break; | |
948 | } | ||
949 | |||
950 | ✗ | case state::header_done: | |
951 | { | ||
952 | // forgot to call parse() | ||
953 | ✗ | detail::throw_logic_error(); | |
954 | } | ||
955 | |||
956 | 40623 | case state::body: | |
957 | { | ||
958 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 40621 times.
|
40623 | if(n > nprepare_) |
959 | { | ||
960 | // n can't be greater than size of | ||
961 | // the buffers returned by prepare() | ||
962 | 2 | detail::throw_invalid_argument(); | |
963 | } | ||
964 | |||
965 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40621 times.
|
40621 | if(got_eof_) |
966 | { | ||
967 | // can't commit after EOF | ||
968 | ✗ | detail::throw_logic_error(); | |
969 | } | ||
970 | |||
971 | 40621 | nprepare_ = 0; // invalidate | |
972 |
6/6✓ Branch 1 taken 19046 times.
✓ Branch 2 taken 21575 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 19026 times.
✓ Branch 5 taken 20 times.
✓ Branch 6 taken 40601 times.
|
40621 | if(is_plain() && style_ == style::elastic) |
973 | { | ||
974 |
2/2✓ Branch 2 taken 1 times.
✓ Branch 3 taken 19 times.
|
20 | if(eb_->max_size() == eb_->size()) |
975 | { | ||
976 | // borrowed 1 byte from | ||
977 | // cb0_ in prepare() | ||
978 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | BOOST_ASSERT(n <= 1); |
979 | 1 | cb0_.commit(n); | |
980 | } | ||
981 | else | ||
982 | { | ||
983 | 19 | eb_->commit(n); | |
984 | 19 | payload_remain_ -= n; | |
985 | 19 | body_total_ += n; | |
986 | } | ||
987 | } | ||
988 | else | ||
989 | { | ||
990 | 40601 | cb0_.commit(n); | |
991 | } | ||
992 | 40621 | break; | |
993 | } | ||
994 | |||
995 | ✗ | case state::set_body: | |
996 | { | ||
997 | // forgot to call parse() | ||
998 | ✗ | detail::throw_logic_error(); | |
999 | } | ||
1000 | |||
1001 | 1 | case state::complete_in_place: | |
1002 | case state::complete: | ||
1003 | { | ||
1004 | // already complete | ||
1005 | 1 | detail::throw_logic_error(); | |
1006 | } | ||
1007 | } | ||
1008 | 50993 | } | |
1009 | |||
1010 | void | ||
1011 | 401 | commit_eof() | |
1012 | { | ||
1013 | 401 | nprepare_ = 0; // invalidate | |
1014 | |||
1015 |
5/7✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 368 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
|
401 | switch(state_) |
1016 | { | ||
1017 | 1 | default: | |
1018 | case state::reset: | ||
1019 | // reset must be called first | ||
1020 | 1 | detail::throw_logic_error(); | |
1021 | |||
1022 | 1 | case state::start: | |
1023 | // forgot to call start() | ||
1024 | 1 | detail::throw_logic_error(); | |
1025 | |||
1026 | 30 | case state::header: | |
1027 | 30 | got_eof_ = true; | |
1028 | 30 | break; | |
1029 | |||
1030 | ✗ | case state::header_done: | |
1031 | // forgot to call parse() | ||
1032 | ✗ | detail::throw_logic_error(); | |
1033 | |||
1034 | 368 | case state::body: | |
1035 | 368 | got_eof_ = true; | |
1036 | 368 | break; | |
1037 | |||
1038 | ✗ | case state::set_body: | |
1039 | // forgot to call parse() | ||
1040 | ✗ | detail::throw_logic_error(); | |
1041 | |||
1042 | 1 | case state::complete_in_place: | |
1043 | case state::complete: | ||
1044 | // can't commit eof when complete | ||
1045 | 1 | detail::throw_logic_error(); | |
1046 | } | ||
1047 | 398 | } | |
1048 | |||
1049 | void | ||
1050 | 69827 | parse( | |
1051 | system::error_code& ec) | ||
1052 | { | ||
1053 | 69827 | ec = {}; | |
1054 |
7/7✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 16650 times.
✓ Branch 3 taken 9083 times.
✓ Branch 4 taken 41299 times.
✓ Branch 5 taken 2333 times.
✓ Branch 6 taken 460 times.
|
69827 | switch(state_) |
1055 | { | ||
1056 | 1 | default: | |
1057 | case state::reset: | ||
1058 | // reset must be called first | ||
1059 | 1 | detail::throw_logic_error(); | |
1060 | |||
1061 | 1 | case state::start: | |
1062 | // start must be called first | ||
1063 | 1 | detail::throw_logic_error(); | |
1064 | |||
1065 | 16650 | case state::header: | |
1066 | { | ||
1067 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 16650 times.
|
16650 | BOOST_ASSERT(m_.h_.buf == static_cast< |
1068 | void const*>(ws_.data())); | ||
1069 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 16650 times.
|
16650 | BOOST_ASSERT(m_.h_.cbuf == static_cast< |
1070 | void const*>(ws_.data())); | ||
1071 | |||
1072 | 16650 | m_.h_.parse(fb_.size(), svc_.cfg.headers, ec); | |
1073 | |||
1074 |
2/2✓ Branch 2 taken 6385 times.
✓ Branch 3 taken 10265 times.
|
16650 | if(ec == condition::need_more_input) |
1075 | { | ||
1076 |
2/2✓ Branch 0 taken 6358 times.
✓ Branch 1 taken 27 times.
|
6385 | if(! got_eof_) |
1077 | { | ||
1078 | // headers incomplete | ||
1079 | 6358 | return; | |
1080 | } | ||
1081 | |||
1082 |
2/2✓ Branch 1 taken 12 times.
✓ Branch 2 taken 15 times.
|
27 | if(fb_.size() == 0) |
1083 | { | ||
1084 | // stream closed cleanly | ||
1085 | 12 | state_ = state::reset; | |
1086 | 24 | ec = BOOST_HTTP_PROTO_ERR( | |
1087 | error::end_of_stream); | ||
1088 | 12 | return; | |
1089 | } | ||
1090 | |||
1091 | // stream closed with a | ||
1092 | // partial message received | ||
1093 | 15 | state_ = state::reset; | |
1094 | 30 | ec = BOOST_HTTP_PROTO_ERR( | |
1095 | error::incomplete); | ||
1096 | 15 | return; | |
1097 | } | ||
1098 |
2/2✓ Branch 1 taken 259 times.
✓ Branch 2 taken 10006 times.
|
10265 | else if(ec.failed()) |
1099 | { | ||
1100 | // other error, | ||
1101 | // | ||
1102 | // VFALCO map this to a bad | ||
1103 | // request or bad response error? | ||
1104 | // | ||
1105 | 259 | state_ = state::reset; // unrecoverable | |
1106 | 259 | return; | |
1107 | } | ||
1108 | |||
1109 | 10006 | got_header_ = true; | |
1110 | |||
1111 | // reserve headers + table | ||
1112 | 10006 | ws_.reserve_front(m_.h_.size); | |
1113 | 10006 | ws_.reserve_back(m_.h_.table_space()); | |
1114 | |||
1115 | // no payload | ||
1116 |
4/4✓ Branch 1 taken 9084 times.
✓ Branch 2 taken 922 times.
✓ Branch 3 taken 922 times.
✓ Branch 4 taken 9084 times.
|
19090 | if(m_.payload() == payload::none || |
1117 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9084 times.
|
9084 | head_response_) |
1118 | { | ||
1119 | // octets of the next message | ||
1120 | 922 | auto overread = fb_.size() - m_.h_.size; | |
1121 |
1/2✓ Branch 2 taken 922 times.
✗ Branch 3 not taken.
|
922 | cb0_ = { ws_.data(), overread, overread }; |
1122 | 922 | ws_.reserve_front(overread); | |
1123 | 922 | state_ = state::complete_in_place; | |
1124 | 922 | return; | |
1125 | } | ||
1126 | |||
1127 | 9084 | state_ = state::header_done; | |
1128 | 9084 | break; | |
1129 | } | ||
1130 | |||
1131 | 9083 | case state::header_done: | |
1132 | { | ||
1133 | // metadata error | ||
1134 |
2/2✓ Branch 1 taken 180 times.
✓ Branch 2 taken 8903 times.
|
9083 | if(m_.payload() == payload::error) |
1135 | { | ||
1136 | // VFALCO This needs looking at | ||
1137 | 360 | ec = BOOST_HTTP_PROTO_ERR( | |
1138 | error::bad_payload); | ||
1139 | 180 | state_ = state::reset; // unrecoverable | |
1140 | 180 | return; | |
1141 | } | ||
1142 | |||
1143 | // overread currently includes any and all octets that | ||
1144 | // extend beyond the current end of the header | ||
1145 | // this can include associated body octets for the | ||
1146 | // current message or octets of the next message in the | ||
1147 | // stream, e.g. pipelining is being used | ||
1148 | 8903 | auto const overread = fb_.size() - m_.h_.size; | |
1149 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 8903 times.
|
8903 | BOOST_ASSERT(overread <= svc_.max_overread()); |
1150 | |||
1151 | 8903 | auto cap = fb_.capacity() + overread + | |
1152 | 8903 | svc_.cfg.min_buffer; | |
1153 | |||
1154 | // reserve body buffers first, as the decoder | ||
1155 | // must be installed after them. | ||
1156 | 8903 | auto const p = ws_.reserve_front(cap); | |
1157 | |||
1158 |
3/4✓ Branch 1 taken 36 times.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8831 times.
|
8903 | switch(m_.metadata().content_encoding.coding) |
1159 | { | ||
1160 | 36 | case content_coding::deflate: | |
1161 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
|
36 | if(!svc_.cfg.apply_deflate_decoder) |
1162 | ✗ | goto no_filter; | |
1163 | 72 | filter_ = &ws_.emplace<zlib_filter>( | |
1164 | 36 | ctx_, ws_, svc_.cfg.zlib_window_bits); | |
1165 | 36 | break; | |
1166 | |||
1167 | 36 | case content_coding::gzip: | |
1168 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
|
36 | if(!svc_.cfg.apply_gzip_decoder) |
1169 | ✗ | goto no_filter; | |
1170 | 72 | filter_ = &ws_.emplace<zlib_filter>( | |
1171 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | ctx_, ws_, svc_.cfg.zlib_window_bits + 16); |
1172 | 36 | break; | |
1173 | |||
1174 | ✗ | case content_coding::br: | |
1175 | ✗ | if(!svc_.cfg.apply_brotli_decoder) | |
1176 | ✗ | goto no_filter; | |
1177 | ✗ | filter_ = &ws_.emplace<brotli_filter>( | |
1178 | ✗ | ctx_, ws_); | |
1179 | ✗ | break; | |
1180 | |||
1181 | ✗ | no_filter: | |
1182 | 8831 | default: | |
1183 | 8831 | cap += svc_.max_codec; | |
1184 | 8831 | ws_.reserve_front(svc_.max_codec); | |
1185 | 8831 | break; | |
1186 | } | ||
1187 | |||
1188 |
6/6✓ Branch 1 taken 4205 times.
✓ Branch 2 taken 4698 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 4181 times.
✓ Branch 5 taken 4722 times.
✓ Branch 6 taken 4181 times.
|
8903 | if(is_plain() || style_ == style::elastic) |
1189 | { | ||
1190 |
1/2✓ Branch 1 taken 4722 times.
✗ Branch 2 not taken.
|
4722 | cb0_ = { p, cap, overread }; |
1191 | 4722 | cb1_ = {}; | |
1192 | } | ||
1193 | else | ||
1194 | { | ||
1195 | // buffered payload | ||
1196 | 8362 | std::size_t n0 = (overread > svc_.cfg.min_buffer) | |
1197 |
2/2✓ Branch 0 taken 4157 times.
✓ Branch 1 taken 24 times.
|
4181 | ? overread |
1198 | 4157 | : svc_.cfg.min_buffer; | |
1199 | 4181 | std::size_t n1 = svc_.cfg.min_buffer; | |
1200 | |||
1201 |
1/2✓ Branch 1 taken 4181 times.
✗ Branch 2 not taken.
|
4181 | cb0_ = { p , n0, overread }; |
1202 | 4181 | cb1_ = { p + n0 , n1 }; | |
1203 | } | ||
1204 | |||
1205 |
2/2✓ Branch 1 taken 4374 times.
✓ Branch 2 taken 4529 times.
|
8903 | if(m_.payload() == payload::size) |
1206 | { | ||
1207 |
6/6✓ Branch 0 taken 4350 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4349 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 4373 times.
|
8724 | if(!filter_ && |
1208 | 4350 | body_limit_ < m_.payload_size()) | |
1209 | { | ||
1210 | 2 | ec = BOOST_HTTP_PROTO_ERR( | |
1211 | error::body_too_large); | ||
1212 | 1 | state_ = state::reset; | |
1213 | 1 | return; | |
1214 | } | ||
1215 | 4373 | payload_remain_ = m_.payload_size(); | |
1216 | } | ||
1217 | |||
1218 | 8902 | state_ = state::body; | |
1219 | BOOST_FALLTHROUGH; | ||
1220 | } | ||
1221 | |||
1222 | case state::body: | ||
1223 | { | ||
1224 | 50201 | do_body: | |
1225 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 50201 times.
|
50201 | BOOST_ASSERT(state_ == state::body); |
1226 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 50201 times.
|
50201 | BOOST_ASSERT(m_.payload() != payload::none); |
1227 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 50201 times.
|
50201 | BOOST_ASSERT(m_.payload() != payload::error); |
1228 | |||
1229 | 8797 | auto set_state_to_complete = [&]() | |
1230 | { | ||
1231 |
2/2✓ Branch 0 taken 8337 times.
✓ Branch 1 taken 460 times.
|
8797 | if(style_ == style::in_place) |
1232 | { | ||
1233 | 8337 | state_ = state::complete_in_place; | |
1234 | 8337 | return; | |
1235 | } | ||
1236 | 460 | state_ = state::complete; | |
1237 | 50201 | }; | |
1238 | |||
1239 |
2/2✓ Branch 1 taken 24436 times.
✓ Branch 2 taken 25765 times.
|
50201 | if(m_.payload() == payload::chunked) |
1240 | { | ||
1241 | for(;;) | ||
1242 | { | ||
1243 |
2/2✓ Branch 0 taken 124351 times.
✓ Branch 1 taken 1153 times.
|
125504 | if(chunk_remain_ == 0 |
1244 |
2/2✓ Branch 0 taken 120206 times.
✓ Branch 1 taken 4145 times.
|
124351 | && !chunked_body_ended) |
1245 | { | ||
1246 | 120206 | auto cs = chained_sequence(cb0_.data()); | |
1247 | 19411 | auto check_ec = [&]() | |
1248 | { | ||
1249 |
4/6✓ Branch 2 taken 19402 times.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 19402 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 19411 times.
|
19411 | if(ec == condition::need_more_input && got_eof_) |
1250 | { | ||
1251 | ✗ | ec = BOOST_HTTP_PROTO_ERR(error::incomplete); | |
1252 | ✗ | state_ = state::reset; | |
1253 | } | ||
1254 | 139617 | }; | |
1255 | |||
1256 |
2/2✓ Branch 0 taken 111566 times.
✓ Branch 1 taken 8640 times.
|
120206 | if(needs_chunk_close_) |
1257 | { | ||
1258 | 111566 | parse_eol(cs, ec); | |
1259 |
2/2✓ Branch 1 taken 17 times.
✓ Branch 2 taken 111549 times.
|
111566 | if(ec) |
1260 | { | ||
1261 | 17 | check_ec(); | |
1262 | 19411 | return; | |
1263 | } | ||
1264 | } | ||
1265 |
2/2✓ Branch 0 taken 4223 times.
✓ Branch 1 taken 4417 times.
|
8640 | else if(trailer_headers_) |
1266 | { | ||
1267 | 4223 | skip_trailer_headers(cs, ec); | |
1268 |
2/2✓ Branch 1 taken 78 times.
✓ Branch 2 taken 4145 times.
|
4223 | if(ec) |
1269 | { | ||
1270 | 78 | check_ec(); | |
1271 | 78 | return; | |
1272 | } | ||
1273 | 4145 | cb0_.consume(cb0_.size() - cs.size()); | |
1274 | 4145 | chunked_body_ended = true; | |
1275 | 8292 | continue; | |
1276 | } | ||
1277 | |||
1278 | 115966 | auto chunk_size = parse_hex(cs, ec); | |
1279 |
2/2✓ Branch 1 taken 19284 times.
✓ Branch 2 taken 96682 times.
|
115966 | if(ec) |
1280 | { | ||
1281 | 19284 | check_ec(); | |
1282 | 19284 | return; | |
1283 | } | ||
1284 | |||
1285 | // skip chunk extensions | ||
1286 | 96682 | find_eol(cs, ec); | |
1287 |
2/2✓ Branch 1 taken 32 times.
✓ Branch 2 taken 96650 times.
|
96682 | if(ec) |
1288 | { | ||
1289 | 32 | check_ec(); | |
1290 | 32 | return; | |
1291 | } | ||
1292 | |||
1293 | 96650 | cb0_.consume(cb0_.size() - cs.size()); | |
1294 | 96650 | chunk_remain_ = chunk_size; | |
1295 | |||
1296 | 96650 | needs_chunk_close_ = true; | |
1297 |
2/2✓ Branch 0 taken 4147 times.
✓ Branch 1 taken 92503 times.
|
96650 | if(chunk_remain_ == 0) |
1298 | { | ||
1299 | 4147 | needs_chunk_close_ = false; | |
1300 | 4147 | trailer_headers_ = true; | |
1301 | 4147 | continue; | |
1302 | } | ||
1303 | } | ||
1304 | |||
1305 |
6/6✓ Branch 1 taken 2485 times.
✓ Branch 2 taken 95316 times.
✓ Branch 3 taken 340 times.
✓ Branch 4 taken 2145 times.
✓ Branch 5 taken 340 times.
✓ Branch 6 taken 97461 times.
|
97801 | if(cb0_.size() == 0 && !chunked_body_ended) |
1306 | { | ||
1307 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 339 times.
|
340 | if(got_eof_) |
1308 | { | ||
1309 | 2 | ec = BOOST_HTTP_PROTO_ERR( | |
1310 | error::incomplete); | ||
1311 | 1 | state_ = state::reset; | |
1312 | 1 | return; | |
1313 | } | ||
1314 | |||
1315 | 678 | ec = BOOST_HTTP_PROTO_ERR( | |
1316 | error::need_data); | ||
1317 | 339 | return; | |
1318 | } | ||
1319 | |||
1320 |
2/2✓ Branch 0 taken 51079 times.
✓ Branch 1 taken 46382 times.
|
97461 | if(filter_) |
1321 | { | ||
1322 |
1/2✓ Branch 2 taken 51079 times.
✗ Branch 3 not taken.
|
51079 | chunk_remain_ -= apply_filter( |
1323 | ec, | ||
1324 | clamp(chunk_remain_, cb0_.size()), | ||
1325 | 51079 | !chunked_body_ended); | |
1326 | |||
1327 |
6/6✓ Branch 1 taken 50539 times.
✓ Branch 2 taken 540 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 50515 times.
✓ Branch 5 taken 564 times.
✓ Branch 6 taken 50515 times.
|
51079 | if(ec || chunked_body_ended) |
1328 | 564 | return; | |
1329 | } | ||
1330 | else | ||
1331 | { | ||
1332 | const std::size_t chunk_avail = | ||
1333 | 46382 | clamp(chunk_remain_, cb0_.size()); | |
1334 | const auto chunk = | ||
1335 | 46382 | buffers::prefix(cb0_.data(), chunk_avail); | |
1336 | |||
1337 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 46382 times.
|
46382 | if(body_limit_remain() < chunk_avail) |
1338 | { | ||
1339 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
1340 | error::body_too_large); | ||
1341 | ✗ | state_ = state::reset; | |
1342 | 4121 | return; | |
1343 | } | ||
1344 | |||
1345 |
1/4✓ Branch 0 taken 46382 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
46382 | switch(style_) |
1346 | { | ||
1347 | 46382 | case style::in_place: | |
1348 | { | ||
1349 | 46382 | auto copied = buffers::copy( | |
1350 |
1/2✓ Branch 2 taken 46382 times.
✗ Branch 3 not taken.
|
46382 | cb1_.prepare(cb1_.capacity()), |
1351 | chunk); | ||
1352 | 46382 | chunk_remain_ -= copied; | |
1353 | 46382 | body_avail_ += copied; | |
1354 | 46382 | body_total_ += copied; | |
1355 | 46382 | cb0_.consume(copied); | |
1356 | 46382 | cb1_.commit(copied); | |
1357 | 46382 | if(cb1_.capacity() == 0 | |
1358 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 46382 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 46382 times.
|
46382 | && !chunked_body_ended) |
1359 | { | ||
1360 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
1361 | error::in_place_overflow); | ||
1362 | ✗ | return; | |
1363 | } | ||
1364 | 46382 | break; | |
1365 | } | ||
1366 | ✗ | case style::sink: | |
1367 | { | ||
1368 | ✗ | auto sink_rs = sink_->write( | |
1369 | ✗ | chunk, !chunked_body_ended); | |
1370 | ✗ | chunk_remain_ -= sink_rs.bytes; | |
1371 | ✗ | body_total_ += sink_rs.bytes; | |
1372 | ✗ | cb0_.consume(sink_rs.bytes); | |
1373 | ✗ | if(sink_rs.ec.failed()) | |
1374 | { | ||
1375 | ✗ | body_avail_ += | |
1376 | ✗ | chunk_avail - sink_rs.bytes; | |
1377 | ✗ | ec = sink_rs.ec; | |
1378 | ✗ | state_ = state::reset; | |
1379 | ✗ | return; | |
1380 | } | ||
1381 | ✗ | break; | |
1382 | } | ||
1383 | ✗ | case style::elastic: | |
1384 | { | ||
1385 | ✗ | if(eb_->max_size() - eb_->size() | |
1386 | ✗ | < chunk_avail) | |
1387 | { | ||
1388 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
1389 | error::buffer_overflow); | ||
1390 | ✗ | state_ = state::reset; | |
1391 | ✗ | return; | |
1392 | } | ||
1393 | ✗ | buffers::copy( | |
1394 | ✗ | eb_->prepare(chunk_avail), | |
1395 | chunk); | ||
1396 | ✗ | chunk_remain_ -= chunk_avail; | |
1397 | ✗ | body_total_ += chunk_avail; | |
1398 | ✗ | cb0_.consume(chunk_avail); | |
1399 | ✗ | eb_->commit(chunk_avail); | |
1400 | ✗ | break; | |
1401 | } | ||
1402 | } | ||
1403 | |||
1404 |
2/2✓ Branch 0 taken 4121 times.
✓ Branch 1 taken 42261 times.
|
46382 | if(chunked_body_ended) |
1405 | { | ||
1406 | 4121 | set_state_to_complete(); | |
1407 | 4121 | return; | |
1408 | } | ||
1409 | } | ||
1410 | 101068 | } | |
1411 | } | ||
1412 | else | ||
1413 | { | ||
1414 | // non-chunked payload | ||
1415 | |||
1416 | 77295 | const std::size_t payload_avail = [&]() | |
1417 | { | ||
1418 | 25765 | auto ret = cb0_.size(); | |
1419 |
2/2✓ Branch 0 taken 24121 times.
✓ Branch 1 taken 1644 times.
|
25765 | if(!filter_) |
1420 | 24121 | ret -= body_avail_; | |
1421 |
2/2✓ Branch 1 taken 24159 times.
✓ Branch 2 taken 1606 times.
|
25765 | if(m_.payload() == payload::size) |
1422 | 24159 | return clamp(payload_remain_, ret); | |
1423 | // payload::eof | ||
1424 | 1606 | return ret; | |
1425 | 25765 | }(); | |
1426 | |||
1427 | 77295 | const bool is_complete = [&]() | |
1428 | { | ||
1429 |
2/2✓ Branch 1 taken 24159 times.
✓ Branch 2 taken 1606 times.
|
25765 | if(m_.payload() == payload::size) |
1430 | 24159 | return payload_avail == payload_remain_; | |
1431 | // payload::eof | ||
1432 | 1606 | return got_eof_; | |
1433 | 25765 | }(); | |
1434 | |||
1435 |
2/2✓ Branch 0 taken 1644 times.
✓ Branch 1 taken 24121 times.
|
25765 | if(filter_) |
1436 | { | ||
1437 | 3288 | payload_remain_ -= apply_filter( | |
1438 |
1/2✓ Branch 1 taken 1644 times.
✗ Branch 2 not taken.
|
1644 | ec, payload_avail, !is_complete); |
1439 |
6/6✓ Branch 1 taken 564 times.
✓ Branch 2 taken 1080 times.
✓ Branch 3 taken 48 times.
✓ Branch 4 taken 516 times.
✓ Branch 5 taken 1128 times.
✓ Branch 6 taken 516 times.
|
1644 | if(ec || is_complete) |
1440 | 1128 | return; | |
1441 | } | ||
1442 | else | ||
1443 | { | ||
1444 | // plain body | ||
1445 | |||
1446 |
2/2✓ Branch 1 taken 764 times.
✓ Branch 2 taken 23357 times.
|
24121 | if(m_.payload() == payload::to_eof) |
1447 | { | ||
1448 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 763 times.
|
764 | if(body_limit_remain() < payload_avail) |
1449 | { | ||
1450 | 2 | ec = BOOST_HTTP_PROTO_ERR( | |
1451 | error::body_too_large); | ||
1452 | 1 | state_ = state::reset; | |
1453 | 1 | return; | |
1454 | } | ||
1455 | } | ||
1456 | |||
1457 |
3/4✓ Branch 0 taken 23363 times.
✓ Branch 1 taken 371 times.
✓ Branch 2 taken 386 times.
✗ Branch 3 not taken.
|
24120 | switch(style_) |
1458 | { | ||
1459 | 23363 | case style::in_place: | |
1460 | { | ||
1461 | 23363 | payload_remain_ -= payload_avail; | |
1462 | 23363 | body_avail_ += payload_avail; | |
1463 | 23363 | body_total_ += payload_avail; | |
1464 |
5/6✓ Branch 1 taken 1 times.
✓ Branch 2 taken 23362 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 23362 times.
|
23363 | if(cb0_.capacity() == 0 && !is_complete) |
1465 | { | ||
1466 | 2 | ec = BOOST_HTTP_PROTO_ERR( | |
1467 | error::in_place_overflow); | ||
1468 | 1 | return; | |
1469 | } | ||
1470 | 23362 | break; | |
1471 | } | ||
1472 | 371 | case style::sink: | |
1473 | { | ||
1474 | 371 | payload_remain_ -= payload_avail; | |
1475 | 371 | body_total_ += payload_avail; | |
1476 |
1/2✓ Branch 1 taken 371 times.
✗ Branch 2 not taken.
|
371 | auto sink_rs = sink_->write( |
1477 | 371 | buffers::prefix(cb0_.data(), payload_avail), | |
1478 | 371 | !is_complete); | |
1479 | 371 | cb0_.consume(sink_rs.bytes); | |
1480 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 371 times.
|
371 | if(sink_rs.ec.failed()) |
1481 | { | ||
1482 | ✗ | body_avail_ += | |
1483 | ✗ | payload_avail - sink_rs.bytes; | |
1484 | ✗ | ec = sink_rs.ec; | |
1485 | ✗ | state_ = state::reset; | |
1486 | ✗ | return; | |
1487 | } | ||
1488 | 371 | break; | |
1489 | } | ||
1490 | 386 | case style::elastic: | |
1491 | { | ||
1492 | // payload_remain_ and body_total_ | ||
1493 | // are already updated in commit() | ||
1494 | |||
1495 | // cb0_ contains data | ||
1496 |
2/2✓ Branch 0 taken 193 times.
✓ Branch 1 taken 193 times.
|
386 | if(payload_avail != 0) |
1497 | { | ||
1498 |
2/4✓ Branch 1 taken 193 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 193 times.
✗ Branch 5 not taken.
|
193 | if(eb_->max_size() - eb_->size() |
1499 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 192 times.
|
193 | < payload_avail) |
1500 | { | ||
1501 | 2 | ec = BOOST_HTTP_PROTO_ERR( | |
1502 | error::buffer_overflow); | ||
1503 | 1 | state_ = state::reset; | |
1504 | 1 | return; | |
1505 | } | ||
1506 | // only happens when an elastic body | ||
1507 | // is attached in header_done state | ||
1508 | 192 | buffers::copy( | |
1509 |
1/2✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
|
192 | eb_->prepare(payload_avail), |
1510 | 192 | cb0_.data()); | |
1511 | 192 | cb0_.consume(payload_avail); | |
1512 |
1/2✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
|
192 | eb_->commit(payload_avail); |
1513 | 192 | payload_remain_ -= payload_avail; | |
1514 | 192 | body_total_ += payload_avail; | |
1515 | } | ||
1516 | 385 | break; | |
1517 | } | ||
1518 | } | ||
1519 | |||
1520 |
2/2✓ Branch 0 taken 4676 times.
✓ Branch 1 taken 19442 times.
|
24118 | if(is_complete) |
1521 | { | ||
1522 | 4676 | set_state_to_complete(); | |
1523 | 4676 | return; | |
1524 | } | ||
1525 | } | ||
1526 | |||
1527 |
6/6✓ Branch 1 taken 19257 times.
✓ Branch 2 taken 701 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 19256 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 19957 times.
|
19958 | if(m_.payload() == payload::size && got_eof_) |
1528 | { | ||
1529 | 2 | ec = BOOST_HTTP_PROTO_ERR( | |
1530 | error::incomplete); | ||
1531 | 1 | state_ = state::reset; | |
1532 | 1 | return; | |
1533 | } | ||
1534 | |||
1535 | 39914 | ec = BOOST_HTTP_PROTO_ERR( | |
1536 | error::need_data); | ||
1537 | 19957 | return; | |
1538 | } | ||
1539 | |||
1540 | break; | ||
1541 | } | ||
1542 | |||
1543 | 2333 | case state::set_body: | |
1544 | case state::complete_in_place: | ||
1545 | { | ||
1546 |
2/2✓ Branch 1 taken 426 times.
✓ Branch 2 taken 1907 times.
|
2333 | auto& body_buf = is_plain() ? cb0_ : cb1_; |
1547 | |||
1548 |
3/4✓ Branch 0 taken 2216 times.
✓ Branch 1 taken 58 times.
✓ Branch 2 taken 59 times.
✗ Branch 3 not taken.
|
2333 | switch(style_) |
1549 | { | ||
1550 | 2216 | case style::in_place: | |
1551 | 2216 | return; // no-op | |
1552 | 58 | case style::sink: | |
1553 | { | ||
1554 |
1/2✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
|
58 | auto rs = sink_->write( |
1555 | 58 | buffers::prefix(body_buf.data(), body_avail_), | |
1556 | 58 | state_ == state::set_body); | |
1557 | 58 | body_buf.consume(rs.bytes); | |
1558 | 58 | body_avail_ -= rs.bytes; | |
1559 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 58 times.
|
58 | if(rs.ec.failed()) |
1560 | { | ||
1561 | ✗ | ec = rs.ec; | |
1562 | ✗ | state_ = state::reset; | |
1563 | ✗ | return; | |
1564 | } | ||
1565 | 58 | break; | |
1566 | } | ||
1567 | 59 | case style::elastic: | |
1568 | { | ||
1569 | 59 | if(eb_->max_size() - eb_->size() | |
1570 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 59 times.
|
59 | < body_avail_) |
1571 | { | ||
1572 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
1573 | error::buffer_overflow); | ||
1574 | ✗ | return; | |
1575 | } | ||
1576 | 59 | buffers::copy( | |
1577 |
1/2✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
|
59 | eb_->prepare(body_avail_), |
1578 | 59 | body_buf.data()); | |
1579 | 59 | body_buf.consume(body_avail_); | |
1580 | 59 | eb_->commit(body_avail_); | |
1581 | 59 | body_avail_ = 0; | |
1582 | // TODO: expand cb0_ when possible? | ||
1583 | 59 | break; | |
1584 | } | ||
1585 | } | ||
1586 | |||
1587 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
|
117 | if(state_ == state::set_body) |
1588 | { | ||
1589 | ✗ | state_ = state::body; | |
1590 | ✗ | goto do_body; | |
1591 | } | ||
1592 | |||
1593 | 117 | state_ = state::complete; | |
1594 | 117 | break; | |
1595 | } | ||
1596 | |||
1597 | 460 | case state::complete: | |
1598 | 460 | break; | |
1599 | } | ||
1600 | } | ||
1601 | |||
1602 | auto | ||
1603 | 41250 | pull_body() -> | |
1604 | const_buffers_type | ||
1605 | { | ||
1606 |
1/3✗ Branch 0 not taken.
✓ Branch 1 taken 41250 times.
✗ Branch 2 not taken.
|
41250 | switch(state_) |
1607 | { | ||
1608 | ✗ | case state::header_done: | |
1609 | ✗ | return {}; | |
1610 | 41250 | case state::body: | |
1611 | case state::complete_in_place: | ||
1612 | 41250 | cbp_ = buffers::prefix( | |
1613 |
2/2✓ Branch 1 taken 18981 times.
✓ Branch 2 taken 22269 times.
|
41250 | (is_plain() ? cb0_ : cb1_).data(), |
1614 | body_avail_); | ||
1615 | 41250 | return detail::make_span(cbp_); | |
1616 | ✗ | default: | |
1617 | ✗ | detail::throw_logic_error(); | |
1618 | } | ||
1619 | } | ||
1620 | |||
1621 | void | ||
1622 | 39606 | consume_body(std::size_t n) | |
1623 | { | ||
1624 |
1/3✗ Branch 0 not taken.
✓ Branch 1 taken 39606 times.
✗ Branch 2 not taken.
|
39606 | switch(state_) |
1625 | { | ||
1626 | ✗ | case state::header_done: | |
1627 | ✗ | return; | |
1628 | 39606 | case state::body: | |
1629 | case state::complete_in_place: | ||
1630 | 39606 | n = clamp(n, body_avail_); | |
1631 |
2/2✓ Branch 1 taken 18981 times.
✓ Branch 2 taken 20625 times.
|
39606 | (is_plain() ? cb0_ : cb1_).consume(n); |
1632 | 39606 | body_avail_ -= n; | |
1633 | 39606 | return; | |
1634 | ✗ | default: | |
1635 | ✗ | detail::throw_logic_error(); | |
1636 | } | ||
1637 | } | ||
1638 | |||
1639 | core::string_view | ||
1640 | 700 | body() const | |
1641 | { | ||
1642 | // Precondition violation | ||
1643 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 700 times.
|
700 | if(state_ != state::complete_in_place) |
1644 | ✗ | detail::throw_logic_error(); | |
1645 | |||
1646 | // Precondition violation | ||
1647 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 700 times.
|
700 | if(body_avail_ != body_total_) |
1648 | ✗ | detail::throw_logic_error(); | |
1649 | |||
1650 |
2/2✓ Branch 1 taken 579 times.
✓ Branch 2 taken 121 times.
|
700 | auto cbp = (is_plain() ? cb0_ : cb1_).data(); |
1651 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 700 times.
|
700 | BOOST_ASSERT(cbp[1].size() == 0); |
1652 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 700 times.
|
700 | BOOST_ASSERT(cbp[0].size() == body_avail_); |
1653 | 700 | return core::string_view( | |
1654 | 700 | static_cast<char const*>(cbp[0].data()), | |
1655 | 1400 | body_avail_); | |
1656 | } | ||
1657 | |||
1658 | void | ||
1659 | 77 | set_body_limit(std::uint64_t n) | |
1660 | { | ||
1661 |
3/3✓ Branch 0 taken 73 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
77 | switch(state_) |
1662 | { | ||
1663 | 73 | case state::header: | |
1664 | case state::header_done: | ||
1665 | 73 | body_limit_ = n; | |
1666 | 73 | break; | |
1667 | 2 | case state::complete_in_place: | |
1668 | // only allowed for empty bodies | ||
1669 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if(body_total_ == 0) |
1670 | 1 | break; | |
1671 | BOOST_FALLTHROUGH; | ||
1672 | default: | ||
1673 | // set body_limit before parsing the body | ||
1674 | 3 | detail::throw_logic_error(); | |
1675 | } | ||
1676 | 74 | } | |
1677 | |||
1678 | void | ||
1679 | 383 | set_body( | |
1680 | buffers::any_dynamic_buffer& eb) noexcept | ||
1681 | { | ||
1682 | 383 | eb_ = &eb; | |
1683 | 383 | style_ = style::elastic; | |
1684 | 383 | nprepare_ = 0; // invalidate | |
1685 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 383 times.
|
383 | if(state_ == state::body) |
1686 | ✗ | state_ = state::set_body; | |
1687 | 383 | } | |
1688 | |||
1689 | void | ||
1690 | 372 | set_body(sink& s) noexcept | |
1691 | { | ||
1692 | 372 | sink_ = &s; | |
1693 | 372 | style_ = style::sink; | |
1694 | 372 | nprepare_ = 0; // invalidate | |
1695 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 372 times.
|
372 | if(state_ == state::body) |
1696 | ✗ | state_ = state::set_body; | |
1697 | 372 | } | |
1698 | |||
1699 | detail::workspace& | ||
1700 | 755 | ws() noexcept | |
1701 | { | ||
1702 | 755 | return ws_; | |
1703 | } | ||
1704 | |||
1705 | private: | ||
1706 | bool | ||
1707 | 182054 | is_plain() const noexcept | |
1708 | { | ||
1709 |
4/4✓ Branch 0 taken 172346 times.
✓ Branch 1 taken 9708 times.
✓ Branch 2 taken 85762 times.
✓ Branch 3 taken 86584 times.
|
354400 | return ! filter_ && |
1710 | 354400 | m_.payload() != payload::chunked; | |
1711 | } | ||
1712 | |||
1713 | std::uint64_t | ||
1714 | 157938 | body_limit_remain() const noexcept | |
1715 | { | ||
1716 | 157938 | return body_limit_ - body_total_; | |
1717 | } | ||
1718 | |||
1719 | std::size_t | ||
1720 | 52723 | apply_filter( | |
1721 | system::error_code& ec, | ||
1722 | std::size_t payload_avail, | ||
1723 | bool more) | ||
1724 | { | ||
1725 | 52723 | std::size_t p0 = payload_avail; | |
1726 | for(;;) | ||
1727 | { | ||
1728 |
4/4✓ Branch 0 taken 51031 times.
✓ Branch 1 taken 56138 times.
✓ Branch 2 taken 50983 times.
✓ Branch 3 taken 48 times.
|
107169 | if(payload_avail == 0 && more) |
1729 | 51103 | break; | |
1730 | |||
1731 | ✗ | auto f_rs = [&](){ | |
1732 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56186 times.
|
56186 | BOOST_ASSERT(filter_ != nullptr); |
1733 |
2/2✓ Branch 0 taken 18145 times.
✓ Branch 1 taken 38041 times.
|
56186 | if(style_ == style::elastic) |
1734 | { | ||
1735 | 18145 | std::size_t n = clamp(body_limit_remain()); | |
1736 | 18145 | n = clamp(n, svc_.cfg.min_buffer); | |
1737 | 18145 | n = clamp(n, eb_->max_size() - eb_->size()); | |
1738 | |||
1739 | // fill capacity first to avoid | ||
1740 | // an allocation | ||
1741 | std::size_t avail = | ||
1742 | 18145 | eb_->capacity() - eb_->size(); | |
1743 |
1/2✓ Branch 0 taken 18145 times.
✗ Branch 1 not taken.
|
18145 | if(avail != 0) |
1744 | 18145 | n = clamp(n, avail); | |
1745 | |||
1746 |
1/2✓ Branch 3 taken 18145 times.
✗ Branch 4 not taken.
|
36290 | return filter_->process( |
1747 |
1/2✓ Branch 1 taken 18145 times.
✗ Branch 2 not taken.
|
18145 | eb_->prepare(n), |
1748 | 18145 | buffers::prefix(cb0_.data(), payload_avail), | |
1749 | 36290 | more); | |
1750 | } | ||
1751 | else // in-place and sink | ||
1752 | { | ||
1753 | 38041 | std::size_t n = clamp(body_limit_remain()); | |
1754 | 38041 | n = clamp(n, cb1_.capacity()); | |
1755 | |||
1756 |
1/2✓ Branch 3 taken 38041 times.
✗ Branch 4 not taken.
|
76082 | return filter_->process( |
1757 |
2/4✓ Branch 1 taken 38041 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 38041 times.
✗ Branch 5 not taken.
|
38041 | detail::make_span(cb1_.prepare(n)), |
1758 | 38041 | buffers::prefix(cb0_.data(), payload_avail), | |
1759 | 76082 | more); | |
1760 | } | ||
1761 |
1/2✓ Branch 1 taken 56186 times.
✗ Branch 2 not taken.
|
56186 | }(); |
1762 | |||
1763 | 56186 | cb0_.consume(f_rs.in_bytes); | |
1764 | 56186 | payload_avail -= f_rs.in_bytes; | |
1765 | 56186 | body_total_ += f_rs.out_bytes; | |
1766 | |||
1767 |
3/4✓ Branch 0 taken 20031 times.
✓ Branch 1 taken 18010 times.
✓ Branch 2 taken 18145 times.
✗ Branch 3 not taken.
|
56186 | switch(style_) |
1768 | { | ||
1769 | 20031 | case style::in_place: | |
1770 | { | ||
1771 | 20031 | cb1_.commit(f_rs.out_bytes); | |
1772 | 20031 | body_avail_ += f_rs.out_bytes; | |
1773 | 20031 | if(cb1_.capacity() == 0 && | |
1774 |
8/8✓ Branch 0 taken 3264 times.
✓ Branch 1 taken 16767 times.
✓ Branch 2 taken 3248 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 1620 times.
✓ Branch 5 taken 1628 times.
✓ Branch 6 taken 1620 times.
✓ Branch 7 taken 18411 times.
|
20031 | !f_rs.finished && f_rs.in_bytes == 0) |
1775 | { | ||
1776 | 3240 | ec = BOOST_HTTP_PROTO_ERR( | |
1777 | error::in_place_overflow); | ||
1778 | 1620 | goto done; | |
1779 | } | ||
1780 | 18411 | break; | |
1781 | } | ||
1782 | 18010 | case style::sink: | |
1783 | { | ||
1784 | 18010 | cb1_.commit(f_rs.out_bytes); | |
1785 |
1/2✓ Branch 1 taken 18010 times.
✗ Branch 2 not taken.
|
18010 | auto sink_rs = sink_->write( |
1786 |
4/4✓ Branch 0 taken 40 times.
✓ Branch 1 taken 17970 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 24 times.
|
18010 | cb1_.data(), !f_rs.finished || more); |
1787 | 18010 | cb1_.consume(sink_rs.bytes); | |
1788 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 18010 times.
|
18010 | if(sink_rs.ec.failed()) |
1789 | { | ||
1790 | ✗ | ec = sink_rs.ec; | |
1791 | ✗ | state_ = state::reset; | |
1792 | ✗ | goto done; | |
1793 | } | ||
1794 | 18010 | break; | |
1795 | } | ||
1796 | 18145 | case style::elastic: | |
1797 | { | ||
1798 |
1/2✓ Branch 1 taken 18145 times.
✗ Branch 2 not taken.
|
18145 | eb_->commit(f_rs.out_bytes); |
1799 |
2/4✓ Branch 1 taken 18145 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18145 times.
✗ Branch 5 not taken.
|
18145 | if(eb_->max_size() - eb_->size() == 0 && |
1800 |
2/8✗ Branch 0 not taken.
✓ Branch 1 taken 18145 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 18145 times.
|
18145 | !f_rs.finished && f_rs.in_bytes == 0) |
1801 | { | ||
1802 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
1803 | error::buffer_overflow); | ||
1804 | ✗ | state_ = state::reset; | |
1805 | ✗ | goto done; | |
1806 | } | ||
1807 | 18145 | break; | |
1808 | } | ||
1809 | } | ||
1810 | |||
1811 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 54566 times.
|
54566 | if(f_rs.ec.failed()) |
1812 | { | ||
1813 | ✗ | ec = f_rs.ec; | |
1814 | ✗ | state_ = state::reset; | |
1815 | ✗ | break; | |
1816 | } | ||
1817 | |||
1818 | 54566 | if(body_limit_remain() == 0 && | |
1819 |
6/8✓ Branch 0 taken 123 times.
✓ Branch 1 taken 54443 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 120 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 54566 times.
|
54566 | !f_rs.finished && f_rs.in_bytes == 0) |
1820 | { | ||
1821 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
1822 | error::body_too_large); | ||
1823 | ✗ | state_ = state::reset; | |
1824 | ✗ | break; | |
1825 | } | ||
1826 | |||
1827 |
2/2✓ Branch 0 taken 120 times.
✓ Branch 1 taken 54446 times.
|
54566 | if(f_rs.finished) |
1828 | { | ||
1829 |
2/2✓ Branch 0 taken 72 times.
✓ Branch 1 taken 48 times.
|
120 | if(!more) |
1830 | { | ||
1831 | 72 | state_ = (style_ == style::in_place) | |
1832 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 48 times.
|
72 | ? state::complete_in_place |
1833 | : state::complete; | ||
1834 | } | ||
1835 | 120 | break; | |
1836 | } | ||
1837 | 54446 | } | |
1838 | |||
1839 | 52723 | done: | |
1840 | 52723 | return p0 - payload_avail; | |
1841 | } | ||
1842 | }; | ||
1843 | |||
1844 | //------------------------------------------------ | ||
1845 | // | ||
1846 | // Special Members | ||
1847 | // | ||
1848 | //------------------------------------------------ | ||
1849 | |||
1850 | 1054 | parser:: | |
1851 | 1054 | parser(const rts::context& ctx, detail::kind k) | |
1852 |
1/4✓ Branch 2 taken 1054 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1054 | : impl_(new impl(ctx, k)) |
1853 | { | ||
1854 | // TODO: use a single allocation for | ||
1855 | // impl and workspace buffer. | ||
1856 | 1054 | } | |
1857 | |||
1858 | 3 | parser:: | |
1859 | 3 | parser(parser&& other) noexcept | |
1860 | 3 | : impl_(other.impl_) | |
1861 | { | ||
1862 | 3 | other.impl_ = nullptr; | |
1863 | 3 | } | |
1864 | |||
1865 | 1057 | parser:: | |
1866 | ~parser() | ||
1867 | { | ||
1868 |
2/2✓ Branch 0 taken 1054 times.
✓ Branch 1 taken 3 times.
|
1057 | delete impl_; |
1869 | 1057 | } | |
1870 | |||
1871 | //-------------------------------------------- | ||
1872 | // | ||
1873 | // Observers | ||
1874 | // | ||
1875 | //-------------------------------------------- | ||
1876 | |||
1877 | bool | ||
1878 | 11938 | parser::got_header() const noexcept | |
1879 | { | ||
1880 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11938 times.
|
11938 | BOOST_ASSERT(impl_); |
1881 | 11938 | return impl_->got_header(); | |
1882 | } | ||
1883 | |||
1884 | bool | ||
1885 | 51344 | parser::is_complete() const noexcept | |
1886 | { | ||
1887 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 51344 times.
|
51344 | BOOST_ASSERT(impl_); |
1888 | 51344 | return impl_->is_complete(); | |
1889 | } | ||
1890 | |||
1891 | //------------------------------------------------ | ||
1892 | // | ||
1893 | // Modifiers | ||
1894 | // | ||
1895 | //------------------------------------------------ | ||
1896 | |||
1897 | void | ||
1898 | 2480 | parser:: | |
1899 | reset() noexcept | ||
1900 | { | ||
1901 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2480 times.
|
2480 | BOOST_ASSERT(impl_); |
1902 | 2480 | impl_->reset(); | |
1903 | 2480 | } | |
1904 | |||
1905 | void | ||
1906 | 10307 | parser::start() | |
1907 | { | ||
1908 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10307 times.
|
10307 | BOOST_ASSERT(impl_); |
1909 | 10307 | impl_->start(false); | |
1910 | 10302 | } | |
1911 | |||
1912 | auto | ||
1913 | 51003 | parser:: | |
1914 | prepare() -> | ||
1915 | mutable_buffers_type | ||
1916 | { | ||
1917 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 51003 times.
|
51003 | BOOST_ASSERT(impl_); |
1918 | 51003 | return impl_->prepare(); | |
1919 | } | ||
1920 | |||
1921 | void | ||
1922 | 51000 | parser:: | |
1923 | commit( | ||
1924 | std::size_t n) | ||
1925 | { | ||
1926 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 51000 times.
|
51000 | BOOST_ASSERT(impl_); |
1927 | 51000 | impl_->commit(n); | |
1928 | 50993 | } | |
1929 | |||
1930 | void | ||
1931 | 401 | parser:: | |
1932 | commit_eof() | ||
1933 | { | ||
1934 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 401 times.
|
401 | BOOST_ASSERT(impl_); |
1935 | 401 | impl_->commit_eof(); | |
1936 | 398 | } | |
1937 | |||
1938 | void | ||
1939 | 69827 | parser:: | |
1940 | parse( | ||
1941 | system::error_code& ec) | ||
1942 | { | ||
1943 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 69827 times.
|
69827 | BOOST_ASSERT(impl_); |
1944 | 69827 | impl_->parse(ec); | |
1945 | 69825 | } | |
1946 | |||
1947 | auto | ||
1948 | 41250 | parser:: | |
1949 | pull_body() -> | ||
1950 | const_buffers_type | ||
1951 | { | ||
1952 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 41250 times.
|
41250 | BOOST_ASSERT(impl_); |
1953 | 41250 | return impl_->pull_body(); | |
1954 | } | ||
1955 | |||
1956 | void | ||
1957 | 39606 | parser:: | |
1958 | consume_body(std::size_t n) | ||
1959 | { | ||
1960 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39606 times.
|
39606 | BOOST_ASSERT(impl_); |
1961 | 39606 | impl_->consume_body(n); | |
1962 | 39606 | } | |
1963 | |||
1964 | core::string_view | ||
1965 | 700 | parser:: | |
1966 | body() const | ||
1967 | { | ||
1968 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 700 times.
|
700 | BOOST_ASSERT(impl_); |
1969 | 700 | return impl_->body(); | |
1970 | } | ||
1971 | |||
1972 | core::string_view | ||
1973 | ✗ | parser:: | |
1974 | release_buffered_data() noexcept | ||
1975 | { | ||
1976 | // TODO | ||
1977 | ✗ | return {}; | |
1978 | } | ||
1979 | |||
1980 | void | ||
1981 | 77 | parser:: | |
1982 | set_body_limit(std::uint64_t n) | ||
1983 | { | ||
1984 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
|
77 | BOOST_ASSERT(impl_); |
1985 | 77 | impl_->set_body_limit(n); | |
1986 | 74 | } | |
1987 | |||
1988 | //------------------------------------------------ | ||
1989 | // | ||
1990 | // Implementation | ||
1991 | // | ||
1992 | //------------------------------------------------ | ||
1993 | |||
1994 | void | ||
1995 | ✗ | parser:: | |
1996 | start_impl(bool head_response) | ||
1997 | { | ||
1998 | ✗ | BOOST_ASSERT(impl_); | |
1999 | ✗ | impl_->start(head_response); | |
2000 | ✗ | } | |
2001 | |||
2002 | static_request const& | ||
2003 | 315 | parser:: | |
2004 | safe_get_request() const | ||
2005 | { | ||
2006 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 315 times.
|
315 | BOOST_ASSERT(impl_); |
2007 | 315 | return impl_->safe_get_request(); | |
2008 | } | ||
2009 | |||
2010 | static_response const& | ||
2011 | 1 | parser:: | |
2012 | safe_get_response() const | ||
2013 | { | ||
2014 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | BOOST_ASSERT(impl_); |
2015 | 1 | return impl_->safe_get_response(); | |
2016 | } | ||
2017 | |||
2018 | detail::workspace& | ||
2019 | 755 | parser:: | |
2020 | ws() noexcept | ||
2021 | { | ||
2022 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 755 times.
|
755 | BOOST_ASSERT(impl_); |
2023 | 755 | return impl_->ws(); | |
2024 | } | ||
2025 | |||
2026 | bool | ||
2027 | 755 | parser:: | |
2028 | is_body_set() const noexcept | ||
2029 | { | ||
2030 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 755 times.
|
755 | BOOST_ASSERT(impl_); |
2031 | 755 | return impl_->is_body_set(); | |
2032 | } | ||
2033 | |||
2034 | void | ||
2035 | 383 | parser:: | |
2036 | set_body_impl( | ||
2037 | buffers::any_dynamic_buffer& eb) noexcept | ||
2038 | { | ||
2039 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 383 times.
|
383 | BOOST_ASSERT(impl_); |
2040 | 383 | impl_->set_body(eb); | |
2041 | 383 | } | |
2042 | |||
2043 | void | ||
2044 | 372 | parser:: | |
2045 | set_body_impl(sink& s) noexcept | ||
2046 | { | ||
2047 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 372 times.
|
372 | BOOST_ASSERT(impl_); |
2048 | 372 | impl_->set_body(s); | |
2049 | 372 | } | |
2050 | |||
2051 | } // http_proto | ||
2052 | } // boost | ||
2053 |