Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) | ||
3 | // | ||
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
6 | // | ||
7 | // Official repository: https://github.com/CPPAlliance/http_proto | ||
8 | // | ||
9 | |||
10 | #ifndef BOOST_HTTP_PROTO_IMPL_PARSER_IPP | ||
11 | #define BOOST_HTTP_PROTO_IMPL_PARSER_IPP | ||
12 | |||
13 | #include <boost/http_proto/parser.hpp> | ||
14 | #include <boost/http_proto/context.hpp> | ||
15 | #include <boost/http_proto/error.hpp> | ||
16 | #include <boost/http_proto/service/zlib_service.hpp> | ||
17 | #include <boost/http_proto/detail/except.hpp> | ||
18 | #include <boost/buffers/buffer_copy.hpp> | ||
19 | #include <boost/url/grammar/ci_string.hpp> | ||
20 | #include <boost/assert.hpp> | ||
21 | #include <memory> | ||
22 | |||
23 | namespace boost { | ||
24 | namespace http_proto { | ||
25 | |||
26 | /* | ||
27 | Principles for fixed-size buffer design | ||
28 | |||
29 | axiom 1: | ||
30 | To read data you must have a buffer. | ||
31 | |||
32 | axiom 2: | ||
33 | The size of the HTTP header is not | ||
34 | known in advance. | ||
35 | |||
36 | conclusion 3: | ||
37 | A single I/O can produce a complete | ||
38 | HTTP header and additional payload | ||
39 | data. | ||
40 | |||
41 | conclusion 4: | ||
42 | A single I/O can produce multiple | ||
43 | complete HTTP headers, complete | ||
44 | payloads, and a partial header or | ||
45 | payload. | ||
46 | |||
47 | axiom 5: | ||
48 | A process is in one of two states: | ||
49 | 1. at or below capacity | ||
50 | 2. above capacity | ||
51 | |||
52 | axiom 6: | ||
53 | A program which can allocate an | ||
54 | unbounded number of resources can | ||
55 | go above capacity. | ||
56 | |||
57 | conclusion 7: | ||
58 | A program can guarantee never going | ||
59 | above capacity if all resources are | ||
60 | provisioned at program startup. | ||
61 | |||
62 | corollary 8: | ||
63 | `parser` and `serializer` should each | ||
64 | allocate a single buffer of calculated | ||
65 | size, and never resize it. | ||
66 | |||
67 | axiom #: | ||
68 | A parser and a serializer are always | ||
69 | used in pairs. | ||
70 | */ | ||
71 | |||
72 | //------------------------------------------------ | ||
73 | /* | ||
74 | Buffer Usage | ||
75 | |||
76 | | | begin | ||
77 | | H | p | | f | read headers | ||
78 | | H | p | | T | f | set T body | ||
79 | | H | p | | C | T | f | make codec C | ||
80 | | H | p | b | C | T | f | decode p into b | ||
81 | | H | p | b | C | T | f | read/parse loop | ||
82 | | H | | T | f | destroy codec | ||
83 | | H | | T | f | finished | ||
84 | |||
85 | H headers | ||
86 | C codec | ||
87 | T body | ||
88 | f table | ||
89 | p partial payload | ||
90 | b body data | ||
91 | |||
92 | "payload" is the bytes coming in from | ||
93 | the stream. | ||
94 | |||
95 | "body" is the logical body, after transfer | ||
96 | encoding is removed. This can be the | ||
97 | same as the payload. | ||
98 | |||
99 | A "plain payload" is when the payload and | ||
100 | body are identical (no transfer encodings). | ||
101 | |||
102 | A "buffered payload" is any payload which is | ||
103 | not plain. A second buffer is required | ||
104 | for reading. | ||
105 | */ | ||
106 | //------------------------------------------------ | ||
107 | |||
108 | class parser_service | ||
109 | : public service | ||
110 | { | ||
111 | public: | ||
112 | parser::config_base cfg; | ||
113 | std::size_t space_needed = 0; | ||
114 | std::size_t max_codec = 0; | ||
115 | zlib::deflate_decoder_service const* | ||
116 | deflate_svc = nullptr; | ||
117 | |||
118 | parser_service( | ||
119 | context& ctx, | ||
120 | parser::config_base const& cfg_); | ||
121 | |||
122 | std::size_t | ||
123 | 83721 | max_overread() const noexcept | |
124 | { | ||
125 | return | ||
126 | 83721 | cfg.headers.max_size + | |
127 | 83721 | cfg.min_buffer; | |
128 | } | ||
129 | }; | ||
130 | |||
131 | 6 | parser_service:: | |
132 | parser_service( | ||
133 | context& ctx, | ||
134 | 6 | parser::config_base const& cfg_) | |
135 | 6 | : cfg(cfg_) | |
136 | { | ||
137 | /* | ||
138 | | fb | cb0 | cb1 | C | T | f | | ||
139 | |||
140 | fb flat_buffer headers.max_size | ||
141 | cb0 circular_buffer min_buffer | ||
142 | cb1 circular_buffer min_buffer | ||
143 | C codec max_codec | ||
144 | T body max_type_erase | ||
145 | f table max_table_space | ||
146 | |||
147 | */ | ||
148 | // validate | ||
149 | //if(cfg.min_prepare > cfg.max_prepare) | ||
150 | //detail::throw_invalid_argument(); | ||
151 | |||
152 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if( cfg.min_buffer < 1 || |
153 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | cfg.min_buffer > cfg.body_limit) |
154 | ✗ | detail::throw_invalid_argument(); | |
155 | |||
156 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if(cfg.max_prepare < 1) |
157 | ✗ | detail::throw_invalid_argument(); | |
158 | |||
159 | // VFALCO TODO OVERFLOW CHECING | ||
160 | { | ||
161 | //fb_.size() - h_.size + | ||
162 | //svc_.cfg.min_buffer + | ||
163 | //svc_.cfg.min_buffer + | ||
164 | //svc_.max_codec; | ||
165 | } | ||
166 | |||
167 | // VFALCO OVERFLOW CHECKING ON THIS | ||
168 | 6 | space_needed += | |
169 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | cfg.headers.valid_space_needed(); |
170 | |||
171 | // cb0_, cb1_ | ||
172 | // VFALCO OVERFLOW CHECKING ON THIS | ||
173 | 6 | space_needed += | |
174 | 6 | cfg.min_buffer + | |
175 | cfg.min_buffer; | ||
176 | |||
177 | // T | ||
178 | 6 | space_needed += cfg.max_type_erase; | |
179 | |||
180 | // max_codec | ||
181 | { | ||
182 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if(cfg.apply_deflate_decoder) |
183 | { | ||
184 | ✗ | deflate_svc = &ctx.get_service< | |
185 | ✗ | zlib::deflate_decoder_service>(); | |
186 | auto const n = | ||
187 | ✗ | deflate_svc->space_needed(); | |
188 | ✗ | if( max_codec < n) | |
189 | ✗ | max_codec = n; | |
190 | } | ||
191 | } | ||
192 | 6 | space_needed += max_codec; | |
193 | 6 | } | |
194 | |||
195 | void | ||
196 | 6 | install_parser_service( | |
197 | context& ctx, | ||
198 | parser::config_base const& cfg) | ||
199 | { | ||
200 | ctx.make_service< | ||
201 | 6 | parser_service>(cfg); | |
202 | 6 | } | |
203 | |||
204 | //------------------------------------------------ | ||
205 | |||
206 | 738 | parser:: | |
207 | parser( | ||
208 | context& ctx, | ||
209 | 738 | detail::kind k) | |
210 | : ctx_(ctx) | ||
211 | , svc_(ctx.get_service< | ||
212 | 1476 | parser_service>()) | |
213 | , h_(detail::empty{k}) | ||
214 | 738 | , st_(state::reset) | |
215 | { | ||
216 | 738 | auto const n = | |
217 | 738 | svc_.space_needed; | |
218 |
1/2✓ Branch 1 taken 738 times.
✗ Branch 2 not taken.
|
738 | ws_.allocate(n); |
219 | 738 | h_.cap = n; | |
220 | 738 | } | |
221 | |||
222 | //------------------------------------------------ | ||
223 | // | ||
224 | // Special Members | ||
225 | // | ||
226 | //------------------------------------------------ | ||
227 | |||
228 | 738 | parser:: | |
229 | 738 | ~parser() | |
230 | { | ||
231 | 738 | } | |
232 | |||
233 | parser:: | ||
234 | parser( | ||
235 | parser&&) noexcept = default; | ||
236 | |||
237 | //------------------------------------------------ | ||
238 | // | ||
239 | // Modifiers | ||
240 | // | ||
241 | //------------------------------------------------ | ||
242 | |||
243 | // prepare for a new stream | ||
244 | void | ||
245 | 5355 | parser:: | |
246 | reset() noexcept | ||
247 | { | ||
248 | 5355 | ws_.clear(); | |
249 | 5355 | st_ = state::start; | |
250 | 5355 | got_eof_ = false; | |
251 | 5355 | } | |
252 | |||
253 | void | ||
254 | 14280 | parser:: | |
255 | start_impl( | ||
256 | bool head_response) | ||
257 | { | ||
258 | 14280 | std::size_t leftover = 0; | |
259 |
2/5✗ Branch 0 not taken.
✓ Branch 1 taken 5355 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8925 times.
|
14280 | switch(st_) |
260 | { | ||
261 | ✗ | default: | |
262 | case state::reset: | ||
263 | // reset must be called first | ||
264 | ✗ | detail::throw_logic_error(); | |
265 | |||
266 | 5355 | case state::start: | |
267 | // reset required on eof | ||
268 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5355 times.
|
5355 | if(got_eof_) |
269 | ✗ | detail::throw_logic_error(); | |
270 | 5355 | break; | |
271 | |||
272 | ✗ | case state::header: | |
273 | // start() called twice | ||
274 | ✗ | detail::throw_logic_error(); | |
275 | |||
276 | ✗ | case state::body: | |
277 | case state::body_set: | ||
278 | // current message is incomplete | ||
279 | ✗ | detail::throw_logic_error(); | |
280 | |||
281 | 8925 | case state::complete: | |
282 | { | ||
283 | // remove partial body. | ||
284 |
1/2✓ Branch 0 taken 8925 times.
✗ Branch 1 not taken.
|
8925 | if(body_buf_ == &cb0_) |
285 | 8925 | cb0_.consume(body_avail_); | |
286 | |||
287 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 8925 times.
|
8925 | if(cb0_.size() > 0) |
288 | { | ||
289 | |||
290 | // headers with no body | ||
291 | ✗ | BOOST_ASSERT(h_.size > 0); | |
292 | ✗ | fb_.consume(h_.size); | |
293 | ✗ | leftover = fb_.size(); | |
294 | // move unused octets to front | ||
295 | ✗ | buffers::buffer_copy( | |
296 | ✗ | buffers::mutable_buffer( | |
297 | ✗ | ws_.data(), | |
298 | leftover), | ||
299 | ✗ | fb_.data()); | |
300 | } | ||
301 | else | ||
302 | { | ||
303 | // leftover data after body | ||
304 | } | ||
305 | 8925 | break; | |
306 | } | ||
307 | } | ||
308 | |||
309 | 14280 | ws_.clear(); | |
310 | |||
311 | 28560 | fb_ = { | |
312 | 14280 | ws_.data(), | |
313 | 14280 | svc_.cfg.headers.max_size + | |
314 | 14280 | svc_.cfg.min_buffer, | |
315 | leftover }; | ||
316 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 14280 times.
|
14280 | BOOST_ASSERT( |
317 | fb_.capacity() == svc_.max_overread()); | ||
318 | |||
319 | 28560 | h_ = detail::header( | |
320 | 14280 | detail::empty{h_.kind}); | |
321 | 14280 | h_.buf = reinterpret_cast< | |
322 | 14280 | char*>(ws_.data()); | |
323 | 14280 | h_.cbuf = h_.buf; | |
324 | 14280 | h_.cap = ws_.size(); | |
325 | |||
326 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 14280 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
14280 | BOOST_ASSERT(! head_response || |
327 | h_.kind == detail::kind::response); | ||
328 | 14280 | head_response_ = head_response; | |
329 | |||
330 | 14280 | how_ = how::in_place; | |
331 | 14280 | st_ = state::header; | |
332 | 14280 | } | |
333 | |||
334 | auto | ||
335 | 42962 | parser:: | |
336 | prepare() -> | ||
337 | mutable_buffers_type | ||
338 | { | ||
339 |
2/6✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 40397 times.
✓ Branch 3 taken 2565 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
42962 | switch(st_) |
340 | { | ||
341 | ✗ | default: | |
342 | case state::reset: | ||
343 | // reset must be called first | ||
344 | ✗ | detail::throw_logic_error(); | |
345 | |||
346 | ✗ | case state::start: | |
347 | // start must be called first | ||
348 | ✗ | detail::throw_logic_error(); | |
349 | |||
350 | 40397 | case state::header: | |
351 | { | ||
352 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40397 times.
|
40397 | BOOST_ASSERT(h_.size < |
353 | svc_.cfg.headers.max_size); | ||
354 | 40397 | auto n = fb_.capacity() - fb_.size(); | |
355 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 40397 times.
|
40397 | BOOST_ASSERT(n <= svc_.max_overread()); |
356 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 40397 times.
|
40397 | if( n > svc_.cfg.max_prepare) |
357 | ✗ | n = svc_.cfg.max_prepare; | |
358 | 40397 | mbp_[0] = fb_.prepare(n); | |
359 | 40397 | return mutable_buffers_type( | |
360 | 80794 | &mbp_[0], 1); | |
361 | } | ||
362 | |||
363 | 2565 | case state::body: | |
364 | { | ||
365 | // buffered payload | ||
366 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2565 times.
|
2565 | if(body_buf_ != &cb0_) |
367 | { | ||
368 | ✗ | auto n = cb0_.capacity() - | |
369 | ✗ | cb0_.size(); | |
370 | ✗ | if( n > svc_.cfg.max_prepare) | |
371 | ✗ | n = svc_.cfg.max_prepare; | |
372 | ✗ | mbp_ = cb0_.prepare(n); | |
373 | ✗ | return mutable_buffers_type(mbp_); | |
374 | } | ||
375 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2565 times.
|
2565 | BOOST_ASSERT(is_plain()); |
376 | |||
377 | // plain payload | ||
378 | |||
379 |
2/2✓ Branch 0 taken 1191 times.
✓ Branch 1 taken 1374 times.
|
2565 | if(how_ == how::in_place) |
380 | { | ||
381 | auto n = | ||
382 | 1191 | body_buf_->capacity() - | |
383 | 1191 | body_buf_->size(); | |
384 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1191 times.
|
1191 | if( n > svc_.cfg.max_prepare) |
385 | ✗ | n = svc_.cfg.max_prepare; | |
386 | 1191 | mbp_ = body_buf_->prepare(n); | |
387 | 1191 | return mutable_buffers_type(mbp_); | |
388 | } | ||
389 | |||
390 |
1/2✓ Branch 0 taken 1374 times.
✗ Branch 1 not taken.
|
1374 | if(how_ == how::dynamic) |
391 | { | ||
392 | // Overreads are not allowed, or | ||
393 | // else the caller will see extra | ||
394 | // unrelated data. | ||
395 | |||
396 |
2/2✓ Branch 0 taken 615 times.
✓ Branch 1 taken 759 times.
|
1374 | if(h_.md.payload == payload::size) |
397 | { | ||
398 | // set_body moves avail to dyn | ||
399 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 615 times.
|
615 | BOOST_ASSERT(body_buf_->size() == 0); |
400 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 615 times.
|
615 | BOOST_ASSERT(body_avail_ == 0); |
401 | 615 | auto n = payload_remain_; | |
402 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 615 times.
|
615 | if( n > svc_.cfg.max_prepare) |
403 | ✗ | n = svc_.cfg.max_prepare; | |
404 | 615 | return dyn_->prepare(n); | |
405 | } | ||
406 | |||
407 | // heuristic size | ||
408 | 759 | std::size_t n = 0; | |
409 |
1/2✓ Branch 0 taken 759 times.
✗ Branch 1 not taken.
|
759 | if(! got_eof_) |
410 | { | ||
411 | 759 | n = svc_.cfg.min_buffer; | |
412 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 759 times.
|
759 | if( n > svc_.cfg.max_prepare) |
413 | ✗ | n = svc_.cfg.max_prepare; | |
414 | std::size_t avail; | ||
415 | 759 | avail = | |
416 | 759 | dyn_->max_size() - dyn_->size(); | |
417 |
1/2✓ Branch 0 taken 759 times.
✗ Branch 1 not taken.
|
759 | if( n > avail) |
418 | 759 | n = avail; | |
419 | 759 | avail = | |
420 | 759 | dyn_->capacity() - dyn_->size(); | |
421 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 759 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
759 | if( n > avail && |
422 | avail != 0) | ||
423 | ✗ | n = avail; | |
424 |
2/2✓ Branch 0 taken 308 times.
✓ Branch 1 taken 451 times.
|
759 | if(n == 0) |
425 | { | ||
426 | // dynamic buffer is full | ||
427 |
2/2✓ Branch 0 taken 273 times.
✓ Branch 1 taken 35 times.
|
308 | if(body_avail_ == 0) |
428 | { | ||
429 | // attempt a 1 byte read so | ||
430 | // we can detect overflow | ||
431 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 273 times.
|
273 | BOOST_ASSERT( |
432 | body_buf_->size() == 0); | ||
433 | 273 | mbp_ = body_buf_->prepare(1); | |
434 | return | ||
435 | 273 | mutable_buffers_type(mbp_); | |
436 | } | ||
437 | return | ||
438 | 35 | mutable_buffers_type{}; | |
439 | } | ||
440 | } | ||
441 | 451 | return dyn_->prepare(n); | |
442 | } | ||
443 | |||
444 | // VFALCO TODO | ||
445 | ✗ | if(how_ == how::pull) | |
446 | ✗ | detail::throw_logic_error(); | |
447 | |||
448 | // VFALCO TODO | ||
449 | ✗ | detail::throw_logic_error(); | |
450 | } | ||
451 | |||
452 | ✗ | case state::body_set: | |
453 | { | ||
454 | ✗ | BOOST_ASSERT(how_ != how::in_place); | |
455 | ✗ | BOOST_ASSERT(how_ != how::dynamic); | |
456 | ✗ | if(how_ == how::sink) | |
457 | { | ||
458 | // this is a no-op, to get the | ||
459 | // caller to call parse next. | ||
460 | ✗ | return mutable_buffers_type{}; | |
461 | } | ||
462 | ✗ | detail::throw_logic_error(); | |
463 | } | ||
464 | |||
465 | ✗ | case state::complete: | |
466 | // We allow the call for callers | ||
467 | // who want normalized usage, but | ||
468 | // just return a 0-sized sequence. | ||
469 | ✗ | return mutable_buffers_type{}; | |
470 | } | ||
471 | } | ||
472 | |||
473 | void | ||
474 | 42962 | parser:: | |
475 | commit( | ||
476 | std::size_t n) | ||
477 | { | ||
478 | // Can't commit after eof | ||
479 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42962 times.
|
42962 | if(got_eof_) |
480 | ✗ | detail::throw_logic_error(); | |
481 | |||
482 |
2/6✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 40397 times.
✓ Branch 3 taken 2565 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
42962 | switch(st_) |
483 | { | ||
484 | ✗ | default: | |
485 | case state::reset: | ||
486 | // reset must be called first | ||
487 | ✗ | detail::throw_logic_error(); | |
488 | |||
489 | ✗ | case state::start: | |
490 | // forgot to call start() | ||
491 | ✗ | detail::throw_logic_error(); | |
492 | |||
493 | 40397 | case state::header: | |
494 | 40397 | fb_.commit(n); | |
495 | 40397 | break; | |
496 | |||
497 | 2565 | case state::body: | |
498 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2565 times.
|
2565 | if(! is_plain()) |
499 | { | ||
500 | // buffered payload | ||
501 | ✗ | cb0_.commit(n); | |
502 | ✗ | break; | |
503 | } | ||
504 | |||
505 | // plain payload | ||
506 | |||
507 |
2/2✓ Branch 0 taken 1191 times.
✓ Branch 1 taken 1374 times.
|
2565 | if(how_ == how::in_place) |
508 | { | ||
509 | 1191 | cb0_.commit(n); | |
510 | 1191 | break; | |
511 | } | ||
512 | |||
513 |
1/2✓ Branch 0 taken 1374 times.
✗ Branch 1 not taken.
|
1374 | if(how_ == how::dynamic) |
514 | { | ||
515 |
2/2✓ Branch 2 taken 1066 times.
✓ Branch 3 taken 308 times.
|
1374 | if(dyn_->size() < dyn_->max_size()) |
516 | { | ||
517 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1066 times.
|
1066 | BOOST_ASSERT(body_avail_ == 0); |
518 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1066 times.
|
1066 | BOOST_ASSERT( |
519 | body_buf_->size() == 0); | ||
520 | 1066 | dyn_->commit(n); | |
521 | } | ||
522 | else | ||
523 | { | ||
524 | 308 | body_buf_->commit(n); | |
525 | 308 | body_avail_ += n; | |
526 | } | ||
527 | 1374 | body_total_ += n; | |
528 |
2/2✓ Branch 0 taken 615 times.
✓ Branch 1 taken 759 times.
|
1374 | if(h_.md.payload == payload::size) |
529 | { | ||
530 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 615 times.
|
615 | BOOST_ASSERT( |
531 | n <= payload_remain_); | ||
532 | 615 | payload_remain_ -= n; | |
533 |
2/2✓ Branch 0 taken 585 times.
✓ Branch 1 taken 30 times.
|
615 | if(payload_remain_ == 0) |
534 | 585 | st_ = state::complete; | |
535 | } | ||
536 | 1374 | break; | |
537 | } | ||
538 | ✗ | if(how_ == how::sink) | |
539 | { | ||
540 | ✗ | cb0_.commit(n); | |
541 | ✗ | break; | |
542 | } | ||
543 | ✗ | if(how_ == how::pull) | |
544 | { | ||
545 | // VFALCO TODO | ||
546 | ✗ | detail::throw_logic_error(); | |
547 | } | ||
548 | ✗ | break; | |
549 | |||
550 | ✗ | case state::body_set: | |
551 | ✗ | BOOST_ASSERT(n == 0); | |
552 | ✗ | break; | |
553 | |||
554 | ✗ | case state::complete: | |
555 | // intended no-op | ||
556 | ✗ | break; | |
557 | } | ||
558 | 42962 | } | |
559 | |||
560 | void | ||
561 | 4356 | parser:: | |
562 | commit_eof() | ||
563 | { | ||
564 |
1/6✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4356 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
4356 | switch(st_) |
565 | { | ||
566 | ✗ | default: | |
567 | case state::reset: | ||
568 | // reset must be called first | ||
569 | ✗ | detail::throw_logic_error(); | |
570 | |||
571 | ✗ | case state::start: | |
572 | // forgot to call prepare() | ||
573 | ✗ | detail::throw_logic_error(); | |
574 | |||
575 | ✗ | case state::header: | |
576 | ✗ | got_eof_ = true; | |
577 | ✗ | break; | |
578 | |||
579 | 4356 | case state::body: | |
580 | 4356 | got_eof_ = true; | |
581 | 4356 | break; | |
582 | |||
583 | ✗ | case state::body_set: | |
584 | ✗ | got_eof_ = true; | |
585 | ✗ | break; | |
586 | |||
587 | ✗ | case state::complete: | |
588 | // can't commit eof when complete | ||
589 | ✗ | detail::throw_logic_error(); | |
590 | } | ||
591 | 4356 | } | |
592 | |||
593 | //----------------------------------------------- | ||
594 | |||
595 | // process input data then | ||
596 | // eof if input data runs out. | ||
597 | void | ||
598 | 60007 | parser:: | |
599 | parse( | ||
600 | system::error_code& ec) | ||
601 | { | ||
602 | 60007 | ec = {}; | |
603 |
3/6✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 40397 times.
✓ Branch 3 taken 6336 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 13274 times.
|
60007 | switch(st_) |
604 | { | ||
605 | ✗ | default: | |
606 | case state::reset: | ||
607 | // reset must be called first | ||
608 | ✗ | detail::throw_logic_error(); | |
609 | |||
610 | ✗ | case state::start: | |
611 | // start must be called first | ||
612 | ✗ | detail::throw_logic_error(); | |
613 | |||
614 | 40397 | case state::header: | |
615 | { | ||
616 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 40397 times.
|
40397 | BOOST_ASSERT(h_.buf == static_cast< |
617 | void const*>(ws_.data())); | ||
618 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 40397 times.
|
40397 | BOOST_ASSERT(h_.cbuf == static_cast< |
619 | void const*>(ws_.data())); | ||
620 | 40397 | auto const new_size = fb_.size(); | |
621 | 40397 | h_.parse(new_size, svc_.cfg.headers, ec); | |
622 |
2/2✓ Branch 2 taken 26117 times.
✓ Branch 3 taken 14280 times.
|
40397 | if(ec == condition::need_more_input) |
623 | { | ||
624 |
1/2✓ Branch 0 taken 26117 times.
✗ Branch 1 not taken.
|
26117 | if(! got_eof_) |
625 | { | ||
626 | // headers incomplete | ||
627 | 26117 | return; | |
628 | } | ||
629 | ✗ | if(h_.size == 0) | |
630 | { | ||
631 | // stream closed cleanly | ||
632 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
633 | error::end_of_stream); | ||
634 | ✗ | return; | |
635 | } | ||
636 | |||
637 | // stream closed with a | ||
638 | // partial message received | ||
639 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
640 | error::incomplete); | ||
641 | ✗ | return; | |
642 | } | ||
643 |
2/2✓ Branch 1 taken 128 times.
✓ Branch 2 taken 14152 times.
|
14280 | if(ec.failed()) |
644 | { | ||
645 | // other error, | ||
646 | // | ||
647 | // VFALCO map this to a bad | ||
648 | // request or bad response error? | ||
649 | // | ||
650 | 128 | st_ = state::reset; // unrecoverable | |
651 | 128 | return; | |
652 | } | ||
653 | |||
654 | // headers are complete | ||
655 | 14152 | on_headers(ec); | |
656 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 14152 times.
|
14152 | if(ec.failed()) |
657 | ✗ | return; | |
658 |
2/2✓ Branch 0 taken 2084 times.
✓ Branch 1 taken 12068 times.
|
14152 | if(st_ == state::complete) |
659 | 2084 | break; | |
660 | BOOST_FALLTHROUGH; | ||
661 | } | ||
662 | |||
663 | case state::body: | ||
664 | { | ||
665 | 12068 | do_body: | |
666 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18404 times.
|
18404 | BOOST_ASSERT(st_ == state::body); |
667 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18404 times.
|
18404 | BOOST_ASSERT( |
668 | h_.md.payload != payload::none); | ||
669 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18404 times.
|
18404 | BOOST_ASSERT( |
670 | h_.md.payload != payload::error); | ||
671 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18404 times.
|
18404 | if(h_.md.payload == payload::chunked) |
672 | { | ||
673 | // VFALCO parse chunked | ||
674 | ✗ | detail::throw_logic_error(); | |
675 | } | ||
676 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18404 times.
|
18404 | else if(filt_) |
677 | { | ||
678 | // VFALCO TODO apply filter | ||
679 | ✗ | detail::throw_logic_error(); | |
680 | } | ||
681 | |||
682 |
2/2✓ Branch 0 taken 15570 times.
✓ Branch 1 taken 2834 times.
|
18404 | if(how_ == how::in_place) |
683 | { | ||
684 |
2/2✓ Branch 0 taken 8061 times.
✓ Branch 1 taken 7509 times.
|
15570 | if(h_.md.payload == payload::size) |
685 | { | ||
686 | 8061 | if(cb0_.size() < | |
687 |
2/2✓ Branch 0 taken 1200 times.
✓ Branch 1 taken 6861 times.
|
8061 | h_.md.payload_size) |
688 | { | ||
689 | 1200 | body_avail_ = cb0_.size(); | |
690 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1200 times.
|
1200 | if(cb0_.capacity() == 0) |
691 | { | ||
692 | // in_place buffer limit | ||
693 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
694 | error::in_place_overflow); | ||
695 | ✗ | return; | |
696 | } | ||
697 | 2400 | ec = BOOST_HTTP_PROTO_ERR( | |
698 | error::need_data); | ||
699 | 1200 | return; | |
700 | } | ||
701 | 6861 | body_avail_ = h_.md.payload_size; | |
702 | 6861 | st_ = state::complete; | |
703 | 6861 | break; | |
704 | } | ||
705 | 7509 | body_avail_ = cb0_.size(); | |
706 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7509 times.
|
7509 | if(body_avail_ > svc_.cfg.body_limit) |
707 | { | ||
708 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
709 | error::body_too_large); | ||
710 | ✗ | st_ = state::reset; // unrecoverable | |
711 | ✗ | return; | |
712 | } | ||
713 |
1/2✓ Branch 0 taken 7509 times.
✗ Branch 1 not taken.
|
7509 | if( h_.md.payload == payload::chunked || |
714 |
2/2✓ Branch 0 taken 5198 times.
✓ Branch 1 taken 2311 times.
|
7509 | ! got_eof_) |
715 | { | ||
716 | 10396 | ec = BOOST_HTTP_PROTO_ERR( | |
717 | error::need_data); | ||
718 | 5198 | return; | |
719 | } | ||
720 | 2311 | st_ = state::complete; | |
721 | 2311 | break; | |
722 | } | ||
723 | |||
724 |
1/2✓ Branch 0 taken 2834 times.
✗ Branch 1 not taken.
|
2834 | if(how_ == how::dynamic) |
725 | { | ||
726 | // state already updated in commit | ||
727 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 2804 times.
|
2834 | if(h_.md.payload == payload::size) |
728 | { | ||
729 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | BOOST_ASSERT(body_avail_ == 0); |
730 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | BOOST_ASSERT(body_total_ < |
731 | h_.md.payload_size); | ||
732 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | BOOST_ASSERT( |
733 | payload_remain_ > 0); | ||
734 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | if(got_eof_) |
735 | { | ||
736 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
737 | error::incomplete); | ||
738 | ✗ | return; | |
739 | } | ||
740 | 30 | return; | |
741 | } | ||
742 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2804 times.
|
2804 | BOOST_ASSERT( |
743 | h_.md.payload == payload::to_eof); | ||
744 |
4/4✓ Branch 2 taken 2108 times.
✓ Branch 3 taken 696 times.
✓ Branch 4 taken 861 times.
✓ Branch 5 taken 1943 times.
|
4912 | if( dyn_->size() == dyn_->max_size() && |
745 |
2/2✓ Branch 0 taken 861 times.
✓ Branch 1 taken 1247 times.
|
2108 | body_avail_ > 0) |
746 | { | ||
747 | 1722 | ec = BOOST_HTTP_PROTO_ERR( | |
748 | error::buffer_overflow); | ||
749 | 861 | st_ = state::reset; // unrecoverable | |
750 | 861 | return; | |
751 | } | ||
752 |
2/2✓ Branch 0 taken 1450 times.
✓ Branch 1 taken 493 times.
|
1943 | if(got_eof_) |
753 | { | ||
754 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1450 times.
|
1450 | BOOST_ASSERT(body_avail_ == 0); |
755 | 1450 | st_ = state::complete; | |
756 | 1450 | break; | |
757 | } | ||
758 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 493 times.
|
493 | BOOST_ASSERT(body_avail_ == 0); |
759 | 493 | break; | |
760 | } | ||
761 | |||
762 | // VFALCO TODO | ||
763 | ✗ | detail::throw_logic_error(); | |
764 | } | ||
765 | |||
766 | ✗ | case state::body_set: | |
767 | { | ||
768 | // transfer in_place data into set body | ||
769 | |||
770 | // this is handled in on_set_body | ||
771 | ✗ | BOOST_ASSERT(how_ != how::dynamic); | |
772 | |||
773 | ✗ | if(how_ == how::sink) | |
774 | { | ||
775 | ✗ | auto n = body_buf_->size(); | |
776 | ✗ | if(h_.md.payload == payload::size) | |
777 | { | ||
778 | // sink_->size_hint(h_.md.payload_size, ec); | ||
779 | |||
780 | ✗ | if(n < h_.md.payload_size) | |
781 | { | ||
782 | ✗ | auto rv = sink_->write( | |
783 | ✗ | body_buf_->data(), false); | |
784 | ✗ | BOOST_ASSERT(rv.ec.failed() || | |
785 | rv.bytes == body_buf_->size()); | ||
786 | ✗ | BOOST_ASSERT( | |
787 | rv.bytes >= body_avail_); | ||
788 | ✗ | BOOST_ASSERT( | |
789 | rv.bytes < payload_remain_); | ||
790 | ✗ | body_buf_->consume(rv.bytes); | |
791 | ✗ | body_avail_ -= rv.bytes; | |
792 | ✗ | body_total_ += rv.bytes; | |
793 | ✗ | payload_remain_ -= rv.bytes; | |
794 | ✗ | if(rv.ec.failed()) | |
795 | { | ||
796 | ✗ | ec = rv.ec; | |
797 | ✗ | st_ = state::reset; // unrecoverable | |
798 | ✗ | return; | |
799 | } | ||
800 | ✗ | st_ = state::body; | |
801 | ✗ | goto do_body; | |
802 | } | ||
803 | |||
804 | ✗ | n = h_.md.payload_size; | |
805 | } | ||
806 | // complete | ||
807 | ✗ | BOOST_ASSERT(body_buf_ == &cb0_); | |
808 | ✗ | auto rv = sink_->write( | |
809 | ✗ | body_buf_->data(), true); | |
810 | ✗ | BOOST_ASSERT(rv.ec.failed() || | |
811 | rv.bytes == body_buf_->size()); | ||
812 | ✗ | body_buf_->consume(rv.bytes); | |
813 | ✗ | if(rv.ec.failed()) | |
814 | { | ||
815 | ✗ | ec = rv.ec; | |
816 | ✗ | st_ = state::reset; // unrecoverable | |
817 | ✗ | return; | |
818 | } | ||
819 | ✗ | st_ = state::complete; | |
820 | ✗ | return; | |
821 | } | ||
822 | |||
823 | // VFALCO TODO | ||
824 | ✗ | detail::throw_logic_error(); | |
825 | } | ||
826 | |||
827 | 13274 | case state::complete: | |
828 | { | ||
829 | // This is a no-op except when set_body | ||
830 | // was called and we have in-place data. | ||
831 |
2/4✓ Branch 0 taken 6775 times.
✓ Branch 1 taken 6499 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
13274 | switch(how_) |
832 | { | ||
833 | 6775 | default: | |
834 | case how::in_place: | ||
835 | 6775 | break; | |
836 | |||
837 | 6499 | case how::dynamic: | |
838 | { | ||
839 |
1/2✓ Branch 1 taken 6499 times.
✗ Branch 2 not taken.
|
6499 | if(body_buf_->size() == 0) |
840 | 6499 | break; | |
841 | ✗ | BOOST_ASSERT(dyn_->size() == 0); | |
842 | ✗ | auto n = buffers::buffer_copy( | |
843 | ✗ | dyn_->prepare( | |
844 | ✗ | body_buf_->size()), | |
845 | ✗ | body_buf_->data()); | |
846 | ✗ | body_buf_->consume(n); | |
847 | ✗ | break; | |
848 | } | ||
849 | |||
850 | ✗ | case how::sink: | |
851 | { | ||
852 | ✗ | if(body_buf_->size() == 0) | |
853 | ✗ | break; | |
854 | ✗ | auto rv = sink_->write( | |
855 | ✗ | body_buf_->data(), false); | |
856 | ✗ | body_buf_->consume(rv.bytes); | |
857 | ✗ | if(rv.ec.failed()) | |
858 | { | ||
859 | ✗ | ec = rv.ec; | |
860 | ✗ | st_ = state::reset; // unrecoverable | |
861 | ✗ | return; | |
862 | } | ||
863 | ✗ | break; | |
864 | } | ||
865 | |||
866 | ✗ | case how::pull: | |
867 | // VFALCO TODO | ||
868 | ✗ | detail::throw_logic_error(); | |
869 | } | ||
870 | } | ||
871 | } | ||
872 | } | ||
873 | |||
874 | //------------------------------------------------ | ||
875 | |||
876 | auto | ||
877 | ✗ | parser:: | |
878 | pull_some() -> | ||
879 | const_buffers_type | ||
880 | { | ||
881 | ✗ | return {}; | |
882 | } | ||
883 | |||
884 | core::string_view | ||
885 | 29135 | parser:: | |
886 | body() const noexcept | ||
887 | { | ||
888 |
2/2✓ Branch 0 taken 5792 times.
✓ Branch 1 taken 23343 times.
|
29135 | switch(st_) |
889 | { | ||
890 | 5792 | default: | |
891 | case state::reset: | ||
892 | case state::start: | ||
893 | case state::header: | ||
894 | case state::body: | ||
895 | case state::body_set: | ||
896 | // not complete | ||
897 | 5792 | return {}; | |
898 | |||
899 | 23343 | case state::complete: | |
900 |
2/2✓ Branch 0 taken 9793 times.
✓ Branch 1 taken 13550 times.
|
23343 | if(how_ != how::in_place) |
901 | { | ||
902 | // not in_place | ||
903 | 9793 | return {}; | |
904 | } | ||
905 | 13550 | auto cbp = body_buf_->data(); | |
906 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 13550 times.
|
13550 | BOOST_ASSERT(cbp[1].size() == 0); |
907 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 13550 times.
|
13550 | BOOST_ASSERT(cbp[0].size() >= body_avail_); |
908 | 13550 | return core::string_view( | |
909 | static_cast<char const*>( | ||
910 | 13550 | cbp[0].data()), | |
911 | 27100 | body_avail_); | |
912 | } | ||
913 | } | ||
914 | |||
915 | core::string_view | ||
916 | ✗ | parser:: | |
917 | release_buffered_data() noexcept | ||
918 | { | ||
919 | ✗ | return {}; | |
920 | } | ||
921 | |||
922 | //------------------------------------------------ | ||
923 | // | ||
924 | // Implementation | ||
925 | // | ||
926 | //------------------------------------------------ | ||
927 | |||
928 | auto | ||
929 | 55 | parser:: | |
930 | safe_get_header() const -> | ||
931 | detail::header const* | ||
932 | { | ||
933 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | switch(st_) |
934 | { | ||
935 | ✗ | default: | |
936 | case state::start: | ||
937 | case state::header: | ||
938 | // Headers not received yet | ||
939 | ✗ | detail::throw_logic_error(); | |
940 | |||
941 | 55 | case state::body: | |
942 | case state::complete: | ||
943 | // VFALCO check if headers are discarded? | ||
944 | 55 | break; | |
945 | } | ||
946 | 55 | return &h_; | |
947 | } | ||
948 | |||
949 | // return true if payload is plain | ||
950 | bool | ||
951 | 23973 | parser:: | |
952 | is_plain() const noexcept | ||
953 | { | ||
954 | return | ||
955 |
1/2✓ Branch 0 taken 23973 times.
✗ Branch 1 not taken.
|
47946 | h_.md.payload != payload::chunked && |
956 |
2/2✓ Branch 0 taken 23232 times.
✓ Branch 1 taken 741 times.
|
47946 | ! filt_; |
957 | } | ||
958 | |||
959 | // Called immediately after | ||
960 | // complete headers are received | ||
961 | void | ||
962 | 14152 | parser:: | |
963 | on_headers( | ||
964 | system::error_code& ec) | ||
965 | { | ||
966 | auto const overread = | ||
967 | 14152 | fb_.size() - h_.size; | |
968 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 14152 times.
|
14152 | BOOST_ASSERT( |
969 | overread <= svc_.max_overread()); | ||
970 | |||
971 | // reserve headers + table | ||
972 | 14152 | ws_.reserve_front(h_.size); | |
973 | 14152 | ws_.reserve_back(h_.table_space()); | |
974 | |||
975 | // no payload | ||
976 |
2/2✓ Branch 0 taken 12068 times.
✓ Branch 1 taken 2084 times.
|
14152 | if( h_.md.payload == payload::none || |
977 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12068 times.
|
12068 | head_response_) |
978 | { | ||
979 | // set cb0_ to overread | ||
980 | 4168 | cb0_ = { | |
981 | 2084 | ws_.data(), | |
982 | 2084 | fb_.capacity() - h_.size, | |
983 | overread }; | ||
984 | 2084 | body_avail_ = 0; | |
985 | 2084 | body_total_ = 0; | |
986 | 2084 | body_buf_ = &cb0_; | |
987 | 2084 | st_ = state::complete; | |
988 | 2084 | return; | |
989 | } | ||
990 | |||
991 | // metadata error | ||
992 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12068 times.
|
12068 | if(h_.md.payload == payload::error) |
993 | { | ||
994 | // VFALCO This needs looking at | ||
995 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
996 | error::bad_payload); | ||
997 | ✗ | st_ = state::reset; // unrecoverable | |
998 | ✗ | return; | |
999 | } | ||
1000 | |||
1001 | // calculate filter | ||
1002 | 12068 | filt_ = nullptr; | |
1003 | |||
1004 | // plain payload | ||
1005 |
1/2✓ Branch 1 taken 12068 times.
✗ Branch 2 not taken.
|
12068 | if(is_plain()) |
1006 | { | ||
1007 | // payload size is known | ||
1008 |
2/2✓ Branch 0 taken 7446 times.
✓ Branch 1 taken 4622 times.
|
12068 | if(h_.md.payload == payload::size) |
1009 | { | ||
1010 | 7446 | if(h_.md.payload_size > | |
1011 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7446 times.
|
7446 | svc_.cfg.body_limit) |
1012 | { | ||
1013 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
1014 | error::body_too_large); | ||
1015 | ✗ | st_ = state::reset; // unrecoverable | |
1016 | ✗ | return; | |
1017 | } | ||
1018 | auto n0 = | ||
1019 | 7446 | fb_.capacity() - h_.size + | |
1020 | 7446 | svc_.cfg.min_buffer + | |
1021 | 7446 | svc_.max_codec; | |
1022 | // limit the capacity of cb0_ so | ||
1023 | // that going over max_overread | ||
1024 | // is impossible. | ||
1025 |
3/6✓ Branch 0 taken 7446 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7446 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7446 times.
✗ Branch 5 not taken.
|
14892 | if( n0 > h_.md.payload_size && |
1026 | 7446 | n0 - h_.md.payload_size >= | |
1027 | 7446 | svc_.max_overread()) | |
1028 | 7446 | n0 = | |
1029 | 7446 | h_.md.payload_size + | |
1030 | 7446 | svc_.max_overread(); | |
1031 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7446 times.
|
7446 | BOOST_ASSERT(n0 <= ws_.size()); |
1032 | 7446 | cb0_ = { | |
1033 | 7446 | ws_.data(), | |
1034 | n0, | ||
1035 | overread }; | ||
1036 | 7446 | body_buf_ = &cb0_; | |
1037 | 7446 | body_avail_ = cb0_.size(); | |
1038 |
2/2✓ Branch 0 taken 6276 times.
✓ Branch 1 taken 1170 times.
|
7446 | if( body_avail_ >= h_.md.payload_size) |
1039 | 6276 | body_avail_ = h_.md.payload_size; | |
1040 | 7446 | body_total_ = body_avail_; | |
1041 | 7446 | payload_remain_ = | |
1042 | 7446 | h_.md.payload_size - body_total_; | |
1043 | 7446 | st_ = state::body; | |
1044 | 7446 | return; | |
1045 | } | ||
1046 | |||
1047 | // payload to eof | ||
1048 | // overread is not applicable | ||
1049 | auto const n0 = | ||
1050 | 4622 | fb_.capacity() - h_.size + | |
1051 | 4622 | svc_.cfg.min_buffer + | |
1052 | 4622 | svc_.max_codec; | |
1053 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4622 times.
|
4622 | BOOST_ASSERT(n0 <= ws_.size()); |
1054 | 4622 | cb0_ = { | |
1055 | 4622 | ws_.data(), | |
1056 | n0, | ||
1057 | overread }; | ||
1058 | 4622 | body_buf_ = &cb0_; | |
1059 | 4622 | body_avail_ = cb0_.size(); | |
1060 | 4622 | body_total_ = body_avail_; | |
1061 | 4622 | st_ = state::body; | |
1062 | 4622 | return; | |
1063 | } | ||
1064 | |||
1065 | // buffered payload | ||
1066 | auto const n0 = | ||
1067 | ✗ | fb_.capacity() - h_.size; | |
1068 | ✗ | BOOST_ASSERT( | |
1069 | n0 <= svc_.max_overread()); | ||
1070 | ✗ | auto n1 = svc_.cfg.min_buffer; | |
1071 | ✗ | if(! filt_) | |
1072 | ✗ | n1 += svc_.max_codec; | |
1073 | ✗ | BOOST_ASSERT( | |
1074 | n0 + n1 <= ws_.size()); | ||
1075 | ✗ | cb0_ = { | |
1076 | ✗ | ws_.data(), | |
1077 | n0, | ||
1078 | overread }; | ||
1079 | ✗ | cb1_ = { | |
1080 | ✗ | ws_.data() + n0, | |
1081 | n1 }; | ||
1082 | ✗ | body_buf_ = &cb1_; | |
1083 | ✗ | body_avail_ = 0; | |
1084 | ✗ | body_total_ = 0; | |
1085 | ✗ | st_ = state::body; | |
1086 | ✗ | return; | |
1087 | } | ||
1088 | |||
1089 | // Called at the end of set_body | ||
1090 | void | ||
1091 | 6775 | parser:: | |
1092 | on_set_body() | ||
1093 | { | ||
1094 | // This function is called after all | ||
1095 | // limit checking and calculation of | ||
1096 | // chunked or filter. | ||
1097 | |||
1098 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6775 times.
|
6775 | BOOST_ASSERT(got_header()); |
1099 | |||
1100 | // VFALCO review this hack | ||
1101 |
2/2✓ Branch 1 taken 741 times.
✓ Branch 2 taken 6034 times.
|
6775 | if(! is_plain()) |
1102 | 741 | return; | |
1103 | |||
1104 | // plain payload | ||
1105 | |||
1106 |
1/2✓ Branch 0 taken 6034 times.
✗ Branch 1 not taken.
|
6034 | if(how_ == how::dynamic) |
1107 | { | ||
1108 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6034 times.
|
6034 | if(h_.md.payload == payload::none) |
1109 | { | ||
1110 | ✗ | st_ = state::complete; | |
1111 | ✗ | return; | |
1112 | } | ||
1113 | 6034 | auto n = body_avail_; | |
1114 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6034 times.
|
6034 | BOOST_ASSERT(n <= body_buf_->size()); |
1115 | auto const space_left = | ||
1116 | 6034 | dyn_->max_size() - dyn_->size(); | |
1117 |
2/2✓ Branch 0 taken 630 times.
✓ Branch 1 taken 5404 times.
|
6034 | if( n > space_left) |
1118 | 630 | n = space_left; | |
1119 |
2/2✓ Branch 0 taken 3723 times.
✓ Branch 1 taken 2311 times.
|
6034 | if(h_.md.payload == payload::size) |
1120 | { | ||
1121 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3723 times.
|
3723 | if( n > h_.md.payload_size) |
1122 | ✗ | n = h_.md.payload_size; | |
1123 | // reserve space | ||
1124 |
1/2✓ Branch 0 taken 3723 times.
✗ Branch 1 not taken.
|
3723 | if(space_left >= h_.md.payload_size) |
1125 | 3723 | dyn_->prepare(h_.md.payload_size); | |
1126 | else | ||
1127 | ✗ | dyn_->prepare(space_left); | |
1128 | } | ||
1129 |
1/2✓ Branch 2 taken 6034 times.
✗ Branch 3 not taken.
|
6034 | dyn_->commit( |
1130 | buffers::buffer_copy( | ||
1131 |
1/2✓ Branch 1 taken 6034 times.
✗ Branch 2 not taken.
|
6034 | dyn_->prepare(n), |
1132 | 6034 | body_buf_->data())); | |
1133 | 6034 | body_buf_->consume(n); | |
1134 | 6034 | body_avail_ -= n; | |
1135 | // VFALCO maybe update payload_remain_ here | ||
1136 |
2/2✓ Branch 0 taken 3723 times.
✓ Branch 1 taken 2311 times.
|
6034 | if( h_.md.payload == payload::size) |
1137 | { | ||
1138 |
2/2✓ Branch 0 taken 585 times.
✓ Branch 1 taken 3138 times.
|
3723 | if(n < h_.md.payload_size) |
1139 | { | ||
1140 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 585 times.
|
585 | BOOST_ASSERT( |
1141 | payload_remain_ > 0); | ||
1142 | 585 | return; | |
1143 | } | ||
1144 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3138 times.
|
3138 | BOOST_ASSERT( |
1145 | n == h_.md.payload_size); | ||
1146 | // complete | ||
1147 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3138 times.
|
3138 | BOOST_ASSERT( |
1148 | payload_remain_ == 0); | ||
1149 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3138 times.
|
3138 | BOOST_ASSERT(body_avail_ == 0); |
1150 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3138 times.
|
3138 | BOOST_ASSERT(body_total_ == n); |
1151 | 3138 | st_ = state::complete; | |
1152 | 3138 | return; | |
1153 | } | ||
1154 | |||
1155 | 2311 | st_ = state::body; | |
1156 | 2311 | return; | |
1157 | } | ||
1158 | |||
1159 | ✗ | if(how_ == how::sink) | |
1160 | { | ||
1161 | // handle this in prepare() where | ||
1162 | // we can return an error_code. | ||
1163 | ✗ | st_ = state::body_set; | |
1164 | ✗ | return; | |
1165 | } | ||
1166 | |||
1167 | // VFALCO TODO | ||
1168 | ✗ | st_ = state::body_set; | |
1169 | ✗ | detail::throw_logic_error(); | |
1170 | } | ||
1171 | |||
1172 | } // http_proto | ||
1173 | } // boost | ||
1174 | |||
1175 | #endif | ||
1176 |