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 | #include <boost/http_proto/parser.hpp> | ||
11 | |||
12 | #include <boost/http_proto/context.hpp> | ||
13 | #include <boost/http_proto/error.hpp> | ||
14 | #include <boost/http_proto/rfc/detail/rules.hpp> | ||
15 | #include <boost/http_proto/service/zlib_service.hpp> | ||
16 | |||
17 | #include <boost/http_proto/detail/except.hpp> | ||
18 | |||
19 | #include <boost/buffers/algorithm.hpp> | ||
20 | #include <boost/buffers/buffer_copy.hpp> | ||
21 | #include <boost/buffers/buffer_size.hpp> | ||
22 | #include <boost/buffers/make_buffer.hpp> | ||
23 | |||
24 | #include <boost/url/grammar/ci_string.hpp> | ||
25 | #include <boost/url/grammar/parse.hpp> | ||
26 | |||
27 | #include <boost/assert.hpp> | ||
28 | |||
29 | #include <array> | ||
30 | #include <iostream> | ||
31 | #include <memory> | ||
32 | |||
33 | #include "rfc/detail/rules.hpp" | ||
34 | #include "zlib_service.hpp" | ||
35 | |||
36 | namespace boost { | ||
37 | namespace http_proto { | ||
38 | |||
39 | /* | ||
40 | Principles for fixed-size buffer design | ||
41 | |||
42 | axiom 1: | ||
43 | To read data you must have a buffer. | ||
44 | |||
45 | axiom 2: | ||
46 | The size of the HTTP header is not | ||
47 | known in advance. | ||
48 | |||
49 | conclusion 3: | ||
50 | A single I/O can produce a complete | ||
51 | HTTP header and additional payload | ||
52 | data. | ||
53 | |||
54 | conclusion 4: | ||
55 | A single I/O can produce multiple | ||
56 | complete HTTP headers, complete | ||
57 | payloads, and a partial header or | ||
58 | payload. | ||
59 | |||
60 | axiom 5: | ||
61 | A process is in one of two states: | ||
62 | 1. at or below capacity | ||
63 | 2. above capacity | ||
64 | |||
65 | axiom 6: | ||
66 | A program which can allocate an | ||
67 | unbounded number of resources can | ||
68 | go above capacity. | ||
69 | |||
70 | conclusion 7: | ||
71 | A program can guarantee never going | ||
72 | above capacity if all resources are | ||
73 | provisioned at program startup. | ||
74 | |||
75 | corollary 8: | ||
76 | `parser` and `serializer` should each | ||
77 | allocate a single buffer of calculated | ||
78 | size, and never resize it. | ||
79 | |||
80 | axiom #: | ||
81 | A parser and a serializer are always | ||
82 | used in pairs. | ||
83 | |||
84 | Buffer Usage | ||
85 | |||
86 | | | begin | ||
87 | | H | p | | f | read headers | ||
88 | | H | p | | T | f | set T body | ||
89 | | H | p | | C | T | f | make codec C | ||
90 | | H | p | b | C | T | f | decode p into b | ||
91 | | H | p | b | C | T | f | read/parse loop | ||
92 | | H | | T | f | destroy codec | ||
93 | | H | | T | f | finished | ||
94 | |||
95 | H headers | ||
96 | C codec | ||
97 | T body | ||
98 | f table | ||
99 | p partial payload | ||
100 | b body data | ||
101 | |||
102 | "payload" is the bytes coming in from | ||
103 | the stream. | ||
104 | |||
105 | "body" is the logical body, after transfer | ||
106 | encoding is removed. This can be the | ||
107 | same as the payload. | ||
108 | |||
109 | A "plain payload" is when the payload and | ||
110 | body are identical (no transfer encodings). | ||
111 | |||
112 | A "buffered payload" is any payload which is | ||
113 | not plain. A second buffer is required | ||
114 | for reading. | ||
115 | |||
116 | "overread" is additional data received past | ||
117 | the end of the headers when reading headers, | ||
118 | or additional data received past the end of | ||
119 | the message payload. | ||
120 | */ | ||
121 | //----------------------------------------------- | ||
122 | |||
123 | struct discontiguous_iterator | ||
124 | { | ||
125 | buffers::const_buffer const* pos = nullptr; | ||
126 | buffers::const_buffer const* end = nullptr; | ||
127 | std::size_t off = 0; | ||
128 | |||
129 | 329 | discontiguous_iterator( | |
130 | buffers::const_buffer const* pos_, | ||
131 | buffers::const_buffer const* end_) | ||
132 | 329 | : pos(pos_) | |
133 | 329 | , end(end_) | |
134 | { | ||
135 | 329 | } | |
136 | |||
137 | char | ||
138 | 3696 | operator*() const noexcept | |
139 | { | ||
140 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3696 times.
|
3696 | BOOST_ASSERT(pos); |
141 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3696 times.
|
3696 | BOOST_ASSERT(pos->size() > 0); |
142 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3696 times.
|
3696 | BOOST_ASSERT(off < pos->size()); |
143 | auto it = | ||
144 | 3696 | static_cast<char const*>(pos->data()) + off; | |
145 | 3696 | return *it; | |
146 | } | ||
147 | |||
148 | discontiguous_iterator& | ||
149 | 3368 | operator++() noexcept | |
150 | { | ||
151 | 3368 | ++off; | |
152 |
2/2✓ Branch 1 taken 204 times.
✓ Branch 2 taken 3164 times.
|
3368 | if( off >= pos->size() ) |
153 | { | ||
154 | 204 | ++pos; | |
155 | 204 | off = 0; | |
156 |
5/6✓ Branch 0 taken 204 times.
✓ Branch 1 taken 204 times.
✓ Branch 3 taken 204 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 204 times.
✓ Branch 6 taken 204 times.
|
408 | while( pos != end && pos->size() == 0 ) |
157 | 204 | ++pos; | |
158 | 204 | return *this; | |
159 | } | ||
160 | 3164 | return *this; | |
161 | } | ||
162 | |||
163 | discontiguous_iterator | ||
164 | 3152 | operator++(int) noexcept | |
165 | { | ||
166 | 3152 | auto old = *this; | |
167 | 3152 | ++*this; | |
168 | 3152 | return old; | |
169 | } | ||
170 | |||
171 | bool | ||
172 | operator==( | ||
173 | discontiguous_iterator const& rhs) const noexcept | ||
174 | { | ||
175 | return pos == rhs.pos && off == rhs.off; | ||
176 | } | ||
177 | |||
178 | bool | ||
179 | operator!=( | ||
180 | discontiguous_iterator const& rhs) const noexcept | ||
181 | { | ||
182 | return !(*this == rhs); | ||
183 | } | ||
184 | |||
185 | bool | ||
186 | 3501 | done() const noexcept | |
187 | { | ||
188 | 3501 | return pos == end; | |
189 | } | ||
190 | }; | ||
191 | |||
192 | constexpr static | ||
193 | std::size_t const max_chunk_header_len = 16 + 2; | ||
194 | |||
195 | constexpr static | ||
196 | std::size_t const last_chunk_len = 5; | ||
197 | |||
198 | static | ||
199 | void | ||
200 | 248 | parse_chunk_header( | |
201 | buffers::circular_buffer& input, | ||
202 | system::error_code& ec, | ||
203 | std::size_t& chunk_remain_) | ||
204 | { | ||
205 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 244 times.
|
248 | if( input.size() == 0 ) |
206 | { | ||
207 | 4 | ec = error::need_data; | |
208 | 98 | return; | |
209 | } | ||
210 | |||
211 | 244 | char tmp[max_chunk_header_len] = {}; | |
212 | 244 | auto* p = tmp; | |
213 | 244 | unsigned num_leading_zeros = 0; | |
214 | |||
215 | { | ||
216 | 244 | auto cbs = input.data(); | |
217 | 244 | discontiguous_iterator pos(cbs.begin(), cbs.end()); | |
218 | |||
219 |
6/6✓ Branch 1 taken 371 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 128 times.
✓ Branch 5 taken 243 times.
✓ Branch 6 taken 128 times.
✓ Branch 7 taken 244 times.
|
372 | for( ; !pos.done() && *pos == '0'; ++pos ) |
220 | 128 | ++num_leading_zeros; | |
221 | |||
222 |
4/4✓ Branch 0 taken 2956 times.
✓ Branch 1 taken 116 times.
✓ Branch 2 taken 2828 times.
✓ Branch 3 taken 244 times.
|
6028 | for( ; p < (tmp + max_chunk_header_len) && |
223 |
2/2✓ Branch 1 taken 2828 times.
✓ Branch 2 taken 128 times.
|
2956 | !pos.done(); ) |
224 | 2828 | *p++ = *pos++; | |
225 | } | ||
226 | |||
227 | 244 | core::string_view sv(tmp, p - tmp); | |
228 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 244 times.
|
244 | BOOST_ASSERT(sv.size() <= input.size()); |
229 | |||
230 | 244 | auto it = sv.begin(); | |
231 | auto rv = | ||
232 | 244 | grammar::parse(it, sv.end(), detail::hex_rule); | |
233 | |||
234 |
2/2✓ Branch 1 taken 85 times.
✓ Branch 2 taken 159 times.
|
244 | if( rv.has_error() ) |
235 | { | ||
236 | 85 | ec = error::bad_payload; | |
237 | 85 | return; | |
238 | } | ||
239 | |||
240 | auto rv2 = | ||
241 | 159 | grammar::parse(it, sv.end(), detail::crlf_rule); | |
242 |
2/2✓ Branch 1 taken 9 times.
✓ Branch 2 taken 150 times.
|
159 | if( rv2.has_error() ) |
243 | { | ||
244 |
2/2✓ Branch 3 taken 6 times.
✓ Branch 4 taken 3 times.
|
9 | if( rv2.error() == condition::need_more_input ) |
245 | 6 | ec = error::need_data; | |
246 | else | ||
247 | 3 | ec = error::bad_payload; | |
248 | 9 | return; | |
249 | } | ||
250 | |||
251 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 150 times.
|
150 | if( rv->v == 0 ) |
252 | { | ||
253 | ✗ | ec = error::bad_payload; | |
254 | ✗ | return; | |
255 | } | ||
256 | |||
257 | 150 | auto n = num_leading_zeros + (it - sv.begin()); | |
258 | 150 | input.consume(n); | |
259 | 150 | chunk_remain_ = rv->v; | |
260 | }; | ||
261 | |||
262 | static | ||
263 | void | ||
264 | 98 | parse_last_chunk( | |
265 | buffers::circular_buffer& input, | ||
266 | system::error_code& ec) | ||
267 | { | ||
268 | // chunked-body = *chunk last-chunk trailer-section CRLF | ||
269 | // last-chunk = 1*"0" [ chunk-ext ] CRLF | ||
270 | // | ||
271 | // drop support trailers/chunk-ext, use internal definition | ||
272 | // | ||
273 | // last-chunk = 1*"0" CRLF CRLF | ||
274 | |||
275 |
2/2✓ Branch 2 taken 13 times.
✓ Branch 3 taken 85 times.
|
98 | if( buffers::buffer_size(input.data()) < |
276 | last_chunk_len ) | ||
277 | { | ||
278 | 13 | ec = error::need_data; | |
279 | 25 | return; | |
280 | } | ||
281 | |||
282 | 85 | auto cbs = input.data(); | |
283 | 85 | discontiguous_iterator pos(cbs.begin(), cbs.end()); | |
284 | |||
285 | 85 | std::size_t len = 0; | |
286 |
5/6✓ Branch 2 taken 173 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 88 times.
✓ Branch 6 taken 85 times.
✓ Branch 7 taken 88 times.
✓ Branch 8 taken 85 times.
|
173 | for( ; !pos.done() && *pos == '0'; ++pos, ++len ) |
287 | { | ||
288 | } | ||
289 | |||
290 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 81 times.
|
85 | if( len == 0 ) |
291 | { | ||
292 | 4 | ec = error::bad_payload; | |
293 | 4 | return; | |
294 | } | ||
295 | |||
296 | 81 | std::size_t const close_len = 4; // for \r\n\r\n | |
297 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 81 times.
|
81 | if( buffers::buffer_size(input.data()) - len < |
298 | close_len ) | ||
299 | { | ||
300 | ✗ | ec = error::need_data; | |
301 | ✗ | return; | |
302 | } | ||
303 | |||
304 | 81 | char tmp[close_len] = {}; | |
305 |
2/2✓ Branch 0 taken 324 times.
✓ Branch 1 taken 81 times.
|
405 | for( std::size_t i = 0; i < close_len; ++i ) |
306 | 324 | tmp[i] = *pos++; | |
307 | |||
308 | 81 | core::string_view s(tmp, close_len); | |
309 |
2/2✓ Branch 2 taken 8 times.
✓ Branch 3 taken 73 times.
|
81 | if( s != "\r\n\r\n" ) |
310 | { | ||
311 | 8 | ec = error::bad_payload; | |
312 | 8 | return; | |
313 | } | ||
314 | |||
315 | 73 | input.consume(len + close_len); | |
316 | }; | ||
317 | |||
318 | template <class ElasticBuffer> | ||
319 | bool | ||
320 | 238 | parse_chunked( | |
321 | buffers::circular_buffer& input, | ||
322 | ElasticBuffer& output, | ||
323 | system::error_code& ec, | ||
324 | std::size_t& chunk_remain_, | ||
325 | bool& needs_chunk_close_) | ||
326 | { | ||
327 |
2/2✓ Branch 1 taken 72 times.
✓ Branch 2 taken 166 times.
|
238 | if( input.size() == 0 ) |
328 | { | ||
329 | 72 | ec = error::need_data; | |
330 | 72 | return false; | |
331 | } | ||
332 | |||
333 | 350 | for(;;) | |
334 | { | ||
335 |
2/2✓ Branch 0 taken 403 times.
✓ Branch 1 taken 113 times.
|
516 | if( chunk_remain_ == 0 ) |
336 | { | ||
337 |
2/2✓ Branch 0 taken 155 times.
✓ Branch 1 taken 248 times.
|
403 | if( needs_chunk_close_ ) |
338 | { | ||
339 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 149 times.
|
155 | if( input.size() < 2 ) |
340 | { | ||
341 | 6 | ec = error::need_data; | |
342 | 9 | return false; | |
343 | } | ||
344 | |||
345 | 149 | std::size_t const crlf_len = 2; | |
346 | 149 | char tmp[crlf_len] = {}; | |
347 | |||
348 | 149 | buffers::buffer_copy( | |
349 | 149 | buffers::mutable_buffer( | |
350 | tmp, crlf_len), | ||
351 | 149 | input.data()); | |
352 | |||
353 | 149 | core::string_view str(tmp, crlf_len); | |
354 |
2/2✓ Branch 2 taken 3 times.
✓ Branch 3 taken 146 times.
|
149 | if( str != "\r\n" ) |
355 | { | ||
356 | 3 | ec = error::bad_payload; | |
357 | 3 | return false; | |
358 | } | ||
359 | |||
360 | 146 | input.consume(crlf_len); | |
361 | 146 | needs_chunk_close_ = false; | |
362 | 146 | continue; | |
363 | 146 | } | |
364 | |||
365 | 248 | parse_chunk_header(input, ec, chunk_remain_); | |
366 |
2/2✓ Branch 1 taken 98 times.
✓ Branch 2 taken 150 times.
|
248 | if( ec ) |
367 | { | ||
368 | 98 | system::error_code ec2; | |
369 | 98 | parse_last_chunk(input, ec2); | |
370 |
2/2✓ Branch 1 taken 25 times.
✓ Branch 2 taken 73 times.
|
98 | if( ec2 ) |
371 | { | ||
372 |
2/2✓ Branch 2 taken 13 times.
✓ Branch 3 taken 12 times.
|
25 | if( ec2 == condition::need_more_input ) |
373 | 13 | ec = ec2; | |
374 | 25 | return false; | |
375 | } | ||
376 | |||
377 | // complete | ||
378 | 73 | ec.clear(); | |
379 | 73 | return true; | |
380 | } | ||
381 | |||
382 | 150 | needs_chunk_close_ = true; | |
383 | } | ||
384 | |||
385 | // we've successfully parsed a chunk-size and have | ||
386 | // consume()d the entire buffer | ||
387 |
2/2✓ Branch 1 taken 59 times.
✓ Branch 2 taken 204 times.
|
263 | if( input.size() == 0 ) |
388 | { | ||
389 | 59 | ec = error::need_data; | |
390 | 59 | return false; | |
391 | } | ||
392 | |||
393 | // TODO: this is an open-ended design space with no | ||
394 | // clear answer at time of writing. | ||
395 | // revisit this later | ||
396 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 204 times.
|
204 | if( output.capacity() == 0 ) |
397 | ✗ | detail::throw_length_error(); | |
398 | |||
399 | 204 | auto n = (std::min)(chunk_remain_, input.size()); | |
400 | |||
401 | 204 | auto m = buffers::buffer_copy( | |
402 |
1/2✓ Branch 2 taken 204 times.
✗ Branch 3 not taken.
|
204 | output.prepare(output.capacity()), |
403 | 204 | buffers::prefix(input.data(), n)); | |
404 | |||
405 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
|
204 | BOOST_ASSERT(m <= chunk_remain_); |
406 | 204 | chunk_remain_ -= m; | |
407 | 204 | input.consume(m); | |
408 | 204 | output.commit(m); | |
409 | } | ||
410 | return false; | ||
411 | } | ||
412 | |||
413 | //----------------------------------------------- | ||
414 | |||
415 | class parser_service | ||
416 | : public service | ||
417 | { | ||
418 | public: | ||
419 | parser::config_base cfg; | ||
420 | std::size_t space_needed = 0; | ||
421 | std::size_t max_codec = 0; | ||
422 | zlib::detail::deflate_decoder_service const* | ||
423 | deflate_svc = nullptr; | ||
424 | |||
425 | parser_service( | ||
426 | context& ctx, | ||
427 | parser::config_base const& cfg_); | ||
428 | |||
429 | std::size_t | ||
430 | 9215 | max_overread() const noexcept | |
431 | { | ||
432 | return | ||
433 | 9215 | cfg.headers.max_size + | |
434 | 9215 | cfg.min_buffer; | |
435 | } | ||
436 | }; | ||
437 | |||
438 | 33 | parser_service:: | |
439 | parser_service( | ||
440 | context& ctx, | ||
441 | 33 | parser::config_base const& cfg_) | |
442 | 33 | : cfg(cfg_) | |
443 | { | ||
444 | /* | ||
445 | | fb | cb0 | cb1 | C | T | f | | ||
446 | |||
447 | fb flat_buffer headers.max_size | ||
448 | cb0 circular_buffer min_buffer | ||
449 | cb1 circular_buffer min_buffer | ||
450 | C codec max_codec | ||
451 | T body max_type_erase | ||
452 | f table max_table_space | ||
453 | |||
454 | */ | ||
455 | // validate | ||
456 | //if(cfg.min_prepare > cfg.max_prepare) | ||
457 | //detail::throw_invalid_argument(); | ||
458 | |||
459 |
1/2✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
|
33 | if( cfg.min_buffer < 1 || |
460 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
|
33 | cfg.min_buffer > cfg.body_limit) |
461 | ✗ | detail::throw_invalid_argument(); | |
462 | |||
463 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
|
33 | if(cfg.max_prepare < 1) |
464 | ✗ | detail::throw_invalid_argument(); | |
465 | |||
466 | // VFALCO TODO OVERFLOW CHECING | ||
467 | { | ||
468 | //fb_.size() - h_.size + | ||
469 | //svc_.cfg.min_buffer + | ||
470 | //svc_.cfg.min_buffer + | ||
471 | //svc_.max_codec; | ||
472 | } | ||
473 | |||
474 | // VFALCO OVERFLOW CHECKING ON THIS | ||
475 | 33 | space_needed += | |
476 |
1/2✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
|
33 | cfg.headers.valid_space_needed(); |
477 | |||
478 | // cb0_, cb1_ | ||
479 | // VFALCO OVERFLOW CHECKING ON THIS | ||
480 | 33 | space_needed += | |
481 | 33 | cfg.min_buffer + | |
482 | cfg.min_buffer; | ||
483 | |||
484 | // T | ||
485 | 33 | space_needed += cfg.max_type_erase; | |
486 | |||
487 | // max_codec | ||
488 | { | ||
489 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 32 times.
|
33 | if(cfg.apply_deflate_decoder) |
490 | { | ||
491 | 1 | deflate_svc = &ctx.get_service< | |
492 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | zlib::detail::deflate_decoder_service>(); |
493 | auto const n = | ||
494 | 1 | deflate_svc->space_needed(); | |
495 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if( max_codec < n) |
496 | ✗ | max_codec = n; | |
497 | } | ||
498 | } | ||
499 | 33 | space_needed += max_codec; | |
500 | |||
501 | // round up to alignof(detail::header::entry) | ||
502 | 33 | auto const al = alignof( | |
503 | detail::header::entry); | ||
504 | 33 | space_needed = al * (( | |
505 | 33 | space_needed + al - 1) / al); | |
506 | 33 | } | |
507 | |||
508 | void | ||
509 | 33 | install_parser_service( | |
510 | context& ctx, | ||
511 | parser::config_base const& cfg) | ||
512 | { | ||
513 | ctx.make_service< | ||
514 | 33 | parser_service>(cfg); | |
515 | 33 | } | |
516 | |||
517 | //------------------------------------------------ | ||
518 | // | ||
519 | // Special Members | ||
520 | // | ||
521 | //------------------------------------------------ | ||
522 | |||
523 | 1045 | parser:: | |
524 | parser( | ||
525 | context& ctx, | ||
526 | 1045 | detail::kind k) | |
527 | 1045 | : ctx_(ctx) | |
528 | 1045 | , svc_(ctx.get_service< | |
529 | 1045 | parser_service>()) | |
530 | 1045 | , h_(detail::empty{k}) | |
531 | 1045 | , eb_(nullptr) | |
532 | 2090 | , st_(state::reset) | |
533 | { | ||
534 | 1045 | auto const n = | |
535 | 1045 | svc_.space_needed; | |
536 |
1/2✓ Branch 1 taken 1045 times.
✗ Branch 2 not taken.
|
1045 | ws_.allocate(n); |
537 | 1045 | h_.cap = n; | |
538 | 1045 | } | |
539 | |||
540 | //------------------------------------------------ | ||
541 | |||
542 | 1045 | parser:: | |
543 | ~parser() | ||
544 | { | ||
545 | 1045 | } | |
546 | |||
547 | //------------------------------------------------ | ||
548 | // | ||
549 | // Modifiers | ||
550 | // | ||
551 | //------------------------------------------------ | ||
552 | |||
553 | // prepare for a new stream | ||
554 | void | ||
555 | 1600 | parser:: | |
556 | reset() noexcept | ||
557 | { | ||
558 | 1600 | ws_.clear(); | |
559 | 1600 | eb_ = nullptr; | |
560 | 1600 | st_ = state::start; | |
561 | 1600 | got_eof_ = false; | |
562 | 1600 | } | |
563 | |||
564 | void | ||
565 | 1830 | parser:: | |
566 | start_impl( | ||
567 | bool head_response) | ||
568 | { | ||
569 | 1830 | std::size_t leftover = 0; | |
570 |
5/5✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1585 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 240 times.
|
1830 | switch(st_) |
571 | { | ||
572 | 1 | default: | |
573 | case state::reset: | ||
574 | // reset must be called first | ||
575 | 1 | detail::throw_logic_error(); | |
576 | |||
577 | 1585 | case state::start: | |
578 | // reset required on eof | ||
579 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1585 times.
|
1585 | if(got_eof_) |
580 | ✗ | detail::throw_logic_error(); | |
581 | 1585 | break; | |
582 | |||
583 | 3 | case state::header: | |
584 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
|
3 | if(fb_.size() == 0) |
585 | { | ||
586 | // start() called twice | ||
587 | 2 | detail::throw_logic_error(); | |
588 | } | ||
589 | BOOST_FALLTHROUGH; | ||
590 | |||
591 | case state::body: | ||
592 | case state::set_body: | ||
593 | // current message is incomplete | ||
594 | 2 | detail::throw_logic_error(); | |
595 | |||
596 | 240 | case state::complete: | |
597 | { | ||
598 | // remove partial body. | ||
599 |
1/2✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
|
240 | if(body_buf_ == &cb0_) |
600 | 240 | cb0_.consume(static_cast<std::size_t>(body_avail_)); | |
601 | |||
602 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 240 times.
|
240 | if(cb0_.size() > 0) |
603 | { | ||
604 | // headers with no body | ||
605 | ✗ | BOOST_ASSERT(h_.size > 0); | |
606 | ✗ | fb_.consume(h_.size); | |
607 | ✗ | leftover = fb_.size(); | |
608 | // move unused octets to front | ||
609 | ✗ | buffers::buffer_copy( | |
610 | ✗ | buffers::mutable_buffer( | |
611 | ✗ | ws_.data(), | |
612 | leftover), | ||
613 | ✗ | fb_.data()); | |
614 | } | ||
615 | else | ||
616 | { | ||
617 | // leftover data after body | ||
618 | } | ||
619 | 240 | break; | |
620 | } | ||
621 | } | ||
622 | |||
623 | 1825 | ws_.clear(); | |
624 | |||
625 | 3650 | fb_ = { | |
626 | 1825 | ws_.data(), | |
627 | 1825 | svc_.cfg.headers.max_size + | |
628 | 1825 | svc_.cfg.min_buffer, | |
629 | leftover }; | ||
630 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 1825 times.
|
1825 | BOOST_ASSERT(fb_.capacity() == |
631 | svc_.max_overread()); | ||
632 | |||
633 | 3650 | h_ = detail::header( | |
634 | 1825 | detail::empty{h_.kind}); | |
635 | 1825 | h_.buf = reinterpret_cast< | |
636 | 1825 | char*>(ws_.data()); | |
637 | 1825 | h_.cbuf = h_.buf; | |
638 | 1825 | h_.cap = ws_.size(); | |
639 | |||
640 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1825 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1825 | BOOST_ASSERT(! head_response || |
641 | h_.kind == detail::kind::response); | ||
642 | 1825 | head_response_ = head_response; | |
643 | |||
644 | // begin with in_place mode | ||
645 | 1825 | how_ = how::in_place; | |
646 | 1825 | st_ = state::header; | |
647 | 1825 | nprepare_ = 0; | |
648 | 1825 | chunk_remain_ = 0; | |
649 | 1825 | needs_chunk_close_ = false; | |
650 | 1825 | } | |
651 | |||
652 | auto | ||
653 | 5801 | parser:: | |
654 | prepare() -> | ||
655 | mutable_buffers_type | ||
656 | { | ||
657 | 5801 | nprepare_ = 0; | |
658 | |||
659 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 5589 times.
✓ Branch 3 taken 180 times.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 3 times.
|
5801 | switch(st_) |
660 | { | ||
661 | 1 | default: | |
662 | case state::reset: | ||
663 | // reset must be called first | ||
664 | 1 | detail::throw_logic_error(); | |
665 | |||
666 | 1 | case state::start: | |
667 | // start must be called first | ||
668 | 1 | detail::throw_logic_error(); | |
669 | |||
670 | 5589 | case state::header: | |
671 | { | ||
672 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5589 times.
|
5589 | BOOST_ASSERT(h_.size < |
673 | svc_.cfg.headers.max_size); | ||
674 | 5589 | auto n = fb_.capacity() - fb_.size(); | |
675 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5589 times.
|
5589 | BOOST_ASSERT(n <= svc_.max_overread()); |
676 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 5560 times.
|
5589 | if( n > svc_.cfg.max_prepare) |
677 | 29 | n = svc_.cfg.max_prepare; | |
678 | 5589 | mbp_[0] = fb_.prepare(n); | |
679 | 5589 | nprepare_ = n; | |
680 | 5589 | return mutable_buffers_type( | |
681 | 11178 | &mbp_[0], 1); | |
682 | } | ||
683 | |||
684 | 180 | case state::body: | |
685 | { | ||
686 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
|
180 | if(got_eof_) |
687 | ✗ | return mutable_buffers_type{}; | |
688 | |||
689 | 180 | do_body: | |
690 |
2/2✓ Branch 1 taken 149 times.
✓ Branch 2 taken 55 times.
|
204 | if(! is_plain()) |
691 | { | ||
692 | // buffered payload | ||
693 | 149 | auto n = cb0_.capacity() - | |
694 | 149 | cb0_.size(); | |
695 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 149 times.
|
149 | if( n > svc_.cfg.max_prepare) |
696 | ✗ | n = svc_.cfg.max_prepare; | |
697 | 149 | mbp_ = cb0_.prepare(n); | |
698 | 149 | nprepare_ = n; | |
699 | 149 | return mutable_buffers_type(mbp_); | |
700 | } | ||
701 | |||
702 | // plain payload | ||
703 | |||
704 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 26 times.
|
55 | if(how_ == how::in_place) |
705 | { | ||
706 | auto n = | ||
707 | 29 | body_buf_->capacity() - | |
708 | 29 | body_buf_->size(); | |
709 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 28 times.
|
29 | if( n > svc_.cfg.max_prepare) |
710 | 1 | n = svc_.cfg.max_prepare; | |
711 | 29 | mbp_ = body_buf_->prepare(n); | |
712 | 29 | nprepare_ = n; | |
713 | 29 | return mutable_buffers_type(mbp_); | |
714 | } | ||
715 | |||
716 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | if(how_ == how::elastic) |
717 | { | ||
718 | // Overreads are not allowed, or | ||
719 | // else the caller will see extra | ||
720 | // unrelated data. | ||
721 | |||
722 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 17 times.
|
26 | if(h_.md.payload == payload::size) |
723 | { | ||
724 | // set_body moves avail to dyn | ||
725 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
|
9 | BOOST_ASSERT(body_buf_->size() == 0); |
726 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | BOOST_ASSERT(body_avail_ == 0); |
727 | 9 | auto n = static_cast<std::size_t>(payload_remain_); | |
728 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
|
9 | if( n > svc_.cfg.max_prepare) |
729 | 1 | n = svc_.cfg.max_prepare; | |
730 | 9 | nprepare_ = n; | |
731 | 9 | return eb_->prepare(n); | |
732 | } | ||
733 | |||
734 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | BOOST_ASSERT( |
735 | h_.md.payload == payload::to_eof); | ||
736 | 17 | std::size_t n = 0; | |
737 |
1/2✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
|
17 | if(! got_eof_) |
738 | { | ||
739 | // calculate n heuristically | ||
740 | 17 | n = svc_.cfg.min_buffer; | |
741 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
|
17 | if( n > svc_.cfg.max_prepare) |
742 | 1 | n = svc_.cfg.max_prepare; | |
743 | { | ||
744 | // apply max_size() | ||
745 | auto avail = | ||
746 | 17 | eb_->max_size() - | |
747 | 17 | eb_->size(); | |
748 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 9 times.
|
17 | if( n > avail) |
749 | 8 | n = avail; | |
750 | } | ||
751 | // fill capacity() first, | ||
752 | // to avoid an allocation | ||
753 | { | ||
754 | auto avail = | ||
755 | 17 | eb_->capacity() - | |
756 | 17 | eb_->size(); | |
757 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
17 | if( n > avail && |
758 | avail != 0) | ||
759 | 1 | n = avail; | |
760 | } | ||
761 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 15 times.
|
17 | if(n == 0) |
762 | { | ||
763 | // dynamic buffer is full | ||
764 | // attempt a 1 byte read so | ||
765 | // we can detect overflow | ||
766 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | BOOST_ASSERT( |
767 | body_buf_->size() == 0); | ||
768 | // handled in init_dynamic | ||
769 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | BOOST_ASSERT( |
770 | body_avail_ == 0); | ||
771 | 2 | mbp_ = body_buf_->prepare(1); | |
772 | 2 | nprepare_ = 1; | |
773 | return | ||
774 | 2 | mutable_buffers_type(mbp_); | |
775 | } | ||
776 | } | ||
777 | 15 | nprepare_ = n; | |
778 | 15 | return eb_->prepare(n); | |
779 | } | ||
780 | |||
781 | // VFALCO TODO | ||
782 | ✗ | if(how_ == how::pull) | |
783 | ✗ | detail::throw_logic_error(); | |
784 | |||
785 | // VFALCO TODO | ||
786 | ✗ | detail::throw_logic_error(); | |
787 | } | ||
788 | |||
789 | 27 | case state::set_body: | |
790 | { | ||
791 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | if(how_ == how::elastic) |
792 | { | ||
793 | // attempt to transfer in-place | ||
794 | // body into the dynamic buffer. | ||
795 | 27 | system::error_code ec; | |
796 |
1/2✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
|
27 | init_dynamic(ec); |
797 |
2/2✓ Branch 1 taken 26 times.
✓ Branch 2 taken 1 times.
|
27 | if(! ec.failed()) |
798 | { | ||
799 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2 times.
|
26 | if(st_ == state::body) |
800 | 24 | goto do_body; | |
801 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | BOOST_ASSERT( |
802 | st_ == state::complete); | ||
803 | 2 | return mutable_buffers_type{}; | |
804 | } | ||
805 | |||
806 | // not enough room, so we | ||
807 | // return this error from parse() | ||
808 | return | ||
809 | 1 | mutable_buffers_type{}; | |
810 | } | ||
811 | |||
812 | ✗ | if(how_ == how::sink) | |
813 | { | ||
814 | // this is a no-op, to get the | ||
815 | // caller to call parse next. | ||
816 | ✗ | return mutable_buffers_type{}; | |
817 | } | ||
818 | |||
819 | // VFALCO TODO | ||
820 | ✗ | detail::throw_logic_error(); | |
821 | } | ||
822 | |||
823 | 3 | case state::complete: | |
824 | // intended no-op | ||
825 | 3 | return mutable_buffers_type{}; | |
826 | } | ||
827 | } | ||
828 | |||
829 | void | ||
830 | 5792 | parser:: | |
831 | commit( | ||
832 | std::size_t n) | ||
833 | { | ||
834 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 5589 times.
✓ Branch 3 taken 195 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 4 times.
|
5792 | switch(st_) |
835 | { | ||
836 | 1 | default: | |
837 | case state::reset: | ||
838 | { | ||
839 | // reset must be called first | ||
840 | 1 | detail::throw_logic_error(); | |
841 | } | ||
842 | |||
843 | 1 | case state::start: | |
844 | { | ||
845 | // forgot to call start() | ||
846 | 1 | detail::throw_logic_error(); | |
847 | } | ||
848 | |||
849 | 5589 | case state::header: | |
850 | { | ||
851 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5588 times.
|
5589 | if(n > nprepare_) |
852 | { | ||
853 | // n can't be greater than size of | ||
854 | // the buffers returned by prepare() | ||
855 | 1 | detail::throw_invalid_argument(); | |
856 | } | ||
857 | |||
858 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5587 times.
|
5588 | if(got_eof_) |
859 | { | ||
860 | // can't commit after EOF | ||
861 | 1 | detail::throw_logic_error(); | |
862 | } | ||
863 | |||
864 | 5587 | nprepare_ = 0; // invalidate | |
865 | 5587 | fb_.commit(n); | |
866 | 5587 | break; | |
867 | } | ||
868 | |||
869 | 195 | case state::body: | |
870 | { | ||
871 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 194 times.
|
195 | if(n > nprepare_) |
872 | { | ||
873 | // n can't be greater than size of | ||
874 | // the buffers returned by prepare() | ||
875 | 1 | detail::throw_invalid_argument(); | |
876 | } | ||
877 | |||
878 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 194 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
194 | BOOST_ASSERT(! got_eof_ || n == 0); |
879 | |||
880 |
2/2✓ Branch 1 taken 149 times.
✓ Branch 2 taken 45 times.
|
194 | if(! is_plain()) |
881 | { | ||
882 | // buffered payload | ||
883 | 149 | cb0_.commit(n); | |
884 | 149 | break; | |
885 | } | ||
886 | |||
887 | // plain payload | ||
888 | |||
889 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 19 times.
|
45 | if(how_ == how::in_place) |
890 | { | ||
891 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | BOOST_ASSERT(body_buf_ == &cb0_); |
892 | 26 | cb0_.commit(n); | |
893 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 14 times.
|
26 | if(h_.md.payload == payload::size) |
894 | { | ||
895 | 12 | if(cb0_.size() < | |
896 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
|
12 | h_.md.payload_size) |
897 | { | ||
898 | 4 | body_avail_ += n; | |
899 | 4 | payload_remain_ -= n; | |
900 | 4 | break; | |
901 | } | ||
902 | 8 | body_avail_ = h_.md.payload_size; | |
903 | 8 | payload_remain_ = 0; | |
904 | 8 | st_ = state::complete; | |
905 | 8 | break; | |
906 | } | ||
907 | |||
908 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | BOOST_ASSERT( |
909 | h_.md.payload == payload::to_eof); | ||
910 | 14 | body_avail_ += n; | |
911 | 14 | break; | |
912 | } | ||
913 | |||
914 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | if(how_ == how::elastic) |
915 | { | ||
916 |
2/2✓ Branch 2 taken 18 times.
✓ Branch 3 taken 1 times.
|
19 | if(eb_->size() < eb_->max_size()) |
917 | { | ||
918 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | BOOST_ASSERT(body_avail_ == 0); |
919 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
|
18 | BOOST_ASSERT( |
920 | body_buf_->size() == 0); | ||
921 | 18 | eb_->commit(n); | |
922 | } | ||
923 | else | ||
924 | { | ||
925 | // If we get here then either | ||
926 | // n==0 as a no-op, or n==1 for | ||
927 | // an intended one byte read. | ||
928 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | BOOST_ASSERT(n <= 1); |
929 | 1 | body_buf_->commit(n); | |
930 | 1 | body_avail_ += n; | |
931 | } | ||
932 | 19 | body_total_ += n; | |
933 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 13 times.
|
19 | if(h_.md.payload == payload::size) |
934 | { | ||
935 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | BOOST_ASSERT( |
936 | n <= payload_remain_); | ||
937 | 6 | payload_remain_ -= n; | |
938 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if(payload_remain_ == 0) |
939 | 6 | st_ = state::complete; | |
940 | } | ||
941 | 19 | break; | |
942 | } | ||
943 | |||
944 | ✗ | if(how_ == how::sink) | |
945 | { | ||
946 | ✗ | cb0_.commit(n); | |
947 | ✗ | break; | |
948 | } | ||
949 | |||
950 | ✗ | if(how_ == how::pull) | |
951 | { | ||
952 | // VFALCO TODO | ||
953 | ✗ | detail::throw_logic_error(); | |
954 | } | ||
955 | ✗ | break; | |
956 | } | ||
957 | |||
958 | 2 | case state::set_body: | |
959 | { | ||
960 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if(n > nprepare_) |
961 | { | ||
962 | // n can't be greater than size of | ||
963 | // the buffers returned by prepare() | ||
964 | 1 | detail::throw_invalid_argument(); | |
965 | } | ||
966 | |||
967 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | BOOST_ASSERT(is_plain()); |
968 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | BOOST_ASSERT(n == 0); |
969 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if( how_ == how::elastic || |
970 | ✗ | how_ == how::sink) | |
971 | { | ||
972 | // intended no-op | ||
973 | break; | ||
974 | } | ||
975 | |||
976 | // VFALCO TODO | ||
977 | ✗ | detail::throw_logic_error(); | |
978 | } | ||
979 | |||
980 | 4 | case state::complete: | |
981 | { | ||
982 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | BOOST_ASSERT(nprepare_ == 0); |
983 | |||
984 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | if(n > 0) |
985 | { | ||
986 | // n can't be greater than size of | ||
987 | // the buffers returned by prepare() | ||
988 | 1 | detail::throw_invalid_argument(); | |
989 | } | ||
990 | |||
991 | // intended no-op | ||
992 | 3 | break; | |
993 | } | ||
994 | } | ||
995 | 5785 | } | |
996 | |||
997 | void | ||
998 | 363 | parser:: | |
999 | commit_eof() | ||
1000 | { | ||
1001 | 363 | nprepare_ = 0; // invalidate | |
1002 | |||
1003 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 127 times.
✓ Branch 4 taken 212 times.
✓ Branch 5 taken 1 times.
|
363 | switch(st_) |
1004 | { | ||
1005 | 1 | default: | |
1006 | case state::reset: | ||
1007 | // reset must be called first | ||
1008 | 1 | detail::throw_logic_error(); | |
1009 | |||
1010 | 1 | case state::start: | |
1011 | // forgot to call prepare() | ||
1012 | 1 | detail::throw_logic_error(); | |
1013 | |||
1014 | 21 | case state::header: | |
1015 | 21 | got_eof_ = true; | |
1016 | 21 | break; | |
1017 | |||
1018 | 127 | case state::body: | |
1019 | 127 | got_eof_ = true; | |
1020 | 127 | break; | |
1021 | |||
1022 | 212 | case state::set_body: | |
1023 | 212 | got_eof_ = true; | |
1024 | 212 | break; | |
1025 | |||
1026 | 1 | case state::complete: | |
1027 | // can't commit eof when complete | ||
1028 | 1 | detail::throw_logic_error(); | |
1029 | } | ||
1030 | 360 | } | |
1031 | |||
1032 | //----------------------------------------------- | ||
1033 | |||
1034 | // process input data then | ||
1035 | // eof if input data runs out. | ||
1036 | void | ||
1037 | 6700 | parser:: | |
1038 | parse( | ||
1039 | system::error_code& ec) | ||
1040 | { | ||
1041 | 6700 | ec = {}; | |
1042 |
6/6✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 5589 times.
✓ Branch 3 taken 306 times.
✓ Branch 4 taken 211 times.
✓ Branch 5 taken 592 times.
|
6700 | switch(st_) |
1043 | { | ||
1044 | 1 | default: | |
1045 | case state::reset: | ||
1046 | // reset must be called first | ||
1047 | 1 | detail::throw_logic_error(); | |
1048 | |||
1049 | 1 | case state::start: | |
1050 | // start must be called first | ||
1051 | 1 | detail::throw_logic_error(); | |
1052 | |||
1053 | 5589 | case state::header: | |
1054 | { | ||
1055 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5589 times.
|
5589 | BOOST_ASSERT(h_.buf == static_cast< |
1056 | void const*>(ws_.data())); | ||
1057 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5589 times.
|
5589 | BOOST_ASSERT(h_.cbuf == static_cast< |
1058 | void const*>(ws_.data())); | ||
1059 | |||
1060 | 5589 | h_.parse(fb_.size(), svc_.cfg.headers, ec); | |
1061 | |||
1062 |
2/2✓ Branch 2 taken 3792 times.
✓ Branch 3 taken 1797 times.
|
5589 | if(ec == condition::need_more_input) |
1063 | { | ||
1064 |
2/2✓ Branch 0 taken 3774 times.
✓ Branch 1 taken 18 times.
|
3792 | if(! got_eof_) |
1065 | { | ||
1066 | // headers incomplete | ||
1067 | 3774 | return; | |
1068 | } | ||
1069 | |||
1070 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 10 times.
|
18 | if(fb_.size() == 0) |
1071 | { | ||
1072 | // stream closed cleanly | ||
1073 | 8 | st_ = state::complete; | |
1074 | 16 | ec = BOOST_HTTP_PROTO_ERR( | |
1075 | error::end_of_stream); | ||
1076 | 8 | return; | |
1077 | } | ||
1078 | |||
1079 | // stream closed with a | ||
1080 | // partial message received | ||
1081 | 10 | st_ = state::reset; | |
1082 | 20 | ec = BOOST_HTTP_PROTO_ERR( | |
1083 | error::incomplete); | ||
1084 | 10 | return; | |
1085 | } | ||
1086 |
2/2✓ Branch 1 taken 259 times.
✓ Branch 2 taken 1538 times.
|
1797 | if(ec.failed()) |
1087 | { | ||
1088 | // other error, | ||
1089 | // | ||
1090 | // VFALCO map this to a bad | ||
1091 | // request or bad response error? | ||
1092 | // | ||
1093 | 259 | st_ = state::reset; // unrecoverable | |
1094 | 259 | return; | |
1095 | } | ||
1096 | |||
1097 | // headers are complete | ||
1098 | 1538 | on_headers(ec); | |
1099 |
2/2✓ Branch 1 taken 120 times.
✓ Branch 2 taken 1418 times.
|
1538 | if(ec.failed()) |
1100 | 120 | return; | |
1101 |
2/2✓ Branch 0 taken 844 times.
✓ Branch 1 taken 574 times.
|
1418 | if(st_ == state::complete) |
1102 | 844 | break; | |
1103 | |||
1104 | BOOST_FALLTHROUGH; | ||
1105 | } | ||
1106 | |||
1107 | case state::body: | ||
1108 | { | ||
1109 | 574 | do_body: | |
1110 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 982 times.
|
982 | BOOST_ASSERT(st_ == state::body); |
1111 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 982 times.
|
982 | BOOST_ASSERT( |
1112 | h_.md.payload != payload::none); | ||
1113 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 982 times.
|
982 | BOOST_ASSERT( |
1114 | h_.md.payload != payload::error); | ||
1115 | |||
1116 |
2/2✓ Branch 0 taken 238 times.
✓ Branch 1 taken 744 times.
|
982 | if( h_.md.payload == payload::chunked ) |
1117 | { | ||
1118 | 238 | auto completed = false; | |
1119 | 238 | auto& input = cb0_; | |
1120 | |||
1121 |
1/2✓ Branch 0 taken 238 times.
✗ Branch 1 not taken.
|
238 | if( how_ == how::in_place ) |
1122 | { | ||
1123 | completed = | ||
1124 | 238 | parse_chunked( | |
1125 | 238 | input, cb1_, ec, chunk_remain_, | |
1126 | 238 | needs_chunk_close_); | |
1127 | } | ||
1128 | else | ||
1129 | ✗ | detail::throw_logic_error(); | |
1130 | |||
1131 |
2/2✓ Branch 0 taken 73 times.
✓ Branch 1 taken 165 times.
|
238 | if( completed ) |
1132 | 73 | st_ = state::complete; | |
1133 | |||
1134 | 238 | return; | |
1135 | } | ||
1136 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 744 times.
|
744 | else if( filt_ ) |
1137 | { | ||
1138 | // VFALCO TODO apply filter | ||
1139 | ✗ | detail::throw_logic_error(); | |
1140 | } | ||
1141 | |||
1142 |
2/2✓ Branch 0 taken 618 times.
✓ Branch 1 taken 126 times.
|
744 | if(how_ == how::in_place) |
1143 | { | ||
1144 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 618 times.
|
618 | BOOST_ASSERT(body_avail_ == |
1145 | body_buf_->size()); | ||
1146 |
2/2✓ Branch 0 taken 255 times.
✓ Branch 1 taken 363 times.
|
618 | if(h_.md.payload == payload::size) |
1147 | { | ||
1148 | 255 | if(body_avail_ < | |
1149 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 225 times.
|
255 | h_.md.payload_size) |
1150 | { | ||
1151 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 29 times.
|
30 | if(got_eof_) |
1152 | { | ||
1153 | // incomplete | ||
1154 | 2 | ec = BOOST_HTTP_PROTO_ERR( | |
1155 | error::incomplete); | ||
1156 | 1 | return; | |
1157 | } | ||
1158 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 28 times.
|
29 | if(body_buf_->capacity() == 0) |
1159 | { | ||
1160 | // in_place buffer limit | ||
1161 | 2 | ec = BOOST_HTTP_PROTO_ERR( | |
1162 | error::in_place_overflow); | ||
1163 | 1 | return; | |
1164 | } | ||
1165 | 56 | ec = BOOST_HTTP_PROTO_ERR( | |
1166 | error::need_data); | ||
1167 | 28 | return; | |
1168 | } | ||
1169 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 225 times.
|
225 | BOOST_ASSERT(body_avail_ == |
1170 | h_.md.payload_size); | ||
1171 | 225 | st_ = state::complete; | |
1172 | 225 | break; | |
1173 | } | ||
1174 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 362 times.
|
363 | if(body_avail_ > svc_.cfg.body_limit) |
1175 | { | ||
1176 | 2 | ec = BOOST_HTTP_PROTO_ERR( | |
1177 | error::body_too_large); | ||
1178 | 1 | st_ = state::reset; // unrecoverable | |
1179 | 1 | return; | |
1180 | } | ||
1181 |
1/2✓ Branch 0 taken 362 times.
✗ Branch 1 not taken.
|
362 | if( h_.md.payload == payload::chunked || |
1182 |
2/2✓ Branch 0 taken 248 times.
✓ Branch 1 taken 114 times.
|
362 | ! got_eof_) |
1183 | { | ||
1184 | 496 | ec = BOOST_HTTP_PROTO_ERR( | |
1185 | error::need_data); | ||
1186 | 248 | return; | |
1187 | } | ||
1188 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
|
114 | BOOST_ASSERT(got_eof_); |
1189 | 114 | st_ = state::complete; | |
1190 | 114 | break; | |
1191 | } | ||
1192 | |||
1193 |
1/2✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
|
126 | if(how_ == how::elastic) |
1194 | { | ||
1195 | // state already updated in commit | ||
1196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
|
126 | if(h_.md.payload == payload::size) |
1197 | { | ||
1198 | ✗ | BOOST_ASSERT(body_total_ < | |
1199 | h_.md.payload_size); | ||
1200 | ✗ | BOOST_ASSERT(payload_remain_ > 0); | |
1201 | ✗ | if(body_avail_ != 0) | |
1202 | { | ||
1203 | ✗ | BOOST_ASSERT( | |
1204 | eb_->max_size() - | ||
1205 | eb_->size() < | ||
1206 | payload_remain_); | ||
1207 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
1208 | error::buffer_overflow); | ||
1209 | ✗ | st_ = state::reset; // unrecoverable | |
1210 | ✗ | return; | |
1211 | } | ||
1212 | ✗ | if(got_eof_) | |
1213 | { | ||
1214 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
1215 | error::incomplete); | ||
1216 | ✗ | st_ = state::reset; // unrecoverable | |
1217 | ✗ | return; | |
1218 | } | ||
1219 | ✗ | return; | |
1220 | } | ||
1221 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
|
126 | BOOST_ASSERT( |
1222 | h_.md.payload == payload::to_eof); | ||
1223 |
3/4✓ Branch 2 taken 46 times.
✓ Branch 3 taken 80 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 126 times.
|
172 | if( eb_->size() == eb_->max_size() && |
1224 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
|
46 | body_avail_ > 0) |
1225 | { | ||
1226 | // got here from the 1-byte read | ||
1227 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
1228 | error::buffer_overflow); | ||
1229 | ✗ | st_ = state::reset; // unrecoverable | |
1230 | ✗ | return; | |
1231 | } | ||
1232 |
2/2✓ Branch 0 taken 113 times.
✓ Branch 1 taken 13 times.
|
126 | if(got_eof_) |
1233 | { | ||
1234 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
|
113 | BOOST_ASSERT(body_avail_ == 0); |
1235 | 113 | st_ = state::complete; | |
1236 | 113 | break; | |
1237 | } | ||
1238 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | BOOST_ASSERT(body_avail_ == 0); |
1239 | 13 | break; | |
1240 | } | ||
1241 | |||
1242 | // VFALCO TODO | ||
1243 | ✗ | detail::throw_logic_error(); | |
1244 | } | ||
1245 | |||
1246 | 211 | case state::set_body: | |
1247 | { | ||
1248 | // transfer in_place data into set body | ||
1249 | |||
1250 |
1/2✓ Branch 0 taken 211 times.
✗ Branch 1 not taken.
|
211 | if(how_ == how::elastic) |
1251 | { | ||
1252 | 211 | init_dynamic(ec); | |
1253 |
1/2✓ Branch 1 taken 211 times.
✗ Branch 2 not taken.
|
211 | if(! ec.failed()) |
1254 | { | ||
1255 |
2/2✓ Branch 0 taken 102 times.
✓ Branch 1 taken 109 times.
|
211 | if(st_ == state::body) |
1256 | 102 | goto do_body; | |
1257 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
|
109 | BOOST_ASSERT( |
1258 | st_ == state::complete); | ||
1259 | 109 | break; | |
1260 | } | ||
1261 | ✗ | st_ = state::reset; // unrecoverable | |
1262 | ✗ | return; | |
1263 | } | ||
1264 | |||
1265 | ✗ | if(how_ == how::sink) | |
1266 | { | ||
1267 | ✗ | auto n = body_buf_->size(); | |
1268 | ✗ | if(h_.md.payload == payload::size) | |
1269 | { | ||
1270 | // sink_->size_hint(h_.md.payload_size, ec); | ||
1271 | |||
1272 | ✗ | if(n < h_.md.payload_size) | |
1273 | { | ||
1274 | ✗ | auto rv = sink_->write( | |
1275 | ✗ | body_buf_->data(), false); | |
1276 | ✗ | BOOST_ASSERT(rv.ec.failed() || | |
1277 | rv.bytes == body_buf_->size()); | ||
1278 | ✗ | BOOST_ASSERT( | |
1279 | rv.bytes >= body_avail_); | ||
1280 | ✗ | BOOST_ASSERT( | |
1281 | rv.bytes < payload_remain_); | ||
1282 | ✗ | body_buf_->consume(rv.bytes); | |
1283 | ✗ | body_avail_ -= rv.bytes; | |
1284 | ✗ | body_total_ += rv.bytes; | |
1285 | ✗ | payload_remain_ -= rv.bytes; | |
1286 | ✗ | if(rv.ec.failed()) | |
1287 | { | ||
1288 | ✗ | ec = rv.ec; | |
1289 | ✗ | st_ = state::reset; // unrecoverable | |
1290 | ✗ | return; | |
1291 | } | ||
1292 | ✗ | st_ = state::body; | |
1293 | ✗ | goto do_body; | |
1294 | } | ||
1295 | |||
1296 | ✗ | n = static_cast<std::size_t>(h_.md.payload_size); | |
1297 | } | ||
1298 | // complete | ||
1299 | ✗ | BOOST_ASSERT(body_buf_ == &cb0_); | |
1300 | ✗ | auto rv = sink_->write( | |
1301 | ✗ | body_buf_->data(), true); | |
1302 | ✗ | BOOST_ASSERT(rv.ec.failed() || | |
1303 | rv.bytes == body_buf_->size()); | ||
1304 | ✗ | body_buf_->consume(rv.bytes); | |
1305 | ✗ | if(rv.ec.failed()) | |
1306 | { | ||
1307 | ✗ | ec = rv.ec; | |
1308 | ✗ | st_ = state::reset; // unrecoverable | |
1309 | ✗ | return; | |
1310 | } | ||
1311 | ✗ | st_ = state::complete; | |
1312 | ✗ | return; | |
1313 | } | ||
1314 | |||
1315 | // VFALCO TODO | ||
1316 | ✗ | detail::throw_logic_error(); | |
1317 | } | ||
1318 | |||
1319 | 592 | case state::complete: | |
1320 | { | ||
1321 | // This is a no-op except when set_body | ||
1322 | // was called and we have in-place data. | ||
1323 |
2/4✓ Branch 0 taken 296 times.
✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
592 | switch(how_) |
1324 | { | ||
1325 | 296 | default: | |
1326 | case how::in_place: | ||
1327 | 296 | break; | |
1328 | |||
1329 | 296 | case how::elastic: | |
1330 | { | ||
1331 |
1/2✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
|
296 | if(body_buf_->size() == 0) |
1332 | 296 | break; | |
1333 | ✗ | BOOST_ASSERT(eb_->size() == 0); | |
1334 | ✗ | auto n = buffers::buffer_copy( | |
1335 | ✗ | eb_->prepare( | |
1336 | ✗ | body_buf_->size()), | |
1337 | ✗ | body_buf_->data()); | |
1338 | ✗ | body_buf_->consume(n); | |
1339 | ✗ | break; | |
1340 | } | ||
1341 | |||
1342 | ✗ | case how::sink: | |
1343 | { | ||
1344 | ✗ | if(body_buf_->size() == 0) | |
1345 | ✗ | break; | |
1346 | ✗ | auto rv = sink_->write( | |
1347 | ✗ | body_buf_->data(), false); | |
1348 | ✗ | body_buf_->consume(rv.bytes); | |
1349 | ✗ | if(rv.ec.failed()) | |
1350 | { | ||
1351 | ✗ | ec = rv.ec; | |
1352 | ✗ | st_ = state::reset; // unrecoverable | |
1353 | ✗ | return; | |
1354 | } | ||
1355 | ✗ | break; | |
1356 | } | ||
1357 | |||
1358 | ✗ | case how::pull: | |
1359 | // VFALCO TODO | ||
1360 | ✗ | detail::throw_logic_error(); | |
1361 | } | ||
1362 | } | ||
1363 | } | ||
1364 | } | ||
1365 | |||
1366 | //------------------------------------------------ | ||
1367 | |||
1368 | auto | ||
1369 | ✗ | parser:: | |
1370 | pull_some() -> | ||
1371 | const_buffers_type | ||
1372 | { | ||
1373 | ✗ | return {}; | |
1374 | } | ||
1375 | |||
1376 | core::string_view | ||
1377 | 1344 | parser:: | |
1378 | body() const noexcept | ||
1379 | { | ||
1380 |
2/2✓ Branch 0 taken 349 times.
✓ Branch 1 taken 995 times.
|
1344 | switch(st_) |
1381 | { | ||
1382 | 349 | default: | |
1383 | case state::reset: | ||
1384 | case state::start: | ||
1385 | case state::header: | ||
1386 | case state::body: | ||
1387 | case state::set_body: | ||
1388 | // not complete | ||
1389 | 349 | return {}; | |
1390 | |||
1391 | 995 | case state::complete: | |
1392 |
2/2✓ Branch 0 taken 346 times.
✓ Branch 1 taken 649 times.
|
995 | if(how_ != how::in_place) |
1393 | { | ||
1394 | // not in_place | ||
1395 | 346 | return {}; | |
1396 | } | ||
1397 | 649 | auto cbp = body_buf_->data(); | |
1398 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 649 times.
|
649 | BOOST_ASSERT(cbp[1].size() == 0); |
1399 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 649 times.
|
649 | BOOST_ASSERT(cbp[0].size() >= body_avail_); |
1400 | 1298 | return core::string_view( | |
1401 | static_cast<char const*>( | ||
1402 | 649 | cbp[0].data()), | |
1403 | 1298 | cbp[0].size()); | |
1404 | } | ||
1405 | } | ||
1406 | |||
1407 | core::string_view | ||
1408 | ✗ | parser:: | |
1409 | release_buffered_data() noexcept | ||
1410 | { | ||
1411 | ✗ | return {}; | |
1412 | } | ||
1413 | |||
1414 | //------------------------------------------------ | ||
1415 | // | ||
1416 | // Implementation | ||
1417 | // | ||
1418 | //------------------------------------------------ | ||
1419 | |||
1420 | auto | ||
1421 | 314 | parser:: | |
1422 | safe_get_header() const -> | ||
1423 | detail::header const* | ||
1424 | { | ||
1425 | // headers must be received | ||
1426 |
3/6✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 314 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 314 times.
|
628 | if( ! got_header() || |
1427 | 314 | fb_.size() == 0) // happens on eof | |
1428 | ✗ | detail::throw_logic_error(); | |
1429 | |||
1430 | 314 | return &h_; | |
1431 | } | ||
1432 | |||
1433 | bool | ||
1434 | 973 | parser:: | |
1435 | is_plain() const noexcept | ||
1436 | { | ||
1437 |
1/2✓ Branch 0 taken 973 times.
✗ Branch 1 not taken.
|
1946 | return ! filt_ && |
1438 |
2/2✓ Branch 0 taken 586 times.
✓ Branch 1 taken 387 times.
|
973 | h_.md.payload != |
1439 | 973 | payload::chunked; | |
1440 | } | ||
1441 | |||
1442 | // Called immediately after complete headers | ||
1443 | // are received. We leave fb_ as-is to indicate | ||
1444 | // whether any data was received before eof. | ||
1445 | // | ||
1446 | void | ||
1447 | 1538 | parser:: | |
1448 | on_headers( | ||
1449 | system::error_code& ec) | ||
1450 | { | ||
1451 | 1538 | auto const overread = fb_.size() - h_.size; | |
1452 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1538 times.
|
1538 | BOOST_ASSERT( |
1453 | overread <= svc_.max_overread()); | ||
1454 | |||
1455 | // metadata error | ||
1456 |
2/2✓ Branch 0 taken 120 times.
✓ Branch 1 taken 1418 times.
|
1538 | if(h_.md.payload == payload::error) |
1457 | { | ||
1458 | // VFALCO This needs looking at | ||
1459 | 240 | ec = BOOST_HTTP_PROTO_ERR( | |
1460 | error::bad_payload); | ||
1461 | 120 | st_ = state::reset; // unrecoverable | |
1462 | 120 | return; | |
1463 | } | ||
1464 | |||
1465 | // reserve headers + table | ||
1466 | 1418 | ws_.reserve_front(h_.size); | |
1467 | 1418 | ws_.reserve_back(h_.table_space()); | |
1468 | |||
1469 | // no payload | ||
1470 |
2/2✓ Branch 0 taken 574 times.
✓ Branch 1 taken 844 times.
|
1418 | if( h_.md.payload == payload::none || |
1471 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 574 times.
|
574 | head_response_) |
1472 | { | ||
1473 | // set cb0_ to overread | ||
1474 | 1688 | cb0_ = { | |
1475 | 844 | ws_.data(), | |
1476 | 844 | fb_.capacity() - h_.size, | |
1477 | overread }; | ||
1478 | 844 | body_avail_ = 0; | |
1479 | 844 | body_total_ = 0; | |
1480 | 844 | body_buf_ = &cb0_; | |
1481 | 844 | st_ = state::complete; | |
1482 | 844 | return; | |
1483 | } | ||
1484 | |||
1485 | // calculate filter | ||
1486 | 574 | filt_ = nullptr; // VFALCO TODO | |
1487 | |||
1488 |
2/2✓ Branch 1 taken 485 times.
✓ Branch 2 taken 89 times.
|
574 | if(is_plain()) |
1489 | { | ||
1490 | // plain payload | ||
1491 |
2/2✓ Branch 0 taken 250 times.
✓ Branch 1 taken 235 times.
|
485 | if(h_.md.payload == payload::size) |
1492 | { | ||
1493 | 250 | if(h_.md.payload_size > | |
1494 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 250 times.
|
250 | svc_.cfg.body_limit) |
1495 | { | ||
1496 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
1497 | error::body_too_large); | ||
1498 | ✗ | st_ = state::reset; // unrecoverable | |
1499 | ✗ | return; | |
1500 | } | ||
1501 | |||
1502 | auto n0 = | ||
1503 | 250 | fb_.capacity() - h_.size + | |
1504 | 250 | svc_.cfg.min_buffer + | |
1505 | 250 | svc_.max_codec; | |
1506 | // limit the capacity of cb0_ so | ||
1507 | // that going over max_overread | ||
1508 | // is impossible. | ||
1509 |
6/6✓ Branch 0 taken 249 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 235 times.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 236 times.
|
499 | if( n0 > h_.md.payload_size && |
1510 | 249 | n0 - h_.md.payload_size >= | |
1511 | 249 | svc_.max_overread()) | |
1512 | 14 | n0 = static_cast<std::size_t>(h_.md.payload_size) + | |
1513 | 14 | svc_.max_overread(); | |
1514 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 250 times.
|
250 | BOOST_ASSERT(n0 <= ws_.size()); |
1515 | 250 | cb0_ = { ws_.data(), n0, overread }; | |
1516 | 250 | body_buf_ = &cb0_; | |
1517 | 250 | body_avail_ = cb0_.size(); | |
1518 |
2/2✓ Branch 0 taken 225 times.
✓ Branch 1 taken 25 times.
|
250 | if( body_avail_ >= h_.md.payload_size) |
1519 | 225 | body_avail_ = h_.md.payload_size; | |
1520 | 250 | body_total_ = body_avail_; | |
1521 | 250 | payload_remain_ = | |
1522 | 250 | h_.md.payload_size - body_total_; | |
1523 | 250 | st_ = state::body; | |
1524 | 250 | return; | |
1525 | } | ||
1526 | |||
1527 | // overread is not applicable | ||
1528 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 235 times.
|
235 | BOOST_ASSERT( |
1529 | h_.md.payload == payload::to_eof); | ||
1530 | auto const n0 = | ||
1531 | 235 | fb_.capacity() - h_.size + | |
1532 | 235 | svc_.cfg.min_buffer + | |
1533 | 235 | svc_.max_codec; | |
1534 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 235 times.
|
235 | BOOST_ASSERT(n0 <= ws_.size()); |
1535 | 235 | cb0_ = { ws_.data(), n0, overread }; | |
1536 | 235 | body_buf_ = &cb0_; | |
1537 | 235 | body_avail_ = cb0_.size(); | |
1538 | 235 | body_total_ = body_avail_; | |
1539 | 235 | st_ = state::body; | |
1540 | 235 | return; | |
1541 | } | ||
1542 | |||
1543 |
1/2✓ Branch 0 taken 89 times.
✗ Branch 1 not taken.
|
89 | if( h_.md.payload == payload::chunked ) |
1544 | { | ||
1545 | auto const n0 = | ||
1546 | 89 | fb_.capacity() - fb_.size(); | |
1547 | |||
1548 | 89 | cb0_ = { ws_.data(), n0 / 2, overread }; | |
1549 | 89 | cb1_ = { ws_.data() + n0 / 2, n0 - (n0 / 2), 0 }; | |
1550 | 89 | body_buf_ = &cb1_; | |
1551 | 89 | st_ = state::body; | |
1552 | 89 | return; | |
1553 | } | ||
1554 | |||
1555 | // buffered payload | ||
1556 | ✗ | auto const n0 = fb_.capacity() - h_.size; | |
1557 | ✗ | BOOST_ASSERT(n0 <= svc_.max_overread()); | |
1558 | ✗ | auto n1 = svc_.cfg.min_buffer; | |
1559 | ✗ | if(! filt_) | |
1560 | ✗ | n1 += svc_.max_codec; | |
1561 | ✗ | BOOST_ASSERT(n0 + n1 <= ws_.size()); | |
1562 | ✗ | cb0_ = { ws_.data(), n0, overread }; | |
1563 | ✗ | cb1_ = { ws_.data() + n0, n1 }; | |
1564 | ✗ | body_buf_ = &cb1_; | |
1565 | ✗ | body_avail_ = 0; | |
1566 | ✗ | body_total_ = 0; | |
1567 | ✗ | st_ = state::body; | |
1568 | } | ||
1569 | |||
1570 | // Called at the end of set_body | ||
1571 | void | ||
1572 | 299 | parser:: | |
1573 | on_set_body() | ||
1574 | { | ||
1575 | // This function is called after all | ||
1576 | // limit checking and calculation of | ||
1577 | // chunked or filter. | ||
1578 | |||
1579 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 299 times.
|
299 | BOOST_ASSERT(got_header()); |
1580 | |||
1581 | 299 | nprepare_ = 0; // invalidate | |
1582 | |||
1583 |
1/2✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
|
299 | if(how_ == how::elastic) |
1584 | { | ||
1585 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 241 times.
|
299 | if(h_.md.payload == payload::none) |
1586 | { | ||
1587 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
|
58 | BOOST_ASSERT(st_ == state::complete); |
1588 | 58 | return; | |
1589 | } | ||
1590 | |||
1591 | 241 | st_ = state::set_body; | |
1592 | 241 | return; | |
1593 | } | ||
1594 | |||
1595 | ✗ | if(how_ == how::sink) | |
1596 | { | ||
1597 | ✗ | if(h_.md.payload == payload::none) | |
1598 | { | ||
1599 | ✗ | BOOST_ASSERT(st_ == state::complete); | |
1600 | // force a trip through parse so | ||
1601 | // we can calculate any error. | ||
1602 | ✗ | st_ = state::set_body; | |
1603 | ✗ | return; | |
1604 | } | ||
1605 | |||
1606 | ✗ | st_ = state::set_body; | |
1607 | ✗ | return; | |
1608 | } | ||
1609 | |||
1610 | // VFALCO TODO | ||
1611 | ✗ | detail::throw_logic_error(); | |
1612 | } | ||
1613 | |||
1614 | void | ||
1615 | 238 | parser:: | |
1616 | init_dynamic( | ||
1617 | system::error_code& ec) | ||
1618 | { | ||
1619 | // attempt to transfer in-place | ||
1620 | // body into the dynamic buffer. | ||
1621 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 238 times.
|
238 | BOOST_ASSERT( |
1622 | body_avail_ == body_buf_->size()); | ||
1623 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 238 times.
|
238 | BOOST_ASSERT( |
1624 | body_total_ == body_avail_); | ||
1625 | auto const space_left = | ||
1626 | 238 | eb_->max_size() - eb_->size(); | |
1627 | |||
1628 |
2/2✓ Branch 0 taken 121 times.
✓ Branch 1 taken 117 times.
|
238 | if(h_.md.payload == payload::size) |
1629 | { | ||
1630 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 120 times.
|
121 | if(space_left < h_.md.payload_size) |
1631 | { | ||
1632 | 2 | ec = BOOST_HTTP_PROTO_ERR( | |
1633 | error::buffer_overflow); | ||
1634 | 1 | return; | |
1635 | } | ||
1636 | // reserve the full size | ||
1637 | 120 | eb_->prepare(static_cast<std::size_t>(h_.md.payload_size)); | |
1638 | // transfer in-place body | ||
1639 | 120 | auto n = static_cast<std::size_t>(body_avail_); | |
1640 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
|
120 | if( n > h_.md.payload_size) |
1641 | ✗ | n = static_cast<std::size_t>(h_.md.payload_size); | |
1642 |
1/2✓ Branch 2 taken 120 times.
✗ Branch 3 not taken.
|
120 | eb_->commit( |
1643 | buffers::buffer_copy( | ||
1644 |
1/2✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
|
120 | eb_->prepare(n), |
1645 | 120 | body_buf_->data())); | |
1646 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
|
120 | BOOST_ASSERT(body_avail_ == n); |
1647 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
|
120 | BOOST_ASSERT(body_total_ == n); |
1648 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
|
120 | BOOST_ASSERT(payload_remain_ == |
1649 | h_.md.payload_size - n); | ||
1650 | 120 | body_buf_->consume(n); | |
1651 | 120 | body_avail_ = 0; | |
1652 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 111 times.
|
120 | if(n < h_.md.payload_size) |
1653 | { | ||
1654 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
|
9 | BOOST_ASSERT( |
1655 | body_buf_->size() == 0); | ||
1656 | 9 | st_ = state::body; | |
1657 | 9 | return; | |
1658 | } | ||
1659 | // complete | ||
1660 | 111 | st_ = state::complete; | |
1661 | 111 | return; | |
1662 | } | ||
1663 | |||
1664 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
|
117 | BOOST_ASSERT(h_.md.payload == |
1665 | payload::to_eof); | ||
1666 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
|
117 | if(space_left < body_avail_) |
1667 | { | ||
1668 | ✗ | ec = BOOST_HTTP_PROTO_ERR( | |
1669 | error::buffer_overflow); | ||
1670 | ✗ | return; | |
1671 | } | ||
1672 |
1/2✓ Branch 2 taken 117 times.
✗ Branch 3 not taken.
|
117 | eb_->commit( |
1673 | buffers::buffer_copy( | ||
1674 |
1/2✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
|
117 | eb_->prepare(static_cast<std::size_t>(body_avail_)), |
1675 | 117 | body_buf_->data())); | |
1676 | 117 | body_buf_->consume(static_cast<std::size_t>(body_avail_)); | |
1677 | 117 | body_avail_ = 0; | |
1678 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
|
117 | BOOST_ASSERT( |
1679 | body_buf_->size() == 0); | ||
1680 | 117 | st_ = state::body; | |
1681 | } | ||
1682 | |||
1683 | } // http_proto | ||
1684 | } // boost | ||
1685 |