| 123 | StdInputStream::~StdInputStream() = default; |
| 124 | |
| 125 | Result<void, Error> StdInputStream::fill_buffer(uint32_t min_fill_size) { |
| 126 | if (min_fill_size == 0 || remaining_size() >= min_fill_size) { |
| 127 | return Result<void, Error>(); |
| 128 | } |
| 129 | |
| 130 | const uint32_t read_pos = buffer_->reader_index_; |
| 131 | constexpr uint64_t k_max_u32 = std::numeric_limits<uint32_t>::max(); |
| 132 | const uint64_t target = |
| 133 | static_cast<uint64_t>(read_pos) + static_cast<uint64_t>(min_fill_size); |
| 134 | if (target > k_max_u32) { |
| 135 | return Unexpected( |
| 136 | Error::out_of_bound("stream buffer size exceeds uint32 range")); |
| 137 | } |
| 138 | |
| 139 | std::streambuf *source = stream_->rdbuf(); |
| 140 | if (source == nullptr) { |
| 141 | return Unexpected(Error::io_error("input stream has no stream buffer")); |
| 142 | } |
| 143 | uint32_t write_pos = buffer_->size_; |
| 144 | while (remaining_size() < min_fill_size) { |
| 145 | if (write_pos == data_.size()) { |
| 146 | // min_fill_size can come from attacker-controlled wire lengths. Do not |
| 147 | // query stream availability here: the virtual probe is not part of the |
| 148 | // correctness contract and would add an extra hot-path call for a rare |
| 149 | // fast path. Grow only from bytes already buffered so truncated streams |
| 150 | // fail before reserving the declared body size. |
| 151 | uint64_t new_size = |
| 152 | std::max<uint64_t>(static_cast<uint64_t>(data_.size()) * 2, |
| 153 | static_cast<uint64_t>(initial_buffer_size_)); |
| 154 | if (new_size <= data_.size()) { |
| 155 | new_size = static_cast<uint64_t>(data_.size()) + 1; |
| 156 | } |
| 157 | if (new_size > target) { |
| 158 | new_size = target; |
| 159 | } |
| 160 | reserve(static_cast<uint32_t>(new_size)); |
| 161 | } |
| 162 | uint32_t writable = static_cast<uint32_t>(data_.size()) - write_pos; |
| 163 | const std::streamsize read_bytes = |
| 164 | source->sgetn(reinterpret_cast<char *>(data_.data() + write_pos), |
| 165 | static_cast<std::streamsize>(writable)); |
| 166 | if (read_bytes <= 0) { |
| 167 | return Unexpected(Error::buffer_out_of_bound(read_pos, min_fill_size, |
| 168 | remaining_size())); |
| 169 | } |
| 170 | write_pos += static_cast<uint32_t>(read_bytes); |
| 171 | buffer_->size_ = write_pos; |
| 172 | } |
| 173 | return Result<void, Error>(); |
| 174 | } |
| 175 | |
| 176 | Result<void, Error> StdInputStream::read_to(uint8_t *dst, uint32_t length) { |
| 177 | if (length == 0) { |