chromium/ios/net/chunked_data_stream_uploader.cc

// Copyright 2017 The Chromium Authors
// 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/check_op.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