| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // | ||
| 2 | // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) | ||
| 3 | // Copyright (c) 2024 Christian Mazakas | ||
| 4 | // Copyright (c) 2024 Mohammad Nejati | ||
| 5 | // | ||
| 6 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
| 7 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
| 8 | // | ||
| 9 | // Official repository: https://github.com/cppalliance/http_proto | ||
| 10 | // | ||
| 11 | |||
| 12 | #include <boost/http_proto/detail/except.hpp> | ||
| 13 | #include <boost/http_proto/message_view_base.hpp> | ||
| 14 | #include <boost/http_proto/serializer.hpp> | ||
| 15 | #include <boost/http_proto/service/zlib_service.hpp> | ||
| 16 | |||
| 17 | #include "src/detail/filter.hpp" | ||
| 18 | |||
| 19 | #include <boost/buffers/copy.hpp> | ||
| 20 | #include <boost/buffers/prefix.hpp> | ||
| 21 | #include <boost/buffers/sans_prefix.hpp> | ||
| 22 | #include <boost/buffers/sans_suffix.hpp> | ||
| 23 | #include <boost/buffers/suffix.hpp> | ||
| 24 | #include <boost/buffers/size.hpp> | ||
| 25 | #include <boost/core/ignore_unused.hpp> | ||
| 26 | |||
| 27 | #include <stddef.h> | ||
| 28 | |||
| 29 | namespace boost { | ||
| 30 | namespace http_proto { | ||
| 31 | |||
| 32 | namespace { | ||
| 33 | |||
| 34 | class deflator_filter | ||
| 35 | : public http_proto::detail::filter | ||
| 36 | { | ||
| 37 | zlib::stream& deflator_; | ||
| 38 | |||
| 39 | public: | ||
| 40 | 73 | deflator_filter( | |
| 41 | context& ctx, | ||
| 42 | http_proto::detail::workspace& ws, | ||
| 43 | bool use_gzip) | ||
| 44 | 292 | : deflator_{ ctx.get_service<zlib::service>() | |
| 45 |
2/2✓ Branch 2 taken 37 times.
✓ Branch 3 taken 36 times.
|
73 | .make_deflator(ws, -1, use_gzip ? 31 : 15, 8) } |
| 46 | { | ||
| 47 | 73 | } | |
| 48 | |||
| 49 | virtual filter::results | ||
| 50 | 10525 | on_process( | |
| 51 | buffers::mutable_buffer out, | ||
| 52 | buffers::const_buffer in, | ||
| 53 | bool more) override | ||
| 54 | { | ||
| 55 | 10525 | auto flush = | |
| 56 |
2/2✓ Branch 0 taken 10445 times.
✓ Branch 1 taken 80 times.
|
10525 | more ? zlib::flush::none : zlib::flush::finish; |
| 57 | 10525 | filter::results results; | |
| 58 | |||
| 59 | for(;;) | ||
| 60 | { | ||
| 61 | 17509 | auto params = zlib::params{in.data(), in.size(), | |
| 62 | 17509 | out.data(), out.size() }; | |
| 63 | 17509 | auto ec = deflator_.write(params, flush); | |
| 64 | |||
| 65 | 17509 | results.in_bytes += in.size() - params.avail_in; | |
| 66 | 17509 | results.out_bytes += out.size() - params.avail_out; | |
| 67 | |||
| 68 |
3/4✓ Branch 1 taken 1 times.
✓ Branch 2 taken 17508 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
17510 | if( ec.failed() && |
| 69 |
2/2✓ Branch 2 taken 1 times.
✓ Branch 3 taken 17508 times.
|
17510 | ec != zlib::error::buf_err) |
| 70 | { | ||
| 71 | 1 | results.ec = ec; | |
| 72 | 10525 | return results; | |
| 73 | } | ||
| 74 | |||
| 75 |
2/2✓ Branch 2 taken 72 times.
✓ Branch 3 taken 17436 times.
|
17508 | if( ec == zlib::error::stream_end ) |
| 76 | { | ||
| 77 | 72 | results.finished = true; | |
| 78 | 72 | return results; | |
| 79 | } | ||
| 80 | |||
| 81 | 17436 | in = buffers::suffix(in, params.avail_in); | |
| 82 | 17436 | out = buffers::suffix(out, params.avail_out); | |
| 83 | |||
| 84 |
2/2✓ Branch 1 taken 3404 times.
✓ Branch 2 taken 14032 times.
|
17436 | if( out.size() == 0 ) |
| 85 | 3404 | return results; | |
| 86 | |||
| 87 |
1/2✓ Branch 1 taken 14032 times.
✗ Branch 2 not taken.
|
14032 | if( in.size() == 0 ) |
| 88 | { | ||
| 89 |
3/4✓ Branch 0 taken 6984 times.
✓ Branch 1 taken 7048 times.
✓ Branch 2 taken 6984 times.
✗ Branch 3 not taken.
|
14032 | if( results.out_bytes == 0 && |
| 90 | flush == zlib::flush::none ) | ||
| 91 | { | ||
| 92 | // TODO: Is flush::block the right choice? | ||
| 93 | // We might need a filter::flush() interface | ||
| 94 | // so that the caller can decide when to flush. | ||
| 95 | 6984 | flush = zlib::flush::block; | |
| 96 | 6984 | continue; | |
| 97 | } | ||
| 98 | 7048 | return results; | |
| 99 | } | ||
| 100 | 6984 | } | |
| 101 | } | ||
| 102 | }; | ||
| 103 | |||
| 104 | //------------------------------------------------ | ||
| 105 | |||
| 106 | constexpr | ||
| 107 | std::size_t | ||
| 108 | crlf_len = 2; | ||
| 109 | |||
| 110 | constexpr | ||
| 111 | std::size_t | ||
| 112 | chunk_header_len = 16 + crlf_len; | ||
| 113 | |||
| 114 | constexpr | ||
| 115 | std::size_t | ||
| 116 | final_chunk_len = 1 + crlf_len + crlf_len; | ||
| 117 | |||
| 118 | constexpr | ||
| 119 | std::size_t | ||
| 120 | chunked_overhead_ = | ||
| 121 | chunk_header_len + | ||
| 122 | crlf_len + | ||
| 123 | final_chunk_len; | ||
| 124 | |||
| 125 | template<class MutableBufferSequence> | ||
| 126 | void | ||
| 127 | 9038 | write_chunk_header( | |
| 128 | const MutableBufferSequence& mbs, | ||
| 129 | std::size_t size) noexcept | ||
| 130 | { | ||
| 131 | static constexpr char hexdig[] = | ||
| 132 | "0123456789ABCDEF"; | ||
| 133 | char buf[18]; | ||
| 134 | 9038 | auto p = buf + 16; | |
| 135 |
2/2✓ Branch 0 taken 72304 times.
✓ Branch 1 taken 4519 times.
|
153646 | for(std::size_t i = 16; i--;) |
| 136 | { | ||
| 137 | 144608 | *--p = hexdig[size & 0xf]; | |
| 138 | 144608 | size >>= 4; | |
| 139 | } | ||
| 140 | 9038 | buf[16] = '\r'; | |
| 141 | 9038 | buf[17] = '\n'; | |
| 142 | 9038 | auto n = buffers::copy( | |
| 143 | mbs, | ||
| 144 | 18076 | buffers::const_buffer( | |
| 145 | buf, sizeof(buf))); | ||
| 146 | ignore_unused(n); | ||
| 147 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4519 times.
|
9038 | BOOST_ASSERT(n == 18); |
| 148 | 9038 | } | |
| 149 | |||
| 150 | template<class MutableBufferSequence> | ||
| 151 | void | ||
| 152 | 9038 | write_crlf( | |
| 153 | const MutableBufferSequence& mbs) noexcept | ||
| 154 | { | ||
| 155 | 9038 | auto n = buffers::copy( | |
| 156 | mbs, | ||
| 157 | 18076 | buffers::const_buffer( | |
| 158 | "\r\n", 2)); | ||
| 159 | ignore_unused(n); | ||
| 160 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4519 times.
|
9038 | BOOST_ASSERT(n == 2); |
| 161 | 9038 | } | |
| 162 | |||
| 163 | template<class MutableBufferSequence> | ||
| 164 | void | ||
| 165 | 86 | write_final_chunk( | |
| 166 | const MutableBufferSequence& mbs) noexcept | ||
| 167 | { | ||
| 168 | 86 | auto n = buffers::copy( | |
| 169 | mbs, | ||
| 170 | 172 | buffers::const_buffer( | |
| 171 | "0\r\n\r\n", 5)); | ||
| 172 | ignore_unused(n); | ||
| 173 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 43 times.
|
86 | BOOST_ASSERT(n == 5); |
| 174 | 86 | } | |
| 175 | |||
| 176 | //------------------------------------------------ | ||
| 177 | |||
| 178 | class appender | ||
| 179 | { | ||
| 180 | buffers::circular_buffer& cb_; | ||
| 181 | buffers::mutable_buffer_pair mbp_; | ||
| 182 | std::size_t n_ = 0; | ||
| 183 | bool is_chunked_ = false; | ||
| 184 | bool more_input_ = true; | ||
| 185 | |||
| 186 | public: | ||
| 187 | 8975 | appender( | |
| 188 | buffers::circular_buffer& cb, | ||
| 189 | bool is_chunked) | ||
| 190 | 8975 | : cb_(cb) | |
| 191 | 8975 | , mbp_(cb.prepare(cb.capacity())) | |
| 192 | 8975 | , is_chunked_(is_chunked) | |
| 193 | { | ||
| 194 | 8975 | } | |
| 195 | |||
| 196 | bool | ||
| 197 | 13979 | is_full() const noexcept | |
| 198 | { | ||
| 199 | 13979 | auto remaining = cb_.capacity() - n_; | |
| 200 |
2/2✓ Branch 0 taken 7024 times.
✓ Branch 1 taken 6955 times.
|
13979 | if(is_chunked_) |
| 201 | 7024 | return remaining <= chunked_overhead_; | |
| 202 | |||
| 203 | 6955 | return remaining == 0; | |
| 204 | } | ||
| 205 | |||
| 206 | buffers::mutable_buffer_pair | ||
| 207 | 10527 | prepare() noexcept | |
| 208 | { | ||
| 209 |
2/2✓ Branch 0 taken 5280 times.
✓ Branch 1 taken 5247 times.
|
10527 | if(is_chunked_) |
| 210 | { | ||
| 211 | 5280 | return buffers::sans_suffix( | |
| 212 | 5280 | buffers::sans_prefix( | |
| 213 | 5280 | mbp_, | |
| 214 | 5280 | chunk_header_len + n_) | |
| 215 | 5280 | , final_chunk_len + crlf_len); | |
| 216 | } | ||
| 217 | 5247 | return buffers::sans_prefix(mbp_, n_); | |
| 218 | } | ||
| 219 | |||
| 220 | void | ||
| 221 | 10525 | commit(std::size_t n, bool more) noexcept | |
| 222 | { | ||
| 223 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10525 times.
|
10525 | BOOST_ASSERT(more_input_); |
| 224 | 10525 | n_ += n; | |
| 225 | 10525 | more_input_ = more; | |
| 226 | 10525 | } | |
| 227 | |||
| 228 | 8975 | ~appender() | |
| 229 | { | ||
| 230 |
2/2✓ Branch 0 taken 4504 times.
✓ Branch 1 taken 4471 times.
|
8975 | if(is_chunked_) |
| 231 | { | ||
| 232 |
2/2✓ Branch 0 taken 4503 times.
✓ Branch 1 taken 1 times.
|
4504 | if(n_) |
| 233 | { | ||
| 234 | 4503 | write_chunk_header(mbp_, n_); | |
| 235 | 4503 | cb_.commit(n_ + chunk_header_len); | |
| 236 | |||
| 237 | 4503 | write_crlf( | |
| 238 | 4503 | cb_.prepare(crlf_len)); | |
| 239 | 4503 | cb_.commit(crlf_len); | |
| 240 | } | ||
| 241 | |||
| 242 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 4466 times.
|
4504 | if(!more_input_) |
| 243 | { | ||
| 244 | 38 | write_final_chunk( | |
| 245 | 38 | cb_.prepare(final_chunk_len)); | |
| 246 | 38 | cb_.commit(final_chunk_len); | |
| 247 | } | ||
| 248 | } | ||
| 249 | else // is_chunked_ == false | ||
| 250 | { | ||
| 251 | 4471 | cb_.commit(n_); | |
| 252 | } | ||
| 253 | 8975 | } | |
| 254 | }; | ||
| 255 | |||
| 256 | } // namespace | ||
| 257 | |||
| 258 | //------------------------------------------------ | ||
| 259 | |||
| 260 | 57 | serializer:: | |
| 261 | ~serializer() | ||
| 262 | { | ||
| 263 | 57 | } | |
| 264 | |||
| 265 | ✗ | serializer:: | |
| 266 | serializer( | ||
| 267 | serializer&&) noexcept = default; | ||
| 268 | |||
| 269 | 11 | serializer:: | |
| 270 | serializer( | ||
| 271 | 11 | context& ctx) | |
| 272 | 11 | : serializer(ctx, 65536) | |
| 273 | { | ||
| 274 | 11 | } | |
| 275 | |||
| 276 | 57 | serializer:: | |
| 277 | serializer( | ||
| 278 | context& ctx, | ||
| 279 | 57 | std::size_t buffer_size) | |
| 280 | 57 | : ctx_(ctx) | |
| 281 | 57 | , ws_(buffer_size) | |
| 282 | { | ||
| 283 | 57 | } | |
| 284 | |||
| 285 | void | ||
| 286 | 179 | serializer:: | |
| 287 | reset() noexcept | ||
| 288 | { | ||
| 289 | 179 | ws_.clear(); | |
| 290 | 179 | filter_ = nullptr; | |
| 291 | 179 | is_done_ = false; | |
| 292 | 179 | is_header_done_ = false; | |
| 293 | 179 | filter_done_ = false; | |
| 294 | 179 | } | |
| 295 | |||
| 296 | //------------------------------------------------ | ||
| 297 | |||
| 298 | auto | ||
| 299 | 9042 | serializer:: | |
| 300 | prepare() -> | ||
| 301 | system::result<const_buffers_type> | ||
| 302 | { | ||
| 303 | // Precondition violation | ||
| 304 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9041 times.
|
9042 | if(is_done_) |
| 305 | 1 | detail::throw_logic_error(); | |
| 306 | |||
| 307 | // Expect: 100-continue | ||
| 308 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9037 times.
|
9041 | if(needs_exp100_continue_) |
| 309 | { | ||
| 310 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if(!is_header_done_) |
| 311 | 4 | return const_buffers_type( | |
| 312 | 2 | prepped_.begin(), | |
| 313 | 2 | 1); // limit to header | |
| 314 | |||
| 315 | 2 | needs_exp100_continue_ = false; | |
| 316 | |||
| 317 | 2 | BOOST_HTTP_PROTO_RETURN_EC( | |
| 318 | error::expect_100_continue); | ||
| 319 | } | ||
| 320 | |||
| 321 |
2/2✓ Branch 0 taken 80 times.
✓ Branch 1 taken 8957 times.
|
9037 | if(!filter_) |
| 322 | { | ||
| 323 |
4/5✓ Branch 0 taken 3 times.
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 35 times.
✗ Branch 4 not taken.
|
80 | switch(st_) |
| 324 | { | ||
| 325 | 3 | case style::empty: | |
| 326 | 6 | return const_buffers_type( | |
| 327 | 3 | prepped_.begin(), | |
| 328 | 6 | prepped_.size()); | |
| 329 | |||
| 330 | 19 | case style::buffers: | |
| 331 | // add more buffers if prepped_ is half empty. | ||
| 332 |
6/6✓ Branch 0 taken 10 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 17 times.
|
29 | if(more_input_ && |
| 333 | 10 | prepped_.capacity() >= prepped_.size()) | |
| 334 | { | ||
| 335 | 2 | prepped_.slide_to_front(); | |
| 336 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | while(prepped_.capacity() != 0) |
| 337 | { | ||
| 338 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | auto buf = buf_gen_->next(); |
| 339 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 2 times.
|
15 | if(buf.size() != 0) |
| 340 | { | ||
| 341 | 13 | prepped_.append(buf); | |
| 342 | } | ||
| 343 | else // buf_gen_ is empty | ||
| 344 | { | ||
| 345 | // append crlf and final chunk | ||
| 346 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if(is_chunked_) |
| 347 | { | ||
| 348 | 1 | prepped_.append(tmp_); | |
| 349 | 1 | more_input_ = false; | |
| 350 | } | ||
| 351 | 2 | break; | |
| 352 | } | ||
| 353 | } | ||
| 354 |
6/8✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
|
2 | if(buf_gen_->is_empty() && !is_chunked_) |
| 355 | 1 | more_input_ = false; | |
| 356 | } | ||
| 357 | 38 | return const_buffers_type( | |
| 358 | 19 | prepped_.begin(), | |
| 359 | 38 | prepped_.size()); | |
| 360 | |||
| 361 | 23 | case style::source: | |
| 362 | { | ||
| 363 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
|
23 | if(!more_input_) |
| 364 | 22 | break; | |
| 365 | |||
| 366 | // handles chunked payloads automatically | ||
| 367 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 | appender apndr(cb0_, is_chunked_); |
| 368 | |||
| 369 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
|
18 | if(apndr.is_full()) |
| 370 | ✗ | break; | |
| 371 | |||
| 372 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 | const auto rs = source_->read( |
| 373 | 18 | apndr.prepare()); | |
| 374 | |||
| 375 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 17 times.
|
18 | if(rs.ec.failed()) |
| 376 | { | ||
| 377 | 1 | is_done_ = true; | |
| 378 | 1 | return rs.ec; | |
| 379 | } | ||
| 380 | |||
| 381 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 11 times.
|
17 | if(rs.finished) |
| 382 | 6 | more_input_ = false; | |
| 383 | |||
| 384 | 17 | apndr.commit(rs.bytes, more_input_); | |
| 385 | 17 | break; | |
| 386 |
2/2✓ Branch 1 taken 17 times.
✓ Branch 2 taken 1 times.
|
18 | } |
| 387 | |||
| 388 | 35 | case style::stream: | |
| 389 |
6/6✓ Branch 0 taken 30 times.
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 34 times.
|
35 | if(is_header_done_ && cb0_.size() == 0) |
| 390 | 1 | BOOST_HTTP_PROTO_RETURN_EC( | |
| 391 | error::need_data); | ||
| 392 | 34 | break; | |
| 393 | } | ||
| 394 | } | ||
| 395 | else // filter | ||
| 396 | { | ||
| 397 |
3/5✗ Branch 0 not taken.
✓ Branch 1 taken 1153 times.
✓ Branch 2 taken 2300 times.
✓ Branch 3 taken 5504 times.
✗ Branch 4 not taken.
|
8957 | switch(st_) |
| 398 | { | ||
| 399 | ✗ | case style::empty: | |
| 400 | ✗ | return const_buffers_type( | |
| 401 | ✗ | prepped_.begin(), | |
| 402 | ✗ | prepped_.size()); | |
| 403 | |||
| 404 | 1153 | case style::buffers: | |
| 405 | { | ||
| 406 |
1/2✓ Branch 1 taken 1153 times.
✗ Branch 2 not taken.
|
1153 | appender apndr(cb0_, is_chunked_); |
| 407 |
6/6✓ Branch 1 taken 1393 times.
✓ Branch 2 taken 1128 times.
✓ Branch 3 taken 1369 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 1369 times.
✓ Branch 6 taken 1152 times.
|
2521 | while(!apndr.is_full() && !filter_done_) |
| 408 | { | ||
| 409 |
6/6✓ Branch 0 taken 1353 times.
✓ Branch 1 taken 16 times.
✓ Branch 3 taken 401 times.
✓ Branch 4 taken 952 times.
✓ Branch 5 taken 401 times.
✓ Branch 6 taken 968 times.
|
1369 | if(more_input_ && tmp_.size() == 0) |
| 410 | { | ||
| 411 |
1/2✓ Branch 1 taken 401 times.
✗ Branch 2 not taken.
|
401 | tmp_ = buf_gen_->next(); |
| 412 |
2/2✓ Branch 1 taken 16 times.
✓ Branch 2 taken 385 times.
|
401 | if(tmp_.size() == 0) // buf_gen_ is empty |
| 413 | 16 | more_input_ = false; | |
| 414 | } | ||
| 415 | |||
| 416 |
1/2✓ Branch 1 taken 1369 times.
✗ Branch 2 not taken.
|
1369 | const auto rs = filter_->process( |
| 417 | ✗ | apndr.prepare(), | |
| 418 | 1369 | tmp_, | |
| 419 | 1369 | more_input_); | |
| 420 | |||
| 421 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1368 times.
|
1369 | if(rs.ec.failed()) |
| 422 | { | ||
| 423 | 1 | is_done_ = true; | |
| 424 | 1 | return rs.ec; | |
| 425 | } | ||
| 426 | |||
| 427 |
1/2✓ Branch 1 taken 1368 times.
✗ Branch 2 not taken.
|
1368 | tmp_ = buffers::sans_prefix(tmp_, rs.in_bytes); |
| 428 | 1368 | apndr.commit(rs.out_bytes, !rs.finished); | |
| 429 | |||
| 430 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1344 times.
|
1368 | if(rs.finished) |
| 431 | 24 | filter_done_ = true; | |
| 432 | } | ||
| 433 | 1152 | break; | |
| 434 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1152 times.
|
1153 | } |
| 435 | |||
| 436 | 2300 | case style::source: | |
| 437 | { | ||
| 438 |
1/2✓ Branch 1 taken 2300 times.
✗ Branch 2 not taken.
|
2300 | appender apndr(cb0_, is_chunked_); |
| 439 |
6/6✓ Branch 1 taken 3660 times.
✓ Branch 2 taken 2276 times.
✓ Branch 3 taken 3636 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 3636 times.
✓ Branch 6 taken 2300 times.
|
5936 | while(!apndr.is_full() && !filter_done_) |
| 440 | { | ||
| 441 |
6/6✓ Branch 0 taken 3628 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 2696 times.
✓ Branch 4 taken 932 times.
✓ Branch 5 taken 2696 times.
✓ Branch 6 taken 940 times.
|
3636 | if(more_input_ && cb1_.capacity() != 0) |
| 442 | { | ||
| 443 |
1/2✓ Branch 1 taken 2696 times.
✗ Branch 2 not taken.
|
2696 | const auto rs = source_->read( |
| 444 |
1/2✓ Branch 2 taken 2696 times.
✗ Branch 3 not taken.
|
2696 | cb1_.prepare(cb1_.capacity())); |
| 445 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2696 times.
|
2696 | if(rs.ec.failed()) |
| 446 | { | ||
| 447 | ✗ | is_done_ = true; | |
| 448 | ✗ | return rs.ec; | |
| 449 | } | ||
| 450 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2672 times.
|
2696 | if(rs.finished) |
| 451 | 24 | more_input_ = false; | |
| 452 | 2696 | cb1_.commit(rs.bytes); | |
| 453 | } | ||
| 454 | |||
| 455 |
1/2✓ Branch 1 taken 3636 times.
✗ Branch 2 not taken.
|
3636 | const auto rs = filter_->process( |
| 456 | 3636 | apndr.prepare(), | |
| 457 | ✗ | cb1_.data(), | |
| 458 | 3636 | more_input_); | |
| 459 | |||
| 460 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3636 times.
|
3636 | if(rs.ec.failed()) |
| 461 | { | ||
| 462 | ✗ | is_done_ = true; | |
| 463 | ✗ | return rs.ec; | |
| 464 | } | ||
| 465 | |||
| 466 | 3636 | cb1_.consume(rs.in_bytes); | |
| 467 | 3636 | apndr.commit(rs.out_bytes, !rs.finished); | |
| 468 | |||
| 469 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 3612 times.
|
3636 | if(rs.finished) |
| 470 | 24 | filter_done_ = true; | |
| 471 | } | ||
| 472 | 2300 | break; | |
| 473 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2300 times.
|
2300 | } |
| 474 | |||
| 475 | 5504 | case style::stream: | |
| 476 | { | ||
| 477 |
1/2✓ Branch 1 taken 5504 times.
✗ Branch 2 not taken.
|
5504 | appender apndr(cb0_, is_chunked_); |
| 478 | |||
| 479 |
3/6✓ Branch 1 taken 5504 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 5504 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5504 times.
|
5504 | if(apndr.is_full() || filter_done_) |
| 480 | ✗ | break; | |
| 481 | |||
| 482 | // The stream object is expected to | ||
| 483 | // have already populated cb1_ | ||
| 484 |
4/6✓ Branch 0 taken 5480 times.
✓ Branch 1 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5480 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5504 times.
|
5504 | if(more_input_ && cb1_.size() == 0) |
| 485 | { | ||
| 486 | ✗ | if(!prepped_.empty()) | |
| 487 | ✗ | break; | |
| 488 | |||
| 489 | ✗ | BOOST_HTTP_PROTO_RETURN_EC( | |
| 490 | error::need_data); | ||
| 491 | } | ||
| 492 | |||
| 493 |
1/2✓ Branch 1 taken 5504 times.
✗ Branch 2 not taken.
|
5504 | const auto rs = filter_->process( |
| 494 | 5504 | apndr.prepare(), | |
| 495 | ✗ | cb1_.data(), | |
| 496 | 5504 | more_input_); | |
| 497 | |||
| 498 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5504 times.
|
5504 | if(rs.ec.failed()) |
| 499 | { | ||
| 500 | ✗ | is_done_ = true; | |
| 501 | ✗ | return rs.ec; | |
| 502 | } | ||
| 503 | |||
| 504 | 5504 | cb1_.consume(rs.in_bytes); | |
| 505 | 5504 | apndr.commit(rs.out_bytes, !rs.finished); | |
| 506 | |||
| 507 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 5480 times.
|
5504 | if(rs.finished) |
| 508 | 24 | filter_done_ = true; | |
| 509 | |||
| 510 | 5504 | break; | |
| 511 |
1/2✓ Branch 1 taken 5504 times.
✗ Branch 2 not taken.
|
5504 | } |
| 512 | } | ||
| 513 | } | ||
| 514 | |||
| 515 | 9012 | prepped_.reset(!is_header_done_); | |
| 516 | 9012 | const auto cbp = cb0_.data(); | |
| 517 |
2/2✓ Branch 2 taken 9009 times.
✓ Branch 3 taken 3 times.
|
9012 | if(cbp[0].size() != 0) |
| 518 | 9009 | prepped_.append(cbp[0]); | |
| 519 |
2/2✓ Branch 2 taken 14 times.
✓ Branch 3 taken 8998 times.
|
9012 | if(cbp[1].size() != 0) |
| 520 | 14 | prepped_.append(cbp[1]); | |
| 521 | |||
| 522 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 9012 times.
|
9012 | BOOST_ASSERT( |
| 523 | buffers::size(prepped_) > 0); | ||
| 524 | |||
| 525 | 18024 | return const_buffers_type( | |
| 526 | 9012 | prepped_.begin(), | |
| 527 | 18024 | prepped_.size()); | |
| 528 | } | ||
| 529 | |||
| 530 | void | ||
| 531 | 10775 | serializer:: | |
| 532 | consume( | ||
| 533 | std::size_t n) | ||
| 534 | { | ||
| 535 | // Precondition violation | ||
| 536 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10774 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
10775 | if(is_done_ && n != 0) |
| 537 | 1 | detail::throw_logic_error(); | |
| 538 | |||
| 539 |
2/2✓ Branch 0 taken 100 times.
✓ Branch 1 taken 10674 times.
|
10774 | if(!is_header_done_) |
| 540 | { | ||
| 541 | const auto header_remain = | ||
| 542 | 100 | prepped_[0].size(); | |
| 543 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 89 times.
|
100 | if(n < header_remain) |
| 544 | { | ||
| 545 | 11 | prepped_.consume(n); | |
| 546 | 11 | return; | |
| 547 | } | ||
| 548 | 89 | n -= header_remain; | |
| 549 | 89 | prepped_.consume(header_remain); | |
| 550 | 89 | is_header_done_ = true; | |
| 551 | } | ||
| 552 | |||
| 553 | 10763 | prepped_.consume(n); | |
| 554 | |||
| 555 | // no-op when cb0_ is not in use | ||
| 556 | 10763 | cb0_.consume(n); | |
| 557 | |||
| 558 |
2/2✓ Branch 1 taken 1760 times.
✓ Branch 2 taken 9003 times.
|
10763 | if(!prepped_.empty()) |
| 559 | 1760 | return; | |
| 560 | |||
| 561 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9002 times.
|
9003 | if(needs_exp100_continue_) |
| 562 | 1 | return; | |
| 563 | |||
| 564 |
2/2✓ Branch 0 taken 8897 times.
✓ Branch 1 taken 105 times.
|
9002 | if(more_input_) |
| 565 | 8897 | return; | |
| 566 | |||
| 567 |
4/4✓ Branch 0 taken 88 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 72 times.
|
105 | if(filter_ && !filter_done_) |
| 568 | 16 | return; | |
| 569 | |||
| 570 | 89 | is_done_ = true; | |
| 571 | } | ||
| 572 | |||
| 573 | //------------------------------------------------ | ||
| 574 | |||
| 575 | detail::array_of_const_buffers | ||
| 576 | 99 | serializer:: | |
| 577 | make_array(std::size_t n) | ||
| 578 | { | ||
| 579 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
|
99 | if(n > std::numeric_limits<std::uint16_t>::max()) |
| 580 | ✗ | detail::throw_length_error(); | |
| 581 | |||
| 582 | return { | ||
| 583 | 99 | ws_.push_array(n, | |
| 584 | ✗ | buffers::const_buffer{}), | |
| 585 |
1/2✓ Branch 2 taken 99 times.
✗ Branch 3 not taken.
|
99 | static_cast<std::uint16_t>(n) }; |
| 586 | } | ||
| 587 | |||
| 588 | void | ||
| 589 | 99 | serializer:: | |
| 590 | start_init( | ||
| 591 | message_view_base const& m) | ||
| 592 | { | ||
| 593 | 99 | reset(); | |
| 594 | |||
| 595 | // VFALCO what do we do with | ||
| 596 | // metadata error code failures? | ||
| 597 | // m.ph_->md.maybe_throw(); | ||
| 598 | |||
| 599 | 99 | auto const& md = m.metadata(); | |
| 600 | 99 | needs_exp100_continue_ = md.expect.is_100_continue; | |
| 601 | |||
| 602 | // Transfer-Encoding | ||
| 603 | 99 | is_chunked_ = md.transfer_encoding.is_chunked; | |
| 604 | |||
| 605 | // Content-Encoding | ||
| 606 | 99 | auto const& ce = md.content_encoding; | |
| 607 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 63 times.
|
99 | if(ce.encoding == encoding::deflate) |
| 608 | { | ||
| 609 | 36 | filter_ = &ws_.emplace< | |
| 610 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | deflator_filter>(ctx_, ws_, false); |
| 611 | } | ||
| 612 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 26 times.
|
63 | else if(ce.encoding == encoding::gzip) |
| 613 | { | ||
| 614 | 37 | filter_ = &ws_.emplace< | |
| 615 |
1/2✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
|
37 | deflator_filter>(ctx_, ws_, true); |
| 616 | } | ||
| 617 | 99 | } | |
| 618 | |||
| 619 | void | ||
| 620 | 4 | serializer:: | |
| 621 | start_empty( | ||
| 622 | message_view_base const& m) | ||
| 623 | { | ||
| 624 | using mutable_buffer = | ||
| 625 | buffers::mutable_buffer; | ||
| 626 | |||
| 627 | 4 | start_init(m); | |
| 628 | 4 | st_ = style::empty; | |
| 629 | |||
| 630 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | if(!is_chunked_) |
| 631 | { | ||
| 632 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | prepped_ = make_array( |
| 633 | 1); // header | ||
| 634 | } | ||
| 635 | else | ||
| 636 | { | ||
| 637 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | prepped_ = make_array( |
| 638 | 1 + // header | ||
| 639 | 1); // final chunk | ||
| 640 | |||
| 641 | mutable_buffer final_chunk = { | ||
| 642 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ws_.reserve_front( |
| 643 | final_chunk_len), | ||
| 644 | 1 | final_chunk_len }; | |
| 645 | 1 | write_final_chunk(final_chunk); | |
| 646 | |||
| 647 | 1 | prepped_[1] = final_chunk; | |
| 648 | } | ||
| 649 | |||
| 650 | 4 | prepped_[0] = { m.ph_->cbuf, m.ph_->size }; | |
| 651 | 4 | more_input_ = false; | |
| 652 | 4 | } | |
| 653 | |||
| 654 | void | ||
| 655 | 32 | serializer:: | |
| 656 | start_buffers( | ||
| 657 | message_view_base const& m) | ||
| 658 | { | ||
| 659 | using mutable_buffer = | ||
| 660 | buffers::mutable_buffer; | ||
| 661 | |||
| 662 | // start_init() already called | ||
| 663 | 32 | st_ = style::buffers; | |
| 664 | |||
| 665 | 32 | const auto buffers_max = (std::min)( | |
| 666 | 64 | std::size_t{ 16 }, | |
| 667 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | buf_gen_->count()); |
| 668 | |||
| 669 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 25 times.
|
32 | if(!filter_) |
| 670 | { | ||
| 671 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
|
7 | if(!is_chunked_) |
| 672 | { | ||
| 673 | // no filter and no chunked | ||
| 674 | |||
| 675 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | prepped_ = make_array( |
| 676 | 1 + // header | ||
| 677 | buffers_max ); // buffers | ||
| 678 | |||
| 679 | 6 | prepped_[0] = { m.ph_->cbuf, m.ph_->size }; | |
| 680 |
1/2✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
12 | std::generate( |
| 681 | 6 | prepped_.begin() + 1, | |
| 682 | prepped_.end(), | ||
| 683 | 16 | [this](){ return buf_gen_->next(); }); | |
| 684 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | more_input_ = !buf_gen_->is_empty(); |
| 685 | 6 | return; | |
| 686 | } | ||
| 687 | |||
| 688 | // no filter and chunked | ||
| 689 | |||
| 690 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
1 | if(buf_gen_->is_empty()) |
| 691 | { | ||
| 692 | ✗ | prepped_ = make_array( | |
| 693 | 1 + // header | ||
| 694 | 1); // final chunk | ||
| 695 | |||
| 696 | mutable_buffer final_chunk = { | ||
| 697 | ✗ | ws_.reserve_front( | |
| 698 | final_chunk_len), | ||
| 699 | ✗ | final_chunk_len }; | |
| 700 | ✗ | write_final_chunk( | |
| 701 | final_chunk); | ||
| 702 | |||
| 703 | ✗ | prepped_[0] = { m.ph_->cbuf, m.ph_->size }; | |
| 704 | ✗ | prepped_[1] = final_chunk; | |
| 705 | ✗ | more_input_ = false; | |
| 706 | ✗ | return; | |
| 707 | } | ||
| 708 | |||
| 709 | // Write entire buffers as a single chunk | ||
| 710 | // since total size is known | ||
| 711 | |||
| 712 | mutable_buffer chunk_header = { | ||
| 713 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ws_.reserve_front( |
| 714 | chunk_header_len), | ||
| 715 | 1 | chunk_header_len }; | |
| 716 | |||
| 717 | 1 | write_chunk_header( | |
| 718 | chunk_header, | ||
| 719 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | buf_gen_->size()); |
| 720 | |||
| 721 | mutable_buffer crlf_and_final_chunk = { | ||
| 722 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ws_.reserve_front( |
| 723 | crlf_len + final_chunk_len), | ||
| 724 | 1 | crlf_len + final_chunk_len }; | |
| 725 | |||
| 726 | 1 | write_crlf( | |
| 727 | 1 | buffers::prefix( | |
| 728 | crlf_and_final_chunk, | ||
| 729 | crlf_len)); | ||
| 730 | |||
| 731 | 1 | write_final_chunk( | |
| 732 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | buffers::sans_prefix( |
| 733 | crlf_and_final_chunk, | ||
| 734 | crlf_len)); | ||
| 735 | |||
| 736 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | prepped_ = make_array( |
| 737 | 1 + // header | ||
| 738 | 1 + // chunk header | ||
| 739 | buffers_max + // buffers | ||
| 740 | 1); // buffer or (crlf and final chunk) | ||
| 741 | |||
| 742 | 1 | prepped_[0] = { m.ph_->cbuf, m.ph_->size }; | |
| 743 | 1 | prepped_[1] = chunk_header; | |
| 744 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | std::generate( |
| 745 | 1 | prepped_.begin() + 2, | |
| 746 | 1 | prepped_.end() - 1, | |
| 747 | 16 | [this](){ return buf_gen_->next(); }); | |
| 748 | |||
| 749 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | more_input_ = !buf_gen_->is_empty(); |
| 750 | // assigning the last slot | ||
| 751 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if(more_input_) |
| 752 | { | ||
| 753 | 1 | prepped_[prepped_.size() - 1] = | |
| 754 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
2 | buf_gen_->next(); |
| 755 | |||
| 756 | // deferred until buf_gen_ is drained | ||
| 757 | 1 | tmp_ = crlf_and_final_chunk; | |
| 758 | } | ||
| 759 | else | ||
| 760 | { | ||
| 761 | ✗ | prepped_[prepped_.size() - 1] = | |
| 762 | crlf_and_final_chunk; | ||
| 763 | } | ||
| 764 | 1 | return; | |
| 765 | } | ||
| 766 | |||
| 767 | // filter | ||
| 768 | |||
| 769 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
25 | prepped_ = make_array( |
| 770 | 1 + // header | ||
| 771 | 2); // circular buffer | ||
| 772 | |||
| 773 | 25 | const auto n = ws_.size() - 1; | |
| 774 |
1/2✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
|
25 | cb0_ = { ws_.reserve_front(n), n }; |
| 775 | |||
| 776 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 13 times.
|
25 | if(is_chunked_) |
| 777 | { | ||
| 778 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
|
12 | if(cb0_.capacity() <= chunked_overhead_) |
| 779 | ✗ | detail::throw_length_error(); | |
| 780 | } | ||
| 781 | else | ||
| 782 | { | ||
| 783 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
|
13 | if(cb0_.capacity() == 0) |
| 784 | ✗ | detail::throw_length_error(); | |
| 785 | } | ||
| 786 | |||
| 787 | 25 | prepped_[0] = { m.ph_->cbuf, m.ph_->size }; | |
| 788 | 25 | tmp_ = {}; | |
| 789 | 25 | more_input_ = !buf_gen_->is_empty(); | |
| 790 | } | ||
| 791 | |||
| 792 | void | ||
| 793 | 33 | serializer:: | |
| 794 | start_source( | ||
| 795 | message_view_base const& m) | ||
| 796 | { | ||
| 797 | // start_init() already called | ||
| 798 | 33 | st_ = style::source; | |
| 799 | |||
| 800 |
1/2✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
|
33 | prepped_ = make_array( |
| 801 | 1 + // header | ||
| 802 | 2); // circular buffer | ||
| 803 | |||
| 804 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 9 times.
|
33 | if(filter_) |
| 805 | { | ||
| 806 | // TODO: Optimize buffer distribution | ||
| 807 | 24 | const auto n = (ws_.size() - 1) / 2; | |
| 808 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | cb0_ = { ws_.reserve_front(n), n }; |
| 809 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | cb1_ = { ws_.reserve_front(n), n }; |
| 810 | } | ||
| 811 | else | ||
| 812 | { | ||
| 813 | 9 | const auto n = ws_.size() - 1; | |
| 814 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | cb0_ = { ws_.reserve_front(n), n }; |
| 815 | } | ||
| 816 | |||
| 817 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 19 times.
|
33 | if(is_chunked_) |
| 818 | { | ||
| 819 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
|
14 | if(cb0_.capacity() <= chunked_overhead_) |
| 820 | ✗ | detail::throw_length_error(); | |
| 821 | } | ||
| 822 | else | ||
| 823 | { | ||
| 824 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
|
19 | if(cb0_.capacity() == 0) |
| 825 | ✗ | detail::throw_length_error(); | |
| 826 | } | ||
| 827 | |||
| 828 | 33 | prepped_[0] = { m.ph_->cbuf, m.ph_->size }; | |
| 829 | 33 | more_input_ = true; | |
| 830 | 33 | } | |
| 831 | |||
| 832 | auto | ||
| 833 | 30 | serializer:: | |
| 834 | start_stream( | ||
| 835 | message_view_base const& m) -> | ||
| 836 | stream | ||
| 837 | { | ||
| 838 | 30 | start_init(m); | |
| 839 | 30 | st_ = style::stream; | |
| 840 | |||
| 841 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | prepped_ = make_array( |
| 842 | 1 + // header | ||
| 843 | 2); // circular buffer | ||
| 844 | |||
| 845 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 6 times.
|
30 | if(filter_) |
| 846 | { | ||
| 847 | // TODO: Optimize buffer distribution | ||
| 848 | 24 | const auto n = (ws_.size() - 1) / 2; | |
| 849 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | cb0_ = { ws_.reserve_front(n), n }; |
| 850 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | cb1_ = { ws_.reserve_front(n), n }; |
| 851 | } | ||
| 852 | else | ||
| 853 | { | ||
| 854 | 6 | const auto n = ws_.size() - 1; | |
| 855 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | cb0_ = { ws_.reserve_front(n), n }; |
| 856 | } | ||
| 857 | |||
| 858 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
|
30 | if(is_chunked_) |
| 859 | { | ||
| 860 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
|
15 | if(cb0_.capacity() <= chunked_overhead_) |
| 861 | ✗ | detail::throw_length_error(); | |
| 862 | } | ||
| 863 | else | ||
| 864 | { | ||
| 865 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
|
15 | if(cb0_.capacity() == 0) |
| 866 | ✗ | detail::throw_length_error(); | |
| 867 | } | ||
| 868 | |||
| 869 | 30 | prepped_[0] = { m.ph_->cbuf, m.ph_->size }; | |
| 870 | 30 | more_input_ = true; | |
| 871 | 30 | return stream{ *this }; | |
| 872 | } | ||
| 873 | |||
| 874 | //------------------------------------------------ | ||
| 875 | |||
| 876 | std::size_t | ||
| 877 | 69 | serializer:: | |
| 878 | stream:: | ||
| 879 | capacity() const noexcept | ||
| 880 | { | ||
| 881 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
|
69 | if(sr_->filter_) |
| 882 | ✗ | return sr_->cb1_.capacity(); | |
| 883 | |||
| 884 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 35 times.
|
69 | if(!sr_->is_chunked_) |
| 885 | 34 | return sr_->cb0_.capacity(); | |
| 886 | |||
| 887 | // chunked with no filter | ||
| 888 | 35 | const auto cap = sr_->cb0_.capacity(); | |
| 889 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 14 times.
|
35 | if(cap > chunked_overhead_) |
| 890 | 21 | return cap - chunked_overhead_; | |
| 891 | |||
| 892 | 14 | return 0; | |
| 893 | } | ||
| 894 | |||
| 895 | bool | ||
| 896 | 61 | serializer:: | |
| 897 | stream:: | ||
| 898 | is_full() const noexcept | ||
| 899 | { | ||
| 900 | 61 | return capacity() == 0; | |
| 901 | } | ||
| 902 | |||
| 903 | auto | ||
| 904 | 5511 | serializer:: | |
| 905 | stream:: | ||
| 906 | prepare() const -> | ||
| 907 | buffers_type | ||
| 908 | { | ||
| 909 |
2/2✓ Branch 0 taken 5480 times.
✓ Branch 1 taken 31 times.
|
5511 | if(sr_->filter_) |
| 910 | 5480 | return sr_->cb1_.prepare( | |
| 911 | 10960 | sr_->cb1_.capacity()); | |
| 912 | |||
| 913 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 16 times.
|
31 | if(!sr_->is_chunked_) |
| 914 | 15 | return sr_->cb0_.prepare( | |
| 915 | 30 | sr_->cb0_.capacity()); | |
| 916 | |||
| 917 | // chunked with no filter | ||
| 918 | 16 | const auto cap = sr_->cb0_.capacity(); | |
| 919 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if(cap <= chunked_overhead_) |
| 920 | ✗ | detail::throw_length_error(); | |
| 921 | |||
| 922 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | return buffers::sans_prefix( |
| 923 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
32 | sr_->cb0_.prepare( |
| 924 | cap - crlf_len - final_chunk_len), | ||
| 925 | 16 | chunk_header_len); | |
| 926 | } | ||
| 927 | |||
| 928 | void | ||
| 929 | 5511 | serializer:: | |
| 930 | stream:: | ||
| 931 | commit(std::size_t n) const | ||
| 932 | { | ||
| 933 |
2/2✓ Branch 0 taken 5480 times.
✓ Branch 1 taken 31 times.
|
5511 | if(sr_->filter_) |
| 934 | 5480 | return sr_->cb1_.commit(n); | |
| 935 | |||
| 936 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 16 times.
|
31 | if(!sr_->is_chunked_) |
| 937 | 15 | return sr_->cb0_.commit(n); | |
| 938 | |||
| 939 | // chunked with no filter | ||
| 940 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1 times.
|
16 | if(n != 0) |
| 941 | { | ||
| 942 | 15 | write_chunk_header( | |
| 943 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | sr_->cb0_.prepare( |
| 944 | chunk_header_len), | ||
| 945 | n); | ||
| 946 | 15 | sr_->cb0_.commit( | |
| 947 | chunk_header_len); | ||
| 948 | |||
| 949 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | sr_->cb0_.prepare(n); |
| 950 | 15 | sr_->cb0_.commit(n); | |
| 951 | |||
| 952 | 15 | write_crlf( | |
| 953 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | sr_->cb0_.prepare(crlf_len)); |
| 954 | 15 | sr_->cb0_.commit(crlf_len); | |
| 955 | } | ||
| 956 | } | ||
| 957 | |||
| 958 | void | ||
| 959 | 33 | serializer:: | |
| 960 | stream:: | ||
| 961 | close() const | ||
| 962 | { | ||
| 963 | // Precondition violation | ||
| 964 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 29 times.
|
33 | if(!sr_->more_input_) |
| 965 | 4 | detail::throw_logic_error(); | |
| 966 | |||
| 967 | 29 | sr_->more_input_ = false; | |
| 968 | |||
| 969 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 5 times.
|
29 | if(sr_->filter_) |
| 970 | 24 | return; | |
| 971 | |||
| 972 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
|
5 | if(!sr_->is_chunked_) |
| 973 | 2 | return; | |
| 974 | |||
| 975 | // chunked with no filter | ||
| 976 | 3 | write_final_chunk( | |
| 977 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | sr_->cb0_.prepare( |
| 978 | final_chunk_len)); | ||
| 979 | 3 | sr_->cb0_.commit(final_chunk_len); | |
| 980 | } | ||
| 981 | |||
| 982 | //------------------------------------------------ | ||
| 983 | |||
| 984 | } // http_proto | ||
| 985 | } // boost | ||
| 986 |