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 | /* | ||
28 | Buffer Usage | ||
29 | |||
30 | | | begin | ||
31 | | H | p | | f | read headers | ||
32 | | H | p | | T | f | set T body | ||
33 | | H | p | | C | T | f | make codec C | ||
34 | | H | p | b | C | T | f | decode p into b | ||
35 | | H | p | b | C | T | f | read/parse loop | ||
36 | | H | | T | f | destroy codec | ||
37 | | H | | T | f | finished | ||
38 | |||
39 | H headers | ||
40 | C codec | ||
41 | T body | ||
42 | f table | ||
43 | p partial payload | ||
44 | b body data | ||
45 | |||
46 | - We can compact the headers: | ||
47 | move the table downwards to | ||
48 | squeeze out the unused space | ||
49 | |||
50 | A "plain payload" has no actionable transfer | ||
51 | encoding. | ||
52 | |||
53 | A "buffered payload" is any payload which is | ||
54 | not plain. A second buffer is required | ||
55 | for reading. | ||
56 | */ | ||
57 | //------------------------------------------------ | ||
58 | |||
59 | class parser_service | ||
60 | : public service | ||
61 | { | ||
62 | public: | ||
63 | parser::config_base cfg; | ||
64 | std::size_t space_needed = 0; | ||
65 | std::size_t max_codec = 0; | ||
66 | zlib::deflate_decoder_service const* | ||
67 | deflate_svc = nullptr; | ||
68 | |||
69 | parser_service( | ||
70 | context& ctx, | ||
71 | parser::config_base const& cfg_); | ||
72 | |||
73 | std::size_t | ||
74 | 40065 | max_overread() const noexcept | |
75 | { | ||
76 | return | ||
77 | 40065 | cfg.headers.max_size + | |
78 | 40065 | cfg.min_buffer; | |
79 | } | ||
80 | }; | ||
81 | |||
82 | 6 | parser_service:: | |
83 | parser_service( | ||
84 | context& ctx, | ||
85 | 6 | parser::config_base const& cfg_) | |
86 | 6 | : cfg(cfg_) | |
87 | { | ||
88 | /* | ||
89 | | fb | cb0 | cb1 | C | T | f | | ||
90 | |||
91 | fb flat_buffer headers.max_size | ||
92 | cb0 circular_buffer min_buffer | ||
93 | cb1 circular_buffer min_buffer | ||
94 | C codec max_codec | ||
95 | T body max_type_erase | ||
96 | f table max_table_space | ||
97 | |||
98 | */ | ||
99 | // validate | ||
100 | //if(cfg.min_prepare > cfg.max_prepare) | ||
101 | //detail::throw_invalid_argument(); | ||
102 | |||
103 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if( cfg.min_buffer < 1 || |
104 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | cfg.min_buffer > cfg.body_limit) |
105 | ✗ | detail::throw_invalid_argument(); | |
106 | |||
107 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if(cfg.max_prepare < 1) |
108 | ✗ | detail::throw_invalid_argument(); | |
109 | |||
110 | // VFALCO TODO OVERFLOW CHECING | ||
111 | { | ||
112 | //fb_.size() - h_.size + | ||
113 | //svc_.cfg.min_buffer + | ||
114 | //svc_.cfg.min_buffer + | ||
115 | //svc_.max_codec; | ||
116 | } | ||
117 | |||
118 | // VFALCO OVERFLOW CHECKING ON THIS | ||
119 | 6 | space_needed += | |
120 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | cfg.headers.valid_space_needed(); |
121 | |||
122 | // cb0_, cb1_ | ||
123 | // VFALCO OVERFLOW CHECKING ON THIS | ||
124 | 6 | space_needed += | |
125 | 6 | cfg.min_buffer + | |
126 | cfg.min_buffer; | ||
127 | |||
128 | // T | ||
129 | 6 | space_needed += cfg.max_type_erase; | |
130 | |||
131 | // max_codec | ||
132 | { | ||
133 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if(cfg.apply_deflate_decoder) |
134 | { | ||
135 | ✗ | deflate_svc = &ctx.get_service< | |
136 | ✗ | zlib::deflate_decoder_service>(); | |
137 | auto const n = | ||
138 | ✗ | deflate_svc->space_needed(); | |
139 | ✗ | if( max_codec < n) | |
140 | ✗ | max_codec = n; | |
141 | } | ||
142 | } | ||
143 | 6 | space_needed += max_codec; | |
144 | 6 | } | |
145 | |||
146 | void | ||
147 | 6 | install_parser_service( | |
148 | context& ctx, | ||
149 | parser::config_base const& cfg) | ||
150 | { | ||
151 | ctx.make_service< | ||
152 | 6 | parser_service>(cfg); | |
153 | 6 | } | |
154 | |||
155 | //------------------------------------------------ | ||
156 | |||
157 | 6646 | parser:: | |
158 | parser( | ||
159 | context& ctx, | ||
160 | 6646 | detail::kind k) | |
161 | : ctx_(ctx) | ||
162 | , svc_(ctx.get_service< | ||
163 | 13292 | parser_service>()) | |
164 | , h_(detail::empty{k}) | ||
165 | 6646 | , st_(state::reset) | |
166 | { | ||
167 | 6646 | auto const n = | |
168 | 6646 | svc_.space_needed; | |
169 |
1/2✓ Branch 1 taken 6646 times.
✗ Branch 2 not taken.
|
6646 | ws_.allocate(n); |
170 | 6646 | h_.cap = n; | |
171 | 6646 | } | |
172 | |||
173 | //------------------------------------------------ | ||
174 | // | ||
175 | // Special Members | ||
176 | // | ||
177 | //------------------------------------------------ | ||
178 | |||
179 | 6646 | parser:: | |
180 | 6646 | ~parser() | |
181 | { | ||
182 | 6646 | } | |
183 | |||
184 | parser:: | ||
185 | parser( | ||
186 | parser&&) noexcept = default; | ||
187 | |||
188 | //------------------------------------------------ | ||
189 | // | ||
190 | // Modifiers | ||
191 | // | ||
192 | //------------------------------------------------ | ||
193 | |||
194 | // prepare for a new stream | ||
195 | void | ||
196 | 6644 | parser:: | |
197 | reset() noexcept | ||
198 | { | ||
199 | 6644 | ws_.clear(); | |
200 | 6644 | st_ = state::start; | |
201 | 6644 | got_eof_ = false; | |
202 | 6644 | } | |
203 | |||
204 | void | ||
205 | 6644 | parser:: | |
206 | start_impl( | ||
207 | bool head_response) | ||
208 | { | ||
209 | 6644 | std::size_t leftover = 0; | |
210 |
1/5✗ Branch 0 not taken.
✓ Branch 1 taken 6644 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
6644 | switch(st_) |
211 | { | ||
212 | ✗ | default: | |
213 | case state::reset: | ||
214 | // reset must be called first | ||
215 | ✗ | detail::throw_logic_error(); | |
216 | |||
217 | 6644 | case state::start: | |
218 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6644 times.
|
6644 | BOOST_ASSERT(h_.size == 0); |
219 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6644 times.
|
6644 | BOOST_ASSERT(fb_.size() == 0); |
220 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6644 times.
|
6644 | BOOST_ASSERT(! got_eof_); |
221 | 6644 | break; | |
222 | |||
223 | ✗ | case state::header: | |
224 | // start() called twice | ||
225 | ✗ | detail::throw_logic_error(); | |
226 | |||
227 | ✗ | case state::body: | |
228 | // current message is incomplete | ||
229 | ✗ | detail::throw_logic_error(); | |
230 | |||
231 | ✗ | case state::complete: | |
232 | { | ||
233 | // overread data is always in cb0_ | ||
234 | |||
235 | ✗ | if(fb_.size() > 0) | |
236 | { | ||
237 | // headers with no body | ||
238 | ✗ | BOOST_ASSERT(h_.size > 0); | |
239 | ✗ | fb_.consume(h_.size); | |
240 | ✗ | leftover = fb_.size(); | |
241 | // move unused octets to front | ||
242 | ✗ | buffers::buffer_copy( | |
243 | ✗ | buffers::mutable_buffer( | |
244 | ✗ | ws_.data(), | |
245 | leftover), | ||
246 | ✗ | fb_.data()); | |
247 | } | ||
248 | else | ||
249 | { | ||
250 | // leftover data after body | ||
251 | } | ||
252 | ✗ | break; | |
253 | } | ||
254 | } | ||
255 | |||
256 | 6644 | ws_.clear(); | |
257 | |||
258 | 13288 | fb_ = { | |
259 | 6644 | ws_.data(), | |
260 | 6644 | svc_.cfg.headers.max_size + | |
261 | 6644 | svc_.cfg.min_buffer, | |
262 | leftover }; | ||
263 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 6644 times.
|
6644 | BOOST_ASSERT( |
264 | fb_.capacity() == svc_.max_overread()); | ||
265 | |||
266 | 13288 | h_ = detail::header( | |
267 | 6644 | detail::empty{h_.kind}); | |
268 | 6644 | h_.buf = reinterpret_cast< | |
269 | 6644 | char*>(ws_.data()); | |
270 | 6644 | h_.cbuf = h_.buf; | |
271 | 6644 | h_.cap = ws_.size(); | |
272 | |||
273 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 6644 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
6644 | BOOST_ASSERT(! head_response || |
274 | h_.kind == detail::kind::response); | ||
275 | 6644 | head_response_ = head_response; | |
276 | |||
277 | 6644 | body_ = body::in_place; | |
278 | 6644 | st_ = state::header; | |
279 | 6644 | } | |
280 | |||
281 | auto | ||
282 | 20356 | parser:: | |
283 | prepare() -> | ||
284 | mutable_buffers_type | ||
285 | { | ||
286 |
2/5✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 19459 times.
✓ Branch 3 taken 897 times.
✗ Branch 4 not taken.
|
20356 | switch(st_) |
287 | { | ||
288 | ✗ | default: | |
289 | case state::reset: | ||
290 | // reset must be called first | ||
291 | ✗ | detail::throw_logic_error(); | |
292 | |||
293 | ✗ | case state::start: | |
294 | // start must be called first | ||
295 | ✗ | detail::throw_logic_error(); | |
296 | |||
297 | 19459 | case state::header: | |
298 | { | ||
299 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19459 times.
|
19459 | BOOST_ASSERT(h_.size < |
300 | svc_.cfg.headers.max_size); | ||
301 | 19459 | auto n = fb_.capacity() - fb_.size(); | |
302 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 19459 times.
|
19459 | BOOST_ASSERT(n <= svc_.max_overread()); |
303 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19459 times.
|
19459 | if( n > svc_.cfg.max_prepare) |
304 | ✗ | n = svc_.cfg.max_prepare; | |
305 | 19459 | mbp_[0] = fb_.prepare(n); | |
306 | 19459 | return mutable_buffers_type( | |
307 | 38918 | &mbp_[0], 1); | |
308 | } | ||
309 | |||
310 | 897 | case state::body: | |
311 | { | ||
312 | // buffered payload | ||
313 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 897 times.
|
897 | if(body_buf_ != &cb0_) |
314 | { | ||
315 | ✗ | auto n = cb0_.capacity() - | |
316 | ✗ | cb0_.size(); | |
317 | ✗ | if( n > svc_.cfg.max_prepare) | |
318 | ✗ | n = svc_.cfg.max_prepare; | |
319 | ✗ | mbp_ = cb0_.prepare(n); | |
320 | ✗ | return mutable_buffers_type(mbp_); | |
321 | } | ||
322 | |||
323 | // plain payload | ||
324 | |||
325 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 897 times.
|
897 | if( body_ == body::in_place || |
326 | ✗ | body_ == body::sink) | |
327 | { | ||
328 | 897 | auto n = cb0_.capacity() - | |
329 | 897 | cb0_.size(); | |
330 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 897 times.
|
897 | if( n > svc_.cfg.max_prepare) |
331 | ✗ | n = svc_.cfg.max_prepare; | |
332 | 897 | mbp_ = cb0_.prepare(n); | |
333 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 897 times.
|
897 | BOOST_ASSERT(mbp_[1].size() == 0); |
334 | 897 | return mutable_buffers_type( | |
335 | 1794 | &mbp_[0], 1); | |
336 | } | ||
337 | |||
338 | ✗ | if(body_ == body::dynamic) | |
339 | { | ||
340 | ✗ | BOOST_ASSERT(dyn_ != nullptr); | |
341 | ✗ | if(h_.md.payload == payload::size) | |
342 | { | ||
343 | // exact size | ||
344 | std::size_t n = | ||
345 | ✗ | h_.md.payload_size - dyn_->size(); | |
346 | ✗ | if( n > svc_.cfg.max_prepare) | |
347 | ✗ | n = svc_.cfg.max_prepare; | |
348 | ✗ | return dyn_->prepare(n); | |
349 | } | ||
350 | |||
351 | // heuristic size | ||
352 | ✗ | std::size_t n = svc_.cfg.min_buffer; | |
353 | ✗ | if( n > svc_.cfg.max_prepare) | |
354 | ✗ | n = svc_.cfg.max_prepare; | |
355 | ✗ | return dyn_->prepare(n); | |
356 | } | ||
357 | |||
358 | // VFALCO TODO | ||
359 | ✗ | if(body_ == body::stream) | |
360 | ✗ | detail::throw_logic_error(); | |
361 | |||
362 | // VFALCO TODO | ||
363 | ✗ | detail::throw_logic_error(); | |
364 | } | ||
365 | |||
366 | ✗ | case state::complete: | |
367 | // We allow the call for callers | ||
368 | // who want normalized usage, but | ||
369 | // just return a 0-sized sequence. | ||
370 | ✗ | return mutable_buffers_type{}; | |
371 | } | ||
372 | } | ||
373 | |||
374 | void | ||
375 | 20356 | parser:: | |
376 | commit( | ||
377 | std::size_t n) | ||
378 | { | ||
379 | // Can't commit after eof | ||
380 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20356 times.
|
20356 | if(got_eof_) |
381 | ✗ | detail::throw_logic_error(); | |
382 | |||
383 |
2/5✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 19459 times.
✓ Branch 3 taken 897 times.
✗ Branch 4 not taken.
|
20356 | switch(st_) |
384 | { | ||
385 | ✗ | default: | |
386 | case state::reset: | ||
387 | // reset must be called first | ||
388 | ✗ | detail::throw_logic_error(); | |
389 | |||
390 | ✗ | case state::start: | |
391 | // forgot to call start() | ||
392 | ✗ | detail::throw_logic_error(); | |
393 | |||
394 | 19459 | case state::header: | |
395 | 19459 | fb_.commit(n); | |
396 | 19459 | break; | |
397 | |||
398 | 897 | case state::body: | |
399 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 897 times.
|
897 | if(body_buf_ != &cb0_) |
400 | { | ||
401 | // buffered body | ||
402 | ✗ | cb0_.commit(n); | |
403 | ✗ | break; | |
404 | } | ||
405 |
1/2✓ Branch 0 taken 897 times.
✗ Branch 1 not taken.
|
897 | if(body_ == body::in_place) |
406 | { | ||
407 | 897 | cb0_.commit(n); | |
408 | 897 | break; | |
409 | } | ||
410 | ✗ | if(body_ == body::dynamic) | |
411 | { | ||
412 | ✗ | dyn_->commit(n); | |
413 | ✗ | break; | |
414 | } | ||
415 | ✗ | if(body_ == body::sink) | |
416 | { | ||
417 | ✗ | cb0_.commit(n); | |
418 | ✗ | break; | |
419 | } | ||
420 | ✗ | if(body_ == body::stream) | |
421 | { | ||
422 | // VFALCO TODO | ||
423 | ✗ | detail::throw_logic_error(); | |
424 | } | ||
425 | ✗ | break; | |
426 | |||
427 | ✗ | case state::complete: | |
428 | // intended no-op | ||
429 | ✗ | break; | |
430 | } | ||
431 | 20356 | } | |
432 | |||
433 | void | ||
434 | 1450 | parser:: | |
435 | commit_eof() | ||
436 | { | ||
437 |
1/5✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1450 times.
✗ Branch 4 not taken.
|
1450 | switch(st_) |
438 | { | ||
439 | ✗ | default: | |
440 | case state::reset: | ||
441 | // reset must be called first | ||
442 | ✗ | detail::throw_logic_error(); | |
443 | |||
444 | ✗ | case state::start: | |
445 | // forgot to call prepare() | ||
446 | ✗ | detail::throw_logic_error(); | |
447 | |||
448 | ✗ | case state::header: | |
449 | ✗ | got_eof_ = true; | |
450 | ✗ | break; | |
451 | |||
452 | 1450 | case state::body: | |
453 | 1450 | got_eof_ = true; | |
454 | 1450 | break; | |
455 | |||
456 | ✗ | case state::complete: | |
457 | // can't commit eof when complete | ||
458 | ✗ | detail::throw_logic_error(); | |
459 | } | ||
460 | 1450 | } | |
461 | |||
462 | //----------------------------------------------- | ||
463 | |||
464 | // process input data then | ||
465 | // eof if input data runs out. | ||
466 | void | ||
467 | 21806 | parser:: | |
468 | parse( | ||
469 | system::error_code& ec) | ||
470 | { | ||
471 | 21806 | ec = {}; | |
472 |
2/5✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 19459 times.
✓ Branch 3 taken 2347 times.
✗ Branch 4 not taken.
|
21806 | switch(st_) |
473 | { | ||
474 | ✗ | default: | |
475 | case state::reset: | ||
476 | // reset must be called first | ||
477 | ✗ | detail::throw_logic_error(); | |
478 | |||
479 | ✗ | case state::start: | |
480 | // start must be called first | ||
481 | ✗ | detail::throw_logic_error(); | |
482 | |||
483 | 19459 | case state::header: | |
484 | { | ||
485 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 19459 times.
|
19459 | BOOST_ASSERT(h_.buf == static_cast< |
486 | void const*>(ws_.data())); | ||
487 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 19459 times.
|
19459 | BOOST_ASSERT(h_.cbuf == static_cast< |
488 | void const*>(ws_.data())); | ||
489 | 19459 | auto const new_size = fb_.size(); | |
490 | 19459 | h_.parse(new_size, svc_.cfg.headers, ec); | |
491 |
2/2✓ Branch 2 taken 12815 times.
✓ Branch 3 taken 6644 times.
|
19459 | if(ec == condition::need_more_input) |
492 | { | ||
493 |
1/2✓ Branch 0 taken 12815 times.
✗ Branch 1 not taken.
|
12815 | if(! got_eof_) |
494 | { | ||
495 | // headers incomplete | ||
496 | 12815 | return; | |
497 | } | ||
498 | ✗ | if(h_.size == 0) | |
499 | { | ||
500 | // stream closed cleanly | ||
501 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
502 | error::end_of_stream); | ||
503 | ✗ | return; | |
504 | } | ||
505 | |||
506 | // stream closed with a | ||
507 | // partial message received | ||
508 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
509 | error::incomplete); | ||
510 | ✗ | return; | |
511 | } | ||
512 |
2/2✓ Branch 1 taken 128 times.
✓ Branch 2 taken 6516 times.
|
6644 | if(ec.failed()) |
513 | { | ||
514 | // other error, | ||
515 | // | ||
516 | // VFALCO map this to a bad | ||
517 | // request or bad response error? | ||
518 | // | ||
519 | 128 | st_ = state::reset; // unrecoverable | |
520 | 128 | return; | |
521 | } | ||
522 | |||
523 | // headers are complete | ||
524 | 6516 | on_headers(ec); | |
525 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6516 times.
|
6516 | if(ec.failed()) |
526 | ✗ | return; | |
527 |
2/2✓ Branch 0 taken 1343 times.
✓ Branch 1 taken 5173 times.
|
6516 | if(st_ == state::complete) |
528 | 1343 | break; | |
529 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5173 times.
|
5173 | BOOST_ASSERT(st_ == state::body); |
530 | BOOST_FALLTHROUGH; | ||
531 | } | ||
532 | |||
533 | case state::body: | ||
534 | { | ||
535 |
1/2✓ Branch 0 taken 7520 times.
✗ Branch 1 not taken.
|
7520 | if(body_ == body::in_place) |
536 | { | ||
537 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7520 times.
|
7520 | if(filt_) |
538 | { | ||
539 | // apply filter | ||
540 | ✗ | detail::throw_logic_error(); | |
541 | } | ||
542 |
2/2✓ Branch 0 taken 4338 times.
✓ Branch 1 taken 3182 times.
|
7520 | if(h_.md.payload == payload::size) |
543 | { | ||
544 | 4338 | if(cb0_.size() < | |
545 |
2/2✓ Branch 0 taken 615 times.
✓ Branch 1 taken 3723 times.
|
4338 | h_.md.payload_size) |
546 | { | ||
547 | 1230 | ec = BOOST_HTTP_PROTO_ERR( | |
548 | error::need_data); | ||
549 | 615 | return; | |
550 | } | ||
551 | 3723 | st_ = state::complete; | |
552 | 3723 | break; | |
553 | } | ||
554 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3182 times.
|
3182 | BOOST_ASSERT(h_.md.payload == |
555 | payload::to_eof); | ||
556 |
2/2✓ Branch 0 taken 1732 times.
✓ Branch 1 taken 1450 times.
|
3182 | if(! got_eof_) |
557 | { | ||
558 | 3464 | ec = BOOST_HTTP_PROTO_ERR( | |
559 | error::need_data); | ||
560 | 1732 | return; | |
561 | } | ||
562 | 1450 | st_ = state::complete; | |
563 | 1450 | break; | |
564 | } | ||
565 | |||
566 | // VFALCO TODO | ||
567 | ✗ | detail::throw_logic_error(); | |
568 | } | ||
569 | |||
570 | ✗ | case state::complete: | |
571 | { | ||
572 | // This is a no-op except when set_body | ||
573 | // was called and we have in-place data. | ||
574 | ✗ | switch(body_) | |
575 | { | ||
576 | ✗ | default: | |
577 | case body::in_place: | ||
578 | ✗ | break; | |
579 | |||
580 | ✗ | case body::dynamic: | |
581 | { | ||
582 | ✗ | if(body_buf_->size() == 0) | |
583 | ✗ | break; | |
584 | ✗ | BOOST_ASSERT(dyn_->size() == 0); | |
585 | ✗ | auto n = buffers::buffer_copy( | |
586 | ✗ | dyn_->prepare( | |
587 | ✗ | body_buf_->size()), | |
588 | ✗ | body_buf_->data()); | |
589 | ✗ | body_buf_->consume(n); | |
590 | ✗ | break; | |
591 | } | ||
592 | |||
593 | ✗ | case body::sink: | |
594 | { | ||
595 | ✗ | if(body_buf_->size() == 0) | |
596 | ✗ | break; | |
597 | ✗ | auto rv = sink_->write( | |
598 | ✗ | body_buf_->data(), false); | |
599 | ✗ | body_buf_->consume(rv.bytes); | |
600 | ✗ | if(rv.ec.failed()) | |
601 | { | ||
602 | ✗ | ec = rv.ec; | |
603 | ✗ | st_ = state::reset; // unrecoverable | |
604 | ✗ | return; | |
605 | } | ||
606 | ✗ | break; | |
607 | } | ||
608 | |||
609 | ✗ | case body::stream: | |
610 | // VFALCO TODO | ||
611 | ✗ | detail::throw_logic_error(); | |
612 | } | ||
613 | } | ||
614 | } | ||
615 | } | ||
616 | |||
617 | //------------------------------------------------ | ||
618 | |||
619 | auto | ||
620 | ✗ | parser:: | |
621 | get_stream() -> | ||
622 | stream | ||
623 | { | ||
624 | // body type already chosen | ||
625 | ✗ | if(body_ != body::in_place) | |
626 | ✗ | detail::throw_logic_error(); | |
627 | |||
628 | ✗ | body_ = body::stream; | |
629 | ✗ | return stream(*this); | |
630 | } | ||
631 | |||
632 | core::string_view | ||
633 | 4543 | parser:: | |
634 | in_place_body() const | ||
635 | { | ||
636 | // not in place | ||
637 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4543 times.
|
4543 | if(body_ != body::in_place) |
638 | ✗ | detail::throw_logic_error(); | |
639 | |||
640 | // incomplete | ||
641 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4543 times.
|
4543 | if(st_ != state::complete) |
642 | ✗ | detail::throw_logic_error(); | |
643 | |||
644 | 4543 | buffers::const_buffer_pair bs = body_buf_->data(); | |
645 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 4543 times.
|
4543 | BOOST_ASSERT(bs[1].size() == 0); |
646 | 9086 | return core::string_view(static_cast< | |
647 | 4543 | char const*>(bs[0].data()), | |
648 | 9086 | bs[0].size()); | |
649 | } | ||
650 | |||
651 | //------------------------------------------------ | ||
652 | |||
653 | core::string_view | ||
654 | ✗ | parser:: | |
655 | release_buffered_data() noexcept | ||
656 | { | ||
657 | ✗ | return {}; | |
658 | } | ||
659 | |||
660 | //------------------------------------------------ | ||
661 | // | ||
662 | // Implementation | ||
663 | // | ||
664 | //------------------------------------------------ | ||
665 | |||
666 | auto | ||
667 | 5969 | parser:: | |
668 | safe_get_header() const -> | ||
669 | detail::header const* | ||
670 | { | ||
671 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5969 times.
|
5969 | switch(st_) |
672 | { | ||
673 | ✗ | default: | |
674 | case state::start: | ||
675 | case state::header: | ||
676 | // Headers not received yet | ||
677 | ✗ | detail::throw_logic_error(); | |
678 | |||
679 | 5969 | case state::body: | |
680 | case state::complete: | ||
681 | // VFALCO check if headers are discarded? | ||
682 | 5969 | break; | |
683 | } | ||
684 | 5969 | return &h_; | |
685 | } | ||
686 | |||
687 | // Called immediately after | ||
688 | // complete headers are received | ||
689 | void | ||
690 | 6516 | parser:: | |
691 | on_headers( | ||
692 | system::error_code& ec) | ||
693 | { | ||
694 | auto const overread = | ||
695 | 6516 | fb_.size() - h_.size; | |
696 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6516 times.
|
6516 | BOOST_ASSERT( |
697 | overread <= svc_.max_overread()); | ||
698 | |||
699 | // reserve headers + table | ||
700 | 6516 | ws_.reserve_front(h_.size); | |
701 | 6516 | ws_.reserve_back(h_.table_space()); | |
702 | |||
703 | // no payload | ||
704 |
2/2✓ Branch 0 taken 5173 times.
✓ Branch 1 taken 1343 times.
|
6516 | if( h_.md.payload == payload::none || |
705 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5173 times.
|
5173 | head_response_) |
706 | { | ||
707 | // set cb0_ to overread | ||
708 | 2686 | cb0_ = { | |
709 | 1343 | ws_.data(), | |
710 | 1343 | fb_.capacity() - h_.size, | |
711 | overread }; | ||
712 | 1343 | st_ = state::complete; | |
713 | 1343 | return; | |
714 | } | ||
715 | |||
716 | // metadata error | ||
717 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5173 times.
|
5173 | if(h_.md.payload == payload::error) |
718 | { | ||
719 | // VFALCO This needs looking at | ||
720 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
721 | error::bad_payload); | ||
722 | ✗ | st_ = state::reset; // unrecoverable | |
723 | ✗ | return; | |
724 | } | ||
725 | |||
726 | // calculate filter | ||
727 | 5173 | filt_ = nullptr; | |
728 | |||
729 | // plain payload | ||
730 |
1/2✓ Branch 0 taken 5173 times.
✗ Branch 1 not taken.
|
5173 | if( h_.md.payload != payload::chunked && |
731 |
1/2✓ Branch 0 taken 5173 times.
✗ Branch 1 not taken.
|
5173 | ! filt_) |
732 | { | ||
733 | // payload size is known | ||
734 |
2/2✓ Branch 0 taken 3723 times.
✓ Branch 1 taken 1450 times.
|
5173 | if(h_.md.payload == payload::size) |
735 | { | ||
736 | 3723 | if(h_.md.payload_size > | |
737 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3723 times.
|
3723 | svc_.cfg.body_limit) |
738 | { | ||
739 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
740 | error::body_too_large); | ||
741 | ✗ | st_ = state::reset; // unrecoverable | |
742 | ✗ | return; | |
743 | } | ||
744 | auto n0 = | ||
745 | 3723 | fb_.capacity() - h_.size + | |
746 | 3723 | svc_.cfg.min_buffer + | |
747 | 3723 | svc_.max_codec; | |
748 | // limit the capacity of cb0_ so | ||
749 | // that going over max_overread | ||
750 | // is impossible. | ||
751 |
3/6✓ Branch 0 taken 3723 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3723 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3723 times.
✗ Branch 5 not taken.
|
7446 | if( n0 > h_.md.payload_size && |
752 | 3723 | n0 - h_.md.payload_size >= | |
753 | 3723 | svc_.max_overread()) | |
754 | 3723 | n0 = | |
755 | 3723 | h_.md.payload_size + | |
756 | 3723 | svc_.max_overread(); | |
757 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3723 times.
|
3723 | BOOST_ASSERT(n0 <= ws_.size()); |
758 | 3723 | cb0_ = { | |
759 | 3723 | ws_.data(), | |
760 | n0, | ||
761 | overread }; | ||
762 | 3723 | body_buf_ = &cb0_; | |
763 | 3723 | st_ = state::body; | |
764 | 3723 | return; | |
765 | } | ||
766 | |||
767 | // payload to eof | ||
768 | // overread is not applicable | ||
769 | auto const n0 = | ||
770 | 1450 | fb_.capacity() - h_.size + | |
771 | 1450 | svc_.cfg.min_buffer + | |
772 | 1450 | svc_.max_codec; | |
773 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1450 times.
|
1450 | BOOST_ASSERT(n0 <= ws_.size()); |
774 | 1450 | cb0_ = { | |
775 | 1450 | ws_.data(), | |
776 | n0, | ||
777 | overread }; | ||
778 | 1450 | body_buf_ = &cb0_; | |
779 | 1450 | st_ = state::body; | |
780 | 1450 | return; | |
781 | } | ||
782 | |||
783 | // buffered payload | ||
784 | auto const n0 = | ||
785 | ✗ | fb_.capacity() - h_.size; | |
786 | ✗ | BOOST_ASSERT( | |
787 | n0 <= svc_.max_overread()); | ||
788 | ✗ | auto n1 = svc_.cfg.min_buffer; | |
789 | ✗ | if(! filt_) | |
790 | ✗ | n1 += svc_.max_codec; | |
791 | ✗ | BOOST_ASSERT( | |
792 | n0 + n1 <= ws_.size()); | ||
793 | ✗ | cb0_ = { | |
794 | ✗ | ws_.data(), | |
795 | n0, | ||
796 | overread }; | ||
797 | ✗ | cb1_ = { | |
798 | ✗ | ws_.data() + n0, | |
799 | n1 }; | ||
800 | ✗ | body_buf_ = &cb1_; | |
801 | ✗ | st_ = state::body; | |
802 | ✗ | return; | |
803 | } | ||
804 | |||
805 | // Called at the end of set_body | ||
806 | void | ||
807 | ✗ | parser:: | |
808 | on_set_body() | ||
809 | { | ||
810 | // This function is called after all | ||
811 | // limit checking and calculation of | ||
812 | // chunked or filter. | ||
813 | |||
814 | ✗ | BOOST_ASSERT(got_header()); | |
815 | |||
816 | ✗ | if(h_.md.payload == payload::size) | |
817 | { | ||
818 | ✗ | if(body_ == body::dynamic) | |
819 | { | ||
820 | ✗ | dyn_->prepare( | |
821 | ✗ | h_.md.payload_size); | |
822 | ✗ | return; | |
823 | } | ||
824 | ✗ | if(body_ == body::sink) | |
825 | { | ||
826 | //sink_->size_hint(&h_.md.payload_size); | ||
827 | ✗ | return; | |
828 | } | ||
829 | ✗ | return; | |
830 | } | ||
831 | |||
832 | ✗ | return; | |
833 | } | ||
834 | |||
835 | } // http_proto | ||
836 | } // boost | ||
837 | |||
838 | #endif | ||
839 |