|  | // Copyright (c) 2017 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 "ios/net/chunked_data_stream_uploader.h" | 
|  |  | 
|  | #include "base/logging.h" | 
|  | #include "net/base/io_buffer.h" | 
|  | #include "net/base/net_errors.h" | 
|  |  | 
|  | namespace net { | 
|  |  | 
|  | ChunkedDataStreamUploader::ChunkedDataStreamUploader(Delegate* delegate) | 
|  | : UploadDataStream(true, 0), | 
|  | delegate_(delegate), | 
|  | pending_read_buffer_(nullptr), | 
|  | pending_read_buffer_length_(0), | 
|  | pending_internal_read_(false), | 
|  | is_final_chunk_(false), | 
|  | is_front_of_stream_(true), | 
|  | weak_factory_(this) { | 
|  | DCHECK(delegate_); | 
|  | } | 
|  |  | 
|  | ChunkedDataStreamUploader::~ChunkedDataStreamUploader() {} | 
|  |  | 
|  | int ChunkedDataStreamUploader::InitInternal(const NetLogWithSource& net_log) { | 
|  | if (is_front_of_stream_) | 
|  | return OK; | 
|  | else | 
|  | return ERR_FAILED; | 
|  | } | 
|  |  | 
|  | int ChunkedDataStreamUploader::ReadInternal(net::IOBuffer* buffer, | 
|  | int buffer_length) { | 
|  | DCHECK(buffer); | 
|  | DCHECK_GT(buffer_length, 0); | 
|  | DCHECK(!pending_read_buffer_); | 
|  |  | 
|  | pending_read_buffer_ = buffer; | 
|  | pending_read_buffer_length_ = buffer_length; | 
|  |  | 
|  | // Read the stream if input data comes first. | 
|  | return Upload(); | 
|  | } | 
|  |  | 
|  | void ChunkedDataStreamUploader::ResetInternal() { | 
|  | pending_read_buffer_ = nullptr; | 
|  | pending_read_buffer_length_ = 0; | 
|  | pending_internal_read_ = false; | 
|  | // Internal reset will not affect the external stream data state. | 
|  | is_final_chunk_ = false; | 
|  | } | 
|  |  | 
|  | void ChunkedDataStreamUploader::UploadWhenReady(bool is_final_chunk) { | 
|  | is_final_chunk_ = is_final_chunk; | 
|  |  | 
|  | // Put the data if internal read comes first. | 
|  | if (pending_internal_read_) { | 
|  | Upload(); | 
|  | } | 
|  | } | 
|  |  | 
|  | int ChunkedDataStreamUploader::Upload() { | 
|  | DCHECK(pending_read_buffer_); | 
|  |  | 
|  | is_front_of_stream_ = false; | 
|  | int bytes_read = 0; | 
|  |  | 
|  | if (is_final_chunk_) { | 
|  | SetIsFinalChunk(); | 
|  | } else { | 
|  | bytes_read = delegate_->OnRead(pending_read_buffer_->data(), | 
|  | pending_read_buffer_length_); | 
|  |  | 
|  | // NSInputStream can read 0 bytes when hasBytesAvailable is true, so ignore | 
|  | // this piece and let this internal read remain pending. | 
|  | // Still returns ERR_IO_PENDING for other errors because currently it is not | 
|  | // supported to return failure in UploadDataStream::Read(). Handle the | 
|  | // failure in the delegate level. | 
|  | if (bytes_read <= 0) { | 
|  | pending_internal_read_ = true; | 
|  | return ERR_IO_PENDING; | 
|  | } | 
|  | } | 
|  |  | 
|  | pending_read_buffer_ = nullptr; | 
|  | pending_read_buffer_length_ = 0; | 
|  |  | 
|  | // When there is a Read() pending, call OnReadCompleted to notify read | 
|  | // completed. | 
|  | if (pending_internal_read_) { | 
|  | pending_internal_read_ = false; | 
|  | OnReadCompleted(bytes_read); | 
|  | } | 
|  | return bytes_read; | 
|  | } | 
|  |  | 
|  | }  // namespace net |