1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/base/chunked_upload_data_stream.h"
#include "base/check_op.h"
#include "base/memory/ptr_util.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
namespace net {
ChunkedUploadDataStream::Writer::~Writer() = default;
bool ChunkedUploadDataStream::Writer::AppendData(base::span<const uint8_t> data,
bool is_done) {
if (!upload_data_stream_)
return false;
upload_data_stream_->AppendData(data, is_done);
return true;
}
ChunkedUploadDataStream::Writer::Writer(
base::WeakPtr<ChunkedUploadDataStream> upload_data_stream)
: upload_data_stream_(upload_data_stream) {}
ChunkedUploadDataStream::ChunkedUploadDataStream(int64_t identifier,
bool has_null_source)
: UploadDataStream(/*is_chunked=*/true, has_null_source, identifier) {}
ChunkedUploadDataStream::~ChunkedUploadDataStream() = default;
std::unique_ptr<ChunkedUploadDataStream::Writer>
ChunkedUploadDataStream::CreateWriter() {
return base::WrapUnique(new Writer(weak_factory_.GetWeakPtr()));
}
void ChunkedUploadDataStream::AppendData(base::span<const uint8_t> data,
bool is_done) {
DCHECK(!all_data_appended_);
DCHECK(!data.empty() || is_done);
if (!data.empty()) {
upload_data_.push_back(
std::make_unique<std::vector<uint8_t>>(data.begin(), data.end()));
}
all_data_appended_ = is_done;
if (!read_buffer_.get())
return;
int result = ReadChunk(read_buffer_.get(), read_buffer_len_);
// Shouldn't get an error or ERR_IO_PENDING.
DCHECK_GE(result, 0);
read_buffer_ = nullptr;
read_buffer_len_ = 0;
OnReadCompleted(result);
}
int ChunkedUploadDataStream::InitInternal(const NetLogWithSource& net_log) {
// ResetInternal should already have been called.
DCHECK(!read_buffer_.get());
DCHECK_EQ(0u, read_index_);
DCHECK_EQ(0u, read_offset_);
return OK;
}
int ChunkedUploadDataStream::ReadInternal(IOBuffer* buf, int buf_len) {
DCHECK_LT(0, buf_len);
DCHECK(!read_buffer_.get());
int result = ReadChunk(buf, buf_len);
if (result == ERR_IO_PENDING) {
read_buffer_ = buf;
read_buffer_len_ = buf_len;
}
return result;
}
void ChunkedUploadDataStream::ResetInternal() {
read_buffer_ = nullptr;
read_buffer_len_ = 0;
read_index_ = 0;
read_offset_ = 0;
}
int ChunkedUploadDataStream::ReadChunk(IOBuffer* buf, int buf_len) {
// Copy as much data as possible from |upload_data_| to |buf|.
size_t bytes_read = 0;
const auto buf_len_s = base::checked_cast<size_t>(buf_len);
while (read_index_ < upload_data_.size() && bytes_read < buf_len_s) {
base::span<const uint8_t> data(*upload_data_[read_index_].get());
base::span<const uint8_t> bytes_to_read = data.subspan(
read_offset_,
std::min(buf_len_s - bytes_read, data.size() - read_offset_));
buf->span().subspan(bytes_read).copy_prefix_from(bytes_to_read);
bytes_read += bytes_to_read.size();
read_offset_ += bytes_to_read.size();
if (read_offset_ == data.size()) {
read_index_++;
read_offset_ = 0;
}
}
DCHECK_LE(bytes_read, buf_len_s);
// If no data was written, and not all data has been appended, return
// ERR_IO_PENDING. The read will be completed in the next call to AppendData.
if (bytes_read == 0 && !all_data_appended_) {
return ERR_IO_PENDING;
}
if (read_index_ == upload_data_.size() && all_data_appended_) {
SetIsFinalChunk();
}
return base::checked_cast<int>(bytes_read);
}
} // namespace net
|