// 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/upload_data_stream.h" #include "base/check_op.h" #include "base/values.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/log/net_log_event_type.h" namespace net { namespace { base::Value NetLogInitEndInfoParams(int result, int total_size, bool is_chunked) { base::Value::Dict dict; dict.Set("net_error", result); dict.Set("total_size", total_size); dict.Set("is_chunked", is_chunked); return base::Value(std::move(dict)); } base::Value CreateReadInfoParams(int current_position) { base::Value::Dict dict; dict.Set("current_position", current_position); return base::Value(std::move(dict)); } } // namespace UploadDataStream::UploadDataStream(bool is_chunked, int64_t identifier) : UploadDataStream(is_chunked, /*has_null_source=*/false, identifier) {} UploadDataStream::UploadDataStream(bool is_chunked, bool has_null_source, int64_t identifier) : identifier_(identifier), is_chunked_(is_chunked), has_null_source_(has_null_source) {} UploadDataStream::~UploadDataStream() = default; int UploadDataStream::Init(CompletionOnceCallback callback, const NetLogWithSource& net_log) { Reset(); DCHECK(!initialized_successfully_); DCHECK(callback_.is_null()); DCHECK(!callback.is_null() || IsInMemory()); net_log_ = net_log; net_log_.BeginEvent(NetLogEventType::UPLOAD_DATA_STREAM_INIT); int result = InitInternal(net_log_); if (result == ERR_IO_PENDING) { DCHECK(!IsInMemory()); callback_ = std::move(callback); } else { OnInitCompleted(result); } return result; } int UploadDataStream::Read(IOBuffer* buf, int buf_len, CompletionOnceCallback callback) { DCHECK(!callback.is_null() || IsInMemory()); DCHECK(initialized_successfully_); DCHECK_GT(buf_len, 0); net_log_.BeginEvent(NetLogEventType::UPLOAD_DATA_STREAM_READ, [&] { return CreateReadInfoParams(current_position_); }); int result = 0; if (!is_eof_) result = ReadInternal(buf, buf_len); if (result == ERR_IO_PENDING) { DCHECK(!IsInMemory()); callback_ = std::move(callback); } else { OnReadCompleted(result); } return result; } bool UploadDataStream::IsEOF() const { DCHECK(initialized_successfully_); DCHECK(is_chunked_ || is_eof_ == (current_position_ == total_size_)); return is_eof_; } void UploadDataStream::Reset() { // If there's a pending callback, there's a pending init or read call that is // being canceled. if (!callback_.is_null()) { if (!initialized_successfully_) { // If initialization has not yet succeeded, this call is aborting // initialization. net_log_.EndEventWithNetErrorCode( NetLogEventType::UPLOAD_DATA_STREAM_INIT, ERR_ABORTED); } else { // Otherwise, a read is being aborted. net_log_.EndEventWithNetErrorCode( NetLogEventType::UPLOAD_DATA_STREAM_READ, ERR_ABORTED); } } current_position_ = 0; initialized_successfully_ = false; is_eof_ = false; total_size_ = 0; callback_.Reset(); ResetInternal(); } void UploadDataStream::SetSize(uint64_t size) { DCHECK(!initialized_successfully_); DCHECK(!is_chunked_); total_size_ = size; } void UploadDataStream::SetIsFinalChunk() { DCHECK(initialized_successfully_); DCHECK(is_chunked_); DCHECK(!is_eof_); is_eof_ = true; } bool UploadDataStream::IsInMemory() const { return false; } const std::vector>* UploadDataStream::GetElementReaders() const { return nullptr; } void UploadDataStream::OnInitCompleted(int result) { DCHECK_NE(ERR_IO_PENDING, result); DCHECK(!initialized_successfully_); DCHECK_EQ(0u, current_position_); DCHECK(!is_eof_); if (result == OK) { initialized_successfully_ = true; if (!is_chunked_ && total_size_ == 0) is_eof_ = true; } net_log_.EndEvent(NetLogEventType::UPLOAD_DATA_STREAM_INIT, [&] { return NetLogInitEndInfoParams(result, total_size_, is_chunked_); }); if (!callback_.is_null()) std::move(callback_).Run(result); } void UploadDataStream::OnReadCompleted(int result) { DCHECK(initialized_successfully_); DCHECK(result != 0 || is_eof_); DCHECK_NE(ERR_IO_PENDING, result); if (result > 0) { current_position_ += result; if (!is_chunked_) { DCHECK_LE(current_position_, total_size_); if (current_position_ == total_size_) is_eof_ = true; } } net_log_.EndEventWithNetErrorCode(NetLogEventType::UPLOAD_DATA_STREAM_READ, result); if (!callback_.is_null()) std::move(callback_).Run(result); } UploadProgress UploadDataStream::GetUploadProgress() const { // While initialization / rewinding is in progress, return nothing. if (!initialized_successfully_) return UploadProgress(); return UploadProgress(current_position_, total_size_); } bool UploadDataStream::AllowHTTP1() const { return true; } } // namespace net