// 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/url_request/url_request_simple_job.h"

#include <vector>

#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/location.h"
#include "base/memory/ref_counted_memory.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/threading/worker_pool.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_util.h"
#include "net/url_request/url_request_status.h"

namespace net {

namespace {

void CopyData(const scoped_refptr<IOBuffer>& buf,
              int buf_size,
              const scoped_refptr<base::RefCountedMemory>& data,
              int64_t data_offset) {
  memcpy(buf->data(), data->front() + data_offset, buf_size);
}

}  // namespace

URLRequestSimpleJob::URLRequestSimpleJob(URLRequest* request,
                                         NetworkDelegate* network_delegate)
    : URLRangeRequestJob(request, network_delegate),
      next_data_offset_(0),
      task_runner_(base::WorkerPool::GetTaskRunner(false)),
      weak_factory_(this) {
}

void URLRequestSimpleJob::Start() {
  // Start reading asynchronously so that all error reporting and data
  // callbacks happen as they would for network requests.
  base::ThreadTaskRunnerHandle::Get()->PostTask(
      FROM_HERE,
      base::Bind(&URLRequestSimpleJob::StartAsync, weak_factory_.GetWeakPtr()));
}

void URLRequestSimpleJob::Kill() {
  weak_factory_.InvalidateWeakPtrs();
  URLRangeRequestJob::Kill();
}

bool URLRequestSimpleJob::GetMimeType(std::string* mime_type) const {
  *mime_type = mime_type_;
  return true;
}

bool URLRequestSimpleJob::GetCharset(std::string* charset) {
  *charset = charset_;
  return true;
}

URLRequestSimpleJob::~URLRequestSimpleJob() {}

int URLRequestSimpleJob::ReadRawData(IOBuffer* buf, int buf_size) {
  buf_size = std::min(static_cast<int64_t>(buf_size),
                      byte_range_.last_byte_position() - next_data_offset_ + 1);
  if (buf_size == 0)
    return 0;

  // Do memory copy on a background thread. See crbug.com/422489.
  GetTaskRunner()->PostTaskAndReply(
      FROM_HERE, base::Bind(&CopyData, make_scoped_refptr(buf), buf_size, data_,
                            next_data_offset_),
      base::Bind(&URLRequestSimpleJob::ReadRawDataComplete,
                 weak_factory_.GetWeakPtr(), buf_size));
  next_data_offset_ += buf_size;
  return ERR_IO_PENDING;
}

base::TaskRunner* URLRequestSimpleJob::GetTaskRunner() const {
  return task_runner_.get();
}

int URLRequestSimpleJob::GetData(std::string* mime_type,
                                 std::string* charset,
                                 std::string* data,
                                 const CompletionCallback& callback) const {
  NOTREACHED();
  return ERR_UNEXPECTED;
}

int URLRequestSimpleJob::GetRefCountedData(
    std::string* mime_type,
    std::string* charset,
    scoped_refptr<base::RefCountedMemory>* data,
    const CompletionCallback& callback) const {
  scoped_refptr<base::RefCountedString> str_data(new base::RefCountedString());
  int result = GetData(mime_type, charset, &str_data->data(), callback);
  *data = str_data;
  return result;
}

void URLRequestSimpleJob::StartAsync() {
  if (!request_)
    return;

  if (ranges().size() > 1) {
    NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED,
                                      ERR_REQUEST_RANGE_NOT_SATISFIABLE));
    return;
  }

  if (!ranges().empty() && range_parse_result() == OK)
    byte_range_ = ranges().front();

  const int result =
      GetRefCountedData(&mime_type_, &charset_, &data_,
                        base::Bind(&URLRequestSimpleJob::OnGetDataCompleted,
                                   weak_factory_.GetWeakPtr()));

  if (result != ERR_IO_PENDING)
    OnGetDataCompleted(result);
}

void URLRequestSimpleJob::OnGetDataCompleted(int result) {
  if (result == OK) {
    // Notify that the headers are complete
    if (!byte_range_.ComputeBounds(data_->size())) {
      NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED,
                                        ERR_REQUEST_RANGE_NOT_SATISFIABLE));
      return;
    }

    next_data_offset_ = byte_range_.first_byte_position();
    set_expected_content_size(byte_range_.last_byte_position() -
                              next_data_offset_ + 1);
    NotifyHeadersComplete();
  } else {
    NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, result));
  }
}

}  // namespace net
