| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // | ||
| 2 | // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) | ||
| 3 | // Copyright (c) 2024 Christian Mazakas | ||
| 4 | // | ||
| 5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||
| 6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||
| 7 | // | ||
| 8 | // Official repository: https://github.com/cppalliance/http_proto | ||
| 9 | // | ||
| 10 | |||
| 11 | #include <boost/http_proto/detail/except.hpp> | ||
| 12 | #include <boost/http_proto/message_view_base.hpp> | ||
| 13 | #include <boost/http_proto/serializer.hpp> | ||
| 14 | #include <boost/http_proto/service/zlib_service.hpp> | ||
| 15 | #include <boost/buffers/algorithm.hpp> | ||
| 16 | #include <boost/buffers/buffer_copy.hpp> | ||
| 17 | #include <boost/buffers/buffer_size.hpp> | ||
| 18 | #include <boost/core/ignore_unused.hpp> | ||
| 19 | #include <stddef.h> | ||
| 20 | |||
| 21 | #include "detail/filter.hpp" | ||
| 22 | namespace boost { | ||
| 23 | namespace http_proto { | ||
| 24 | |||
| 25 | namespace { | ||
| 26 | class deflator_filter | ||
| 27 | : public http_proto::detail::filter | ||
| 28 | { | ||
| 29 | using stream_t = zlib::service::stream; | ||
| 30 | stream_t& deflator_; | ||
| 31 | |||
| 32 | public: | ||
| 33 | 48 | deflator_filter( | |
| 34 | context& ctx, | ||
| 35 | http_proto::detail::workspace& ws, | ||
| 36 | bool use_gzip) | ||
| 37 | 192 | : deflator_{ ctx.get_service<zlib::service>() | |
| 38 |
2/2✓ Branch 2 taken 24 times.
✓ Branch 3 taken 24 times.
|
48 | .make_deflator(ws, -1, use_gzip ? 31 : 15, 8) } |
| 39 | { | ||
| 40 | 48 | } | |
| 41 | |||
| 42 | virtual filter::results | ||
| 43 | 23756 | on_process( | |
| 44 | buffers::mutable_buffer out, | ||
| 45 | buffers::const_buffer in, | ||
| 46 | bool more) override | ||
| 47 | { | ||
| 48 | 23756 | auto flush = | |
| 49 |
2/2✓ Branch 0 taken 23648 times.
✓ Branch 1 taken 108 times.
|
23756 | more ? stream_t::flush::none : stream_t::flush::finish; |
| 50 | 23756 | filter::results results; | |
| 51 | |||
| 52 | for(;;) | ||
| 53 | { | ||
| 54 | 36236 | auto r = deflator_.write(out, in, flush); | |
| 55 | |||
| 56 | 36236 | results.out_bytes += r.out_bytes; | |
| 57 | 36236 | results.in_bytes += r.in_bytes; | |
| 58 | 36236 | results.ec = r.ec; | |
| 59 | 36236 | results.finished = r.finished; | |
| 60 | |||
| 61 |
6/6✓ Branch 1 taken 23916 times.
✓ Branch 2 taken 12320 times.
✓ Branch 3 taken 96 times.
✓ Branch 4 taken 23820 times.
✓ Branch 5 taken 12416 times.
✓ Branch 6 taken 23820 times.
|
36236 | if(r.ec || r.finished) |
| 62 | 23756 | return results; | |
| 63 | |||
| 64 | 23820 | out = buffers::sans_prefix(out, r.out_bytes); | |
| 65 | 23820 | in = buffers::sans_prefix(in, r.in_bytes); | |
| 66 | |||
| 67 |
2/2✓ Branch 1 taken 22444 times.
✓ Branch 2 taken 1376 times.
|
23820 | if(in.size() == 0) |
| 68 | { | ||
| 69 |
2/2✓ Branch 0 taken 11104 times.
✓ Branch 1 taken 11340 times.
|
22444 | if(r.out_bytes == 0) |
| 70 | { | ||
| 71 | // TODO: is this necessary? | ||
| 72 | 11104 | flush = stream_t::flush::sync; | |
| 73 | 11104 | continue; | |
| 74 | } | ||
| 75 | 11340 | return results; | |
| 76 | } | ||
| 77 | 12480 | } | |
| 78 | } | ||
| 79 | }; | ||
| 80 | } // namespace | ||
| 81 | |||
| 82 | void | ||
| 83 | ✗ | consume_buffers( | |
| 84 | buffers::const_buffer*& p, | ||
| 85 | std::size_t& n, | ||
| 86 | std::size_t bytes) | ||
| 87 | { | ||
| 88 | ✗ | while(n > 0) | |
| 89 | { | ||
| 90 | ✗ | if(bytes < p->size()) | |
| 91 | { | ||
| 92 | ✗ | *p += bytes; | |
| 93 | ✗ | return; | |
| 94 | } | ||
| 95 | ✗ | bytes -= p->size(); | |
| 96 | ✗ | ++p; | |
| 97 | ✗ | --n; | |
| 98 | } | ||
| 99 | |||
| 100 | // Precondition violation | ||
| 101 | ✗ | if(bytes > 0) | |
| 102 | ✗ | detail::throw_invalid_argument(); | |
| 103 | } | ||
| 104 | |||
| 105 | template<class MutableBuffers> | ||
| 106 | void | ||
| 107 | 6312 | write_chunk_header( | |
| 108 | MutableBuffers const& dest0, | ||
| 109 | std::size_t size) noexcept | ||
| 110 | { | ||
| 111 | static constexpr char hexdig[] = | ||
| 112 | "0123456789ABCDEF"; | ||
| 113 | char buf[18]; | ||
| 114 | 6312 | auto p = buf + 16; | |
| 115 |
2/2✓ Branch 0 taken 100992 times.
✓ Branch 1 taken 6312 times.
|
107304 | for(std::size_t i = 16; i--;) |
| 116 | { | ||
| 117 | 100992 | *--p = hexdig[size & 0xf]; | |
| 118 | 100992 | size >>= 4; | |
| 119 | } | ||
| 120 | 6312 | buf[16] = '\r'; | |
| 121 | 6312 | buf[17] = '\n'; | |
| 122 | 6312 | auto n = buffers::buffer_copy( | |
| 123 | dest0, | ||
| 124 | 12624 | buffers::const_buffer( | |
| 125 | buf, sizeof(buf))); | ||
| 126 | ignore_unused(n); | ||
| 127 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6312 times.
|
6312 | BOOST_ASSERT(n == 18); |
| 128 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6312 times.
|
6312 | BOOST_ASSERT( |
| 129 | buffers::buffer_size(dest0) == n); | ||
| 130 | 6312 | } | |
| 131 | |||
| 132 | template<class DynamicBuffer> | ||
| 133 | void | ||
| 134 | write_chunk_close(DynamicBuffer& db) | ||
| 135 | { | ||
| 136 | db.commit( | ||
| 137 | buffers::buffer_copy( | ||
| 138 | db.prepare(2), | ||
| 139 | buffers::const_buffer("\r\n", 2))); | ||
| 140 | } | ||
| 141 | |||
| 142 | template<class DynamicBuffer> | ||
| 143 | void | ||
| 144 | write_last_chunk(DynamicBuffer& db) | ||
| 145 | { | ||
| 146 | db.commit( | ||
| 147 | buffers::buffer_copy( | ||
| 148 | db.prepare(5), | ||
| 149 | buffers::const_buffer("0\r\n\r\n", 5))); | ||
| 150 | } | ||
| 151 | |||
| 152 | //------------------------------------------------ | ||
| 153 | |||
| 154 | 43 | serializer:: | |
| 155 | ~serializer() | ||
| 156 | { | ||
| 157 | 43 | } | |
| 158 | |||
| 159 | ✗ | serializer:: | |
| 160 | serializer( | ||
| 161 | serializer&&) noexcept = default; | ||
| 162 | |||
| 163 | 9 | serializer:: | |
| 164 | serializer( | ||
| 165 | 9 | context& ctx) | |
| 166 | 9 | : serializer(ctx, 65536) | |
| 167 | { | ||
| 168 | 9 | } | |
| 169 | |||
| 170 | 43 | serializer:: | |
| 171 | serializer( | ||
| 172 | context& ctx, | ||
| 173 | 43 | std::size_t buffer_size) | |
| 174 | 43 | : ws_(buffer_size) | |
| 175 | 43 | , ctx_(ctx) | |
| 176 | { | ||
| 177 | 43 | } | |
| 178 | |||
| 179 | void | ||
| 180 | 56 | serializer:: | |
| 181 | reset() noexcept | ||
| 182 | { | ||
| 183 | 56 | chunk_header_ = {}; | |
| 184 | 56 | chunk_close_ = {}; | |
| 185 | 56 | last_chunk_ = {}; | |
| 186 | 56 | filter_ = nullptr; | |
| 187 | 56 | more_ = false; | |
| 188 | 56 | is_done_ = false; | |
| 189 | 56 | is_chunked_ = false; | |
| 190 | 56 | is_expect_continue_ = false; | |
| 191 | 56 | is_compressed_ = false; | |
| 192 | 56 | filter_done_ = false; | |
| 193 | 56 | in_ = nullptr; | |
| 194 | 56 | out_ = nullptr; | |
| 195 | 56 | ws_.clear(); | |
| 196 | 56 | } | |
| 197 | |||
| 198 | //------------------------------------------------ | ||
| 199 | |||
| 200 | auto | ||
| 201 | 12604 | serializer:: | |
| 202 | prepare() -> | ||
| 203 | system::result< | ||
| 204 | const_buffers_type> | ||
| 205 | { | ||
| 206 | // Precondition violation | ||
| 207 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12603 times.
|
12604 | if( is_done_ ) |
| 208 | 1 | detail::throw_logic_error(); | |
| 209 | |||
| 210 | // Expect: 100-continue | ||
| 211 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12599 times.
|
12603 | if( is_expect_continue_ ) |
| 212 | { | ||
| 213 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if( !is_header_done_ ) |
| 214 | 2 | return const_buffers_type(hp_, 1); | |
| 215 | 2 | is_expect_continue_ = false; | |
| 216 | 2 | BOOST_HTTP_PROTO_RETURN_EC( | |
| 217 | error::expect_100_continue); | ||
| 218 | } | ||
| 219 | |||
| 220 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12596 times.
|
12599 | if( st_ == style::empty ) |
| 221 | 9 | return const_buffers_type( | |
| 222 | 6 | prepped_.data(), prepped_.size()); | |
| 223 | |||
| 224 |
4/4✓ Branch 0 taken 1575 times.
✓ Branch 1 taken 11021 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1572 times.
|
12596 | if( st_ == style::buffers && !filter_ ) |
| 225 | 9 | return const_buffers_type( | |
| 226 | 6 | prepped_.data(), prepped_.size()); | |
| 227 | |||
| 228 | // callers must consume() everything before invoking | ||
| 229 | // prepare() again | ||
| 230 |
4/6✓ Branch 0 taken 59 times.
✓ Branch 1 taken 12534 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 59 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12593 times.
|
12652 | if( !is_header_done_ && |
| 231 | 59 | buffers::buffer_size(prepped_) != prepped_[0].size() ) | |
| 232 | ✗ | detail::throw_logic_error(); | |
| 233 | |||
| 234 |
4/6✓ Branch 0 taken 12534 times.
✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12534 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12593 times.
|
25127 | if( is_header_done_ && |
| 235 | 12534 | buffers::buffer_size(prepped_) > 0 ) | |
| 236 | ✗ | detail::throw_logic_error(); | |
| 237 | |||
| 238 | 12593 | auto& input = *in_; | |
| 239 | 12593 | auto& output = *out_; | |
| 240 |
3/4✓ Branch 0 taken 5490 times.
✓ Branch 1 taken 7103 times.
✓ Branch 2 taken 5490 times.
✗ Branch 3 not taken.
|
12593 | if( st_ == style::source && more_ ) |
| 241 | { | ||
| 242 |
1/2✓ Branch 1 taken 5490 times.
✗ Branch 2 not taken.
|
5490 | auto results = src_->read( |
| 243 |
1/2✓ Branch 2 taken 5490 times.
✗ Branch 3 not taken.
|
5490 | input.prepare(input.capacity())); |
| 244 | 5490 | more_ = !results.finished; | |
| 245 | 5490 | input.commit(results.bytes); | |
| 246 | } | ||
| 247 | |||
| 248 | 30717 | if( st_ == style::stream && | |
| 249 |
8/8✓ Branch 0 taken 5531 times.
✓ Branch 1 taken 7062 times.
✓ Branch 2 taken 5510 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 5509 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 12592 times.
|
18103 | more_ && |
| 250 | 5510 | in_->size() == 0 ) | |
| 251 | 1 | BOOST_HTTP_PROTO_RETURN_EC(error::need_data); | |
| 252 | |||
| 253 | bool has_avail_out = | ||
| 254 |
6/6✓ Branch 0 taken 44 times.
✓ Branch 1 taken 12548 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 33 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 6 times.
|
25145 | ((!filter_ && (more_ || input.size() > 0)) || |
| 255 |
3/4✓ Branch 0 taken 12548 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 12548 times.
✗ Branch 3 not taken.
|
12553 | (filter_ && !filter_done_)); |
| 256 | |||
| 257 | 25312 | auto get_input = [&]() -> buffers::const_buffer | |
| 258 | { | ||
| 259 |
2/2✓ Branch 0 taken 3360 times.
✓ Branch 1 taken 21952 times.
|
25312 | if( st_ == style::buffers ) |
| 260 | { | ||
| 261 |
2/2✓ Branch 1 taken 56 times.
✓ Branch 2 taken 3304 times.
|
3360 | if( buffers::buffer_size(buf_) == 0 ) |
| 262 | 56 | return {}; | |
| 263 | |||
| 264 | 3304 | auto buf = *(buf_.data()); | |
| 265 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3304 times.
|
3304 | BOOST_ASSERT(buf.size() > 0); |
| 266 | 3304 | return buf; | |
| 267 | } | ||
| 268 | else | ||
| 269 | { | ||
| 270 |
2/2✓ Branch 1 taken 10992 times.
✓ Branch 2 taken 10960 times.
|
21952 | if( input.size() == 0 ) |
| 271 | 10992 | return {}; | |
| 272 | |||
| 273 | 10960 | auto cbs = input.data(); | |
| 274 | 10960 | auto buf = *cbs.begin(); | |
| 275 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10960 times.
|
10960 | if( buf.size() == 0 ) |
| 276 | { | ||
| 277 | ✗ | auto p = cbs.begin(); | |
| 278 | ✗ | ++p; | |
| 279 | ✗ | buf = *p; | |
| 280 | } | ||
| 281 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10960 times.
|
10960 | if( buf.size() == 0 ) |
| 282 | ✗ | detail::throw_logic_error(); | |
| 283 | 10960 | return buf; | |
| 284 | } | ||
| 285 | 12592 | }; | |
| 286 | |||
| 287 | 25312 | auto get_output = [&]() -> buffers::mutable_buffer | |
| 288 | { | ||
| 289 |
1/2✓ Branch 2 taken 25312 times.
✗ Branch 3 not taken.
|
25312 | auto mbs = output.prepare(output.capacity()); |
| 290 | 25312 | auto buf = *mbs.begin(); | |
| 291 |
2/2✓ Branch 1 taken 1556 times.
✓ Branch 2 taken 23756 times.
|
25312 | if( buf.size() == 0 ) |
| 292 | { | ||
| 293 | 1556 | auto p = mbs.begin(); | |
| 294 | 1556 | ++p; | |
| 295 | 1556 | buf = *p; | |
| 296 | } | ||
| 297 | 25312 | return buf; | |
| 298 | 12592 | }; | |
| 299 | |||
| 300 | 23756 | auto consume = [&](std::size_t n) | |
| 301 | { | ||
| 302 |
2/2✓ Branch 0 taken 1804 times.
✓ Branch 1 taken 21952 times.
|
23756 | if( st_ == style::buffers ) |
| 303 | { | ||
| 304 | 1804 | buf_.consume(n); | |
| 305 |
2/2✓ Branch 1 taken 60 times.
✓ Branch 2 taken 1744 times.
|
1804 | if( buffers::buffer_size(buf_) == 0 ) |
| 306 | 60 | more_ = false; | |
| 307 | } | ||
| 308 | else | ||
| 309 | 21952 | input.consume(n); | |
| 310 | 36348 | }; | |
| 311 | |||
| 312 | 12592 | std::size_t num_written = 0; | |
| 313 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 12548 times.
|
12592 | if( !filter_ ) |
| 314 | 44 | num_written += input.size(); | |
| 315 | else | ||
| 316 | { | ||
| 317 | for(;;) | ||
| 318 | { | ||
| 319 |
1/2✓ Branch 1 taken 25312 times.
✗ Branch 2 not taken.
|
25312 | auto in = get_input(); |
| 320 |
1/2✓ Branch 1 taken 25312 times.
✗ Branch 2 not taken.
|
25312 | auto out = get_output(); |
| 321 |
2/2✓ Branch 1 taken 1556 times.
✓ Branch 2 taken 23756 times.
|
25312 | if( out.size() == 0 ) |
| 322 | { | ||
| 323 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1556 times.
|
1556 | if( output.size() == 0 ) |
| 324 | ✗ | detail::throw_logic_error(); | |
| 325 | 12548 | break; | |
| 326 | } | ||
| 327 | |||
| 328 | 23756 | auto rs = filter_->process( | |
| 329 |
1/2✓ Branch 1 taken 23756 times.
✗ Branch 2 not taken.
|
23756 | out, in, more_); |
| 330 | |||
| 331 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 23660 times.
|
23756 | if( rs.finished ) |
| 332 | 96 | filter_done_ = true; | |
| 333 | |||
| 334 |
1/2✓ Branch 1 taken 23756 times.
✗ Branch 2 not taken.
|
23756 | consume(rs.in_bytes); |
| 335 | |||
| 336 |
2/2✓ Branch 0 taken 10992 times.
✓ Branch 1 taken 12764 times.
|
23756 | if( rs.out_bytes == 0 ) |
| 337 | 10992 | break; | |
| 338 | |||
| 339 | 12764 | num_written += rs.out_bytes; | |
| 340 | 12764 | output.commit(rs.out_bytes); | |
| 341 | 12764 | } | |
| 342 | } | ||
| 343 | |||
| 344 | // end: | ||
| 345 | 12592 | std::size_t n = 0; | |
| 346 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 12534 times.
|
12592 | if( !is_header_done_ ) |
| 347 | { | ||
| 348 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 58 times.
|
58 | BOOST_ASSERT(hp_ == &prepped_[0]); |
| 349 | 58 | ++n; | |
| 350 | } | ||
| 351 | else | ||
| 352 | 12534 | prepped_.reset(prepped_.capacity()); | |
| 353 | |||
| 354 |
2/2✓ Branch 0 taken 6278 times.
✓ Branch 1 taken 6314 times.
|
12592 | if( !is_chunked_ ) |
| 355 | { | ||
| 356 |
2/2✓ Branch 3 taken 12556 times.
✓ Branch 4 taken 6278 times.
|
18834 | for(buffers::const_buffer const& b : output.data()) |
| 357 | 12556 | prepped_[n++] = b; | |
| 358 | } | ||
| 359 | else | ||
| 360 | { | ||
| 361 |
2/2✓ Branch 0 taken 6311 times.
✓ Branch 1 taken 3 times.
|
6314 | if( has_avail_out ) |
| 362 | { | ||
| 363 | 6311 | write_chunk_header( | |
| 364 | 6311 | chunk_header_, num_written); | |
| 365 | 6311 | prepped_[n++] = chunk_header_; | |
| 366 | |||
| 367 |
2/2✓ Branch 3 taken 12622 times.
✓ Branch 4 taken 6311 times.
|
18933 | for(buffers::const_buffer const& b : output.data()) |
| 368 | 12622 | prepped_[n++] = b; | |
| 369 | |||
| 370 | 6311 | prepped_[n++] = chunk_close_; | |
| 371 | } | ||
| 372 | |||
| 373 |
4/4✓ Branch 0 taken 6292 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 6268 times.
✓ Branch 3 taken 24 times.
|
6314 | if( (filter_ && filter_done_) || |
| 374 |
4/4✓ Branch 0 taken 22 times.
✓ Branch 1 taken 6268 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 17 times.
|
6290 | (!filter_ && !more_) ) |
| 375 | 29 | prepped_[n++] = last_chunk_; | |
| 376 | } | ||
| 377 | |||
| 378 | auto cbs = const_buffers_type( | ||
| 379 | 12592 | prepped_.data(), prepped_.size()); | |
| 380 | |||
| 381 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 12592 times.
|
12592 | BOOST_ASSERT(buffers::buffer_size(cbs) > 0); |
| 382 | 12592 | return cbs; | |
| 383 | } | ||
| 384 | |||
| 385 | void | ||
| 386 | 14345 | serializer:: | |
| 387 | consume( | ||
| 388 | std::size_t n) | ||
| 389 | { | ||
| 390 | // Precondition violation | ||
| 391 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 14344 times.
|
14345 | if( is_done_ ) |
| 392 | 1 | detail::throw_logic_error(); | |
| 393 | |||
| 394 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 14341 times.
|
14344 | if( is_expect_continue_ ) |
| 395 | { | ||
| 396 | // Cannot consume more than | ||
| 397 | // the header on 100-continue | ||
| 398 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
|
3 | if( n > hp_->size() ) |
| 399 | 1 | detail::throw_invalid_argument(); | |
| 400 | } | ||
| 401 | |||
| 402 |
2/2✓ Branch 0 taken 76 times.
✓ Branch 1 taken 14267 times.
|
14343 | if( !is_header_done_ ) |
| 403 | { | ||
| 404 | // consume header | ||
| 405 |
2/2✓ Branch 1 taken 11 times.
✓ Branch 2 taken 65 times.
|
76 | if( n < hp_->size() ) |
| 406 | { | ||
| 407 | 11 | prepped_.consume(n); | |
| 408 | 11 | return; | |
| 409 | } | ||
| 410 | 65 | n -= hp_->size(); | |
| 411 | 65 | prepped_.consume(hp_->size()); | |
| 412 | 65 | is_header_done_ = true; | |
| 413 | } | ||
| 414 | |||
| 415 | 14332 | prepped_.consume(n); | |
| 416 | 14332 | auto is_empty = (buffers::buffer_size(prepped_) == 0); | |
| 417 | |||
| 418 |
6/6✓ Branch 0 taken 1580 times.
✓ Branch 1 taken 12752 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 1572 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 5 times.
|
14332 | if( st_ == style::buffers && !filter_ && is_empty ) |
| 419 | 3 | more_ = false; | |
| 420 | |||
| 421 |
4/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 14327 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 times.
|
14332 | if( st_ == style::empty && |
| 422 | 4 | is_empty && | |
| 423 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | !is_expect_continue_ ) |
| 424 | 3 | more_ = false; | |
| 425 | |||
| 426 |
2/2✓ Branch 0 taken 12600 times.
✓ Branch 1 taken 1732 times.
|
14332 | if( is_empty ) |
| 427 | { | ||
| 428 |
6/6✓ Branch 0 taken 12593 times.
✓ Branch 1 taken 7 times.
✓ Branch 3 taken 12587 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 12587 times.
✓ Branch 6 taken 13 times.
|
12600 | if( out_ && out_->size() ) |
| 429 | { | ||
| 430 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12587 times.
|
12587 | BOOST_ASSERT(st_ != style::empty); |
| 431 | 12587 | out_->consume(out_->size()); | |
| 432 | } | ||
| 433 |
2/2✓ Branch 0 taken 12548 times.
✓ Branch 1 taken 52 times.
|
12600 | is_done_ = filter_ ? filter_done_ : !more_; |
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 437 | void | ||
| 438 | 24 | serializer:: | |
| 439 | use_deflate_encoding() | ||
| 440 | { | ||
| 441 | // can only apply one encoding | ||
| 442 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | if(filter_) |
| 443 | ✗ | detail::throw_logic_error(); | |
| 444 | |||
| 445 | 24 | is_compressed_ = true; | |
| 446 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | filter_ = &ws_.emplace<deflator_filter>(ctx_, ws_, false); |
| 447 | 24 | } | |
| 448 | |||
| 449 | void | ||
| 450 | 24 | serializer:: | |
| 451 | use_gzip_encoding() | ||
| 452 | { | ||
| 453 | // can only apply one encoding | ||
| 454 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | if( filter_ ) |
| 455 | ✗ | detail::throw_logic_error(); | |
| 456 | |||
| 457 | 24 | is_compressed_ = true; | |
| 458 |
1/2✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
|
24 | filter_ = &ws_.emplace<deflator_filter>(ctx_, ws_, true); |
| 459 | 24 | } | |
| 460 | |||
| 461 | //------------------------------------------------ | ||
| 462 | |||
| 463 | void | ||
| 464 | 7 | serializer:: | |
| 465 | copy( | ||
| 466 | buffers::const_buffer* dest, | ||
| 467 | buffers::const_buffer const* src, | ||
| 468 | std::size_t n) noexcept | ||
| 469 | { | ||
| 470 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
|
14 | while(n--) |
| 471 | 7 | *dest++ = *src++; | |
| 472 | 7 | } | |
| 473 | |||
| 474 | void | ||
| 475 | 73 | serializer:: | |
| 476 | start_init( | ||
| 477 | message_view_base const& m) | ||
| 478 | { | ||
| 479 | // VFALCO what do we do with | ||
| 480 | // metadata error code failures? | ||
| 481 | // m.ph_->md.maybe_throw(); | ||
| 482 | |||
| 483 | 73 | auto const& md = m.metadata(); | |
| 484 | |||
| 485 | 73 | is_done_ = false; | |
| 486 | 73 | is_header_done_ = false; | |
| 487 | 73 | is_expect_continue_ = md.expect.is_100_continue; | |
| 488 | |||
| 489 | // Transfer-Encoding | ||
| 490 | { | ||
| 491 | 73 | auto const& te = md.transfer_encoding; | |
| 492 | 73 | is_chunked_ = te.is_chunked; | |
| 493 | } | ||
| 494 | |||
| 495 |
2/2✓ Branch 0 taken 31 times.
✓ Branch 1 taken 42 times.
|
73 | if( is_chunked_) |
| 496 | { | ||
| 497 | 31 | auto* p = ws_.reserve_front(chunked_overhead_); | |
| 498 | 31 | chunk_header_ = | |
| 499 | 31 | buffers::mutable_buffer(p, chunk_header_len_); | |
| 500 | 31 | chunk_close_ = | |
| 501 | 62 | buffers::mutable_buffer( | |
| 502 | 31 | p + chunk_header_len_, crlf_len_); | |
| 503 | 31 | last_chunk_ = | |
| 504 | 62 | buffers::mutable_buffer( | |
| 505 | 31 | p + chunk_header_len_ + crlf_len_, | |
| 506 | last_chunk_len_); | ||
| 507 | |||
| 508 | 31 | buffers::buffer_copy( | |
| 509 | 31 | chunk_close_, buffers::const_buffer("\r\n", 2)); | |
| 510 | 31 | buffers::buffer_copy( | |
| 511 | 31 | last_chunk_, | |
| 512 | 62 | buffers::const_buffer("0\r\n\r\n", 5)); | |
| 513 | } | ||
| 514 | 73 | } | |
| 515 | |||
| 516 | void | ||
| 517 | 4 | serializer:: | |
| 518 | start_empty( | ||
| 519 | message_view_base const& m) | ||
| 520 | { | ||
| 521 | 4 | start_init(m); | |
| 522 | |||
| 523 | 4 | st_ = style::empty; | |
| 524 | 4 | more_ = true; | |
| 525 | |||
| 526 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | if(! is_chunked_) |
| 527 | { | ||
| 528 | 3 | prepped_ = make_array( | |
| 529 | 1); // header | ||
| 530 | } | ||
| 531 | else | ||
| 532 | { | ||
| 533 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | prepped_ = make_array( |
| 534 | 1 + // header | ||
| 535 | 1); // final chunk | ||
| 536 | |||
| 537 | // Buffer is too small | ||
| 538 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if(ws_.size() < 5) |
| 539 | ✗ | detail::throw_length_error(); | |
| 540 | |||
| 541 | buffers::mutable_buffer dest( | ||
| 542 | 1 | ws_.data(), 5); | |
| 543 | 1 | buffers::buffer_copy( | |
| 544 | dest, | ||
| 545 | 1 | buffers::const_buffer( | |
| 546 | "0\r\n\r\n", 5)); | ||
| 547 | 1 | prepped_[1] = dest; | |
| 548 | } | ||
| 549 | |||
| 550 | 4 | hp_ = &prepped_[0]; | |
| 551 | 4 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
| 552 | 4 | } | |
| 553 | |||
| 554 | void | ||
| 555 | 23 | serializer:: | |
| 556 | start_buffers( | ||
| 557 | message_view_base const& m) | ||
| 558 | { | ||
| 559 | 23 | st_ = style::buffers; | |
| 560 | 23 | tmp1_ = {}; | |
| 561 | |||
| 562 |
4/4✓ Branch 0 taken 7 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1 times.
|
23 | if( !filter_ && !is_chunked_ ) |
| 563 | { | ||
| 564 | 6 | prepped_ = make_array( | |
| 565 | 1 + // header | ||
| 566 | 6 | buf_.size()); // user input | |
| 567 | |||
| 568 | 6 | hp_ = &prepped_[0]; | |
| 569 | 6 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
| 570 | |||
| 571 | 6 | copy(&prepped_[1], buf_.data(), buf_.size()); | |
| 572 | |||
| 573 | 6 | more_ = (buffers::buffer_size(buf_) > 0); | |
| 574 | 6 | return; | |
| 575 | } | ||
| 576 | |||
| 577 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
17 | if( !filter_ && is_chunked_ ) |
| 578 | { | ||
| 579 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if( buffers::buffer_size(buf_) == 0 ) |
| 580 | { | ||
| 581 | ✗ | prepped_ = make_array( | |
| 582 | 1 + // header | ||
| 583 | 1); // last chunk | ||
| 584 | |||
| 585 | ✗ | hp_ = &prepped_[0]; | |
| 586 | ✗ | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
| 587 | ✗ | prepped_[1] = last_chunk_; | |
| 588 | ✗ | more_ = false; | |
| 589 | ✗ | return; | |
| 590 | } | ||
| 591 | |||
| 592 | 2 | write_chunk_header( | |
| 593 | 1 | chunk_header_, buffers::buffer_size(buf_)); | |
| 594 | |||
| 595 | 1 | prepped_ = make_array( | |
| 596 | 1 + // header | ||
| 597 | 1 + // chunk header | ||
| 598 | 1 | buf_.size() + // user input | |
| 599 | 1 + // chunk close | ||
| 600 | 1); // last chunk | ||
| 601 | |||
| 602 | 1 | hp_ = &prepped_[0]; | |
| 603 | 1 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
| 604 | 1 | prepped_[1] = chunk_header_; | |
| 605 | 1 | copy(&prepped_[2], buf_.data(), buf_.size()); | |
| 606 | |||
| 607 | 1 | prepped_[prepped_.size() - 2] = chunk_close_; | |
| 608 | 1 | prepped_[prepped_.size() - 1] = last_chunk_; | |
| 609 | 1 | more_ = true; | |
| 610 | 1 | return; | |
| 611 | } | ||
| 612 | |||
| 613 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
|
16 | if( is_chunked_ ) |
| 614 | { | ||
| 615 | 8 | prepped_ = make_array( | |
| 616 | 1 + // header | ||
| 617 | 1 + // chunk header | ||
| 618 | 2 + // tmp | ||
| 619 | 1 + // chunk close | ||
| 620 | 1); // last chunk | ||
| 621 | } | ||
| 622 | else | ||
| 623 | 8 | prepped_ = make_array( | |
| 624 | 1 + // header | ||
| 625 | 2); // tmp | ||
| 626 | |||
| 627 | 16 | hp_ = &prepped_[0]; | |
| 628 | 16 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
| 629 | 16 | tmp0_ = { ws_.data(), ws_.size() }; | |
| 630 | 16 | out_ = &tmp0_; | |
| 631 | 16 | in_ = out_; | |
| 632 | 16 | more_ = true; | |
| 633 | } | ||
| 634 | |||
| 635 | void | ||
| 636 | 24 | serializer:: | |
| 637 | start_source( | ||
| 638 | message_view_base const& m, | ||
| 639 | source* src) | ||
| 640 | { | ||
| 641 | 24 | st_ = style::source; | |
| 642 | 24 | src_ = src; | |
| 643 | |||
| 644 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 14 times.
|
24 | if( is_chunked_ ) |
| 645 | { | ||
| 646 | 10 | prepped_ = make_array( | |
| 647 | 1 + // header | ||
| 648 | 1 + // chunk header | ||
| 649 | 2 + // tmp | ||
| 650 | 1 + // chunk close | ||
| 651 | 1); // last chunk | ||
| 652 | } | ||
| 653 | else | ||
| 654 | 14 | prepped_ = make_array( | |
| 655 | 1 + // header | ||
| 656 | 2); // tmp | ||
| 657 | |||
| 658 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 16 times.
|
24 | if( !filter_ ) |
| 659 | { | ||
| 660 | 8 | tmp0_ = { ws_.data(), ws_.size() }; | |
| 661 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
|
8 | if( tmp0_.capacity() < 1 ) |
| 662 | ✗ | detail::throw_length_error(); | |
| 663 | |||
| 664 | 8 | in_ = &tmp0_; | |
| 665 | 8 | out_ = &tmp0_; | |
| 666 | } | ||
| 667 | else | ||
| 668 | { | ||
| 669 | 16 | auto n = ws_.size() / 2; | |
| 670 | 16 | auto* p = ws_.reserve_front(n); | |
| 671 | 16 | tmp1_ = buffers::circular_buffer(p, n); | |
| 672 | |||
| 673 | 16 | tmp0_ = { ws_.data(), ws_.size() }; | |
| 674 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
|
16 | if( tmp0_.capacity() < 1 ) |
| 675 | ✗ | detail::throw_length_error(); | |
| 676 | |||
| 677 | 16 | in_ = &tmp1_; | |
| 678 | 16 | out_ = &tmp0_; | |
| 679 | } | ||
| 680 | |||
| 681 | 24 | hp_ = &prepped_[0]; | |
| 682 | 24 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
| 683 | 24 | more_ = true; | |
| 684 | 24 | } | |
| 685 | |||
| 686 | auto | ||
| 687 | 22 | serializer:: | |
| 688 | start_stream( | ||
| 689 | message_view_base const& m) -> | ||
| 690 | stream | ||
| 691 | { | ||
| 692 | 22 | start_init(m); | |
| 693 | |||
| 694 | 22 | st_ = style::stream; | |
| 695 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
|
22 | if( is_chunked_ ) |
| 696 | { | ||
| 697 | 11 | prepped_ = make_array( | |
| 698 | 1 + // header | ||
| 699 | 1 + // chunk header | ||
| 700 | 2 + // tmp | ||
| 701 | 1 + // chunk close | ||
| 702 | 1); // last chunk | ||
| 703 | } | ||
| 704 | else | ||
| 705 | 11 | prepped_ = make_array( | |
| 706 | 1 + // header | ||
| 707 | 2); // tmp | ||
| 708 | |||
| 709 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
|
22 | if( !filter_ ) |
| 710 | { | ||
| 711 | 6 | tmp0_ = { ws_.data(), ws_.size() }; | |
| 712 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
|
6 | if( tmp0_.capacity() < 1 ) |
| 713 | ✗ | detail::throw_length_error(); | |
| 714 | |||
| 715 | 6 | in_ = &tmp0_; | |
| 716 | 6 | out_ = &tmp0_; | |
| 717 | } | ||
| 718 | else | ||
| 719 | { | ||
| 720 | 16 | auto n = ws_.size() / 2; | |
| 721 | 16 | auto* p = ws_.reserve_front(n); | |
| 722 | 16 | tmp1_ = buffers::circular_buffer(p, n); | |
| 723 | |||
| 724 | 16 | tmp0_ = { ws_.data(), ws_.size() }; | |
| 725 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
|
16 | if( tmp0_.capacity() < 1 ) |
| 726 | ✗ | detail::throw_length_error(); | |
| 727 | |||
| 728 | 16 | in_ = &tmp1_; | |
| 729 | 16 | out_ = &tmp0_; | |
| 730 | } | ||
| 731 | |||
| 732 | 22 | hp_ = &prepped_[0]; | |
| 733 | 22 | *hp_ = { m.ph_->cbuf, m.ph_->size }; | |
| 734 | 22 | more_ = true; | |
| 735 | 22 | return stream{*this}; | |
| 736 | } | ||
| 737 | |||
| 738 | //------------------------------------------------ | ||
| 739 | |||
| 740 | std::size_t | ||
| 741 | 139 | serializer:: | |
| 742 | stream:: | ||
| 743 | capacity() const noexcept | ||
| 744 | { | ||
| 745 | 139 | return sr_->in_->capacity(); | |
| 746 | } | ||
| 747 | |||
| 748 | std::size_t | ||
| 749 | 72 | serializer:: | |
| 750 | stream:: | ||
| 751 | size() const noexcept | ||
| 752 | { | ||
| 753 | 72 | return sr_->in_->size(); | |
| 754 | } | ||
| 755 | |||
| 756 | bool | ||
| 757 | 63 | serializer:: | |
| 758 | stream:: | ||
| 759 | is_full() const noexcept | ||
| 760 | { | ||
| 761 | 63 | return capacity() == 0; | |
| 762 | } | ||
| 763 | |||
| 764 | auto | ||
| 765 | 5512 | serializer:: | |
| 766 | stream:: | ||
| 767 | prepare() const -> | ||
| 768 | buffers_type | ||
| 769 | { | ||
| 770 | 5512 | return sr_->in_->prepare(sr_->in_->capacity()); | |
| 771 | } | ||
| 772 | |||
| 773 | void | ||
| 774 | 5512 | serializer:: | |
| 775 | stream:: | ||
| 776 | commit(std::size_t n) const | ||
| 777 | { | ||
| 778 | // the stream must make a non-zero amount of bytes | ||
| 779 | // available to the serializer | ||
| 780 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5511 times.
|
5512 | if( n == 0 ) |
| 781 | 1 | detail::throw_logic_error(); | |
| 782 | |||
| 783 | 5511 | sr_->in_->commit(n); | |
| 784 | 5511 | } | |
| 785 | |||
| 786 | void | ||
| 787 | 25 | serializer:: | |
| 788 | stream:: | ||
| 789 | close() const | ||
| 790 | { | ||
| 791 | // Precondition violation | ||
| 792 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 21 times.
|
25 | if(! sr_->more_ ) |
| 793 | 4 | detail::throw_logic_error(); | |
| 794 | 21 | sr_->more_ = false; | |
| 795 | 21 | } | |
| 796 | |||
| 797 | //------------------------------------------------ | ||
| 798 | |||
| 799 | } // http_proto | ||
| 800 | } // boost | ||
| 801 |