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