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