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