blob: 9465b74616249120796106b5f91eb37877510f8a [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/base/elements_upload_data_stream.h"
#include "base/bind.h"
#include "base/logging.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/base/upload_bytes_element_reader.h"
#include "net/base/upload_element_reader.h"
namespace net {
ElementsUploadDataStream::ElementsUploadDataStream(
std::vector<std::unique_ptr<UploadElementReader>> element_readers,
int64_t identifier)
: UploadDataStream(false, identifier),
element_readers_(std::move(element_readers)),
element_index_(0),
read_error_(OK),
weak_ptr_factory_(this) {}
ElementsUploadDataStream::~ElementsUploadDataStream() = default;
std::unique_ptr<UploadDataStream> ElementsUploadDataStream::CreateWithReader(
std::unique_ptr<UploadElementReader> reader,
int64_t identifier) {
std::vector<std::unique_ptr<UploadElementReader>> readers;
readers.push_back(std::move(reader));
return std::unique_ptr<UploadDataStream>(
new ElementsUploadDataStream(std::move(readers), identifier));
}
int ElementsUploadDataStream::InitInternal(const NetLogWithSource& net_log) {
return InitElements(0);
}
int ElementsUploadDataStream::ReadInternal(
IOBuffer* buf,
int buf_len) {
DCHECK_GT(buf_len, 0);
return ReadElements(base::MakeRefCounted<DrainableIOBuffer>(buf, buf_len));
}
bool ElementsUploadDataStream::IsInMemory() const {
for (const std::unique_ptr<UploadElementReader>& it : element_readers_) {
if (!it->IsInMemory())
return false;
}
return true;
}
const std::vector<std::unique_ptr<UploadElementReader>>*
ElementsUploadDataStream::GetElementReaders() const {
return &element_readers_;
}
void ElementsUploadDataStream::ResetInternal() {
weak_ptr_factory_.InvalidateWeakPtrs();
read_error_ = OK;
element_index_ = 0;
}
int ElementsUploadDataStream::InitElements(size_t start_index) {
// Call Init() for all elements.
for (size_t i = start_index; i < element_readers_.size(); ++i) {
UploadElementReader* reader = element_readers_[i].get();
// When new_result is ERR_IO_PENDING, InitInternal() will be called
// with start_index == i + 1 when reader->Init() finishes.
int result = reader->Init(
base::BindOnce(&ElementsUploadDataStream::OnInitElementCompleted,
weak_ptr_factory_.GetWeakPtr(), i));
DCHECK(result != ERR_IO_PENDING || !reader->IsInMemory());
DCHECK_LE(result, OK);
if (result != OK)
return result;
}
uint64_t total_size = 0;
for (const std::unique_ptr<UploadElementReader>& it : element_readers_) {
total_size += it->GetContentLength();
}
SetSize(total_size);
return OK;
}
void ElementsUploadDataStream::OnInitElementCompleted(size_t index,
int result) {
DCHECK_NE(ERR_IO_PENDING, result);
// Check the last result.
if (result == OK)
result = InitElements(index + 1);
if (result != ERR_IO_PENDING)
OnInitCompleted(result);
}
int ElementsUploadDataStream::ReadElements(
const scoped_refptr<DrainableIOBuffer>& buf) {
while (read_error_ == OK && element_index_ < element_readers_.size()) {
UploadElementReader* reader = element_readers_[element_index_].get();
if (reader->BytesRemaining() == 0) {
++element_index_;
continue;
}
if (buf->BytesRemaining() == 0)
break;
int result = reader->Read(
buf.get(), buf->BytesRemaining(),
base::BindOnce(&ElementsUploadDataStream::OnReadElementCompleted,
weak_ptr_factory_.GetWeakPtr(), buf));
if (result == ERR_IO_PENDING)
return ERR_IO_PENDING;
ProcessReadResult(buf, result);
}
if (buf->BytesConsumed() > 0)
return buf->BytesConsumed();
return read_error_;
}
void ElementsUploadDataStream::OnReadElementCompleted(
const scoped_refptr<DrainableIOBuffer>& buf,
int result) {
ProcessReadResult(buf, result);
result = ReadElements(buf);
if (result != ERR_IO_PENDING)
OnReadCompleted(result);
}
void ElementsUploadDataStream::ProcessReadResult(
const scoped_refptr<DrainableIOBuffer>& buf,
int result) {
DCHECK_NE(ERR_IO_PENDING, result);
DCHECK(!read_error_);
if (result >= 0) {
buf->DidConsume(result);
} else {
read_error_ = result;
}
}
} // namespace net