// 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 #include "base/bind.h" #include "base/compiler_specific.h" #include "base/memory/ref_counted_memory.h" #include "base/message_loop/message_loop.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& buf, int buf_size, const scoped_refptr& data, int64 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::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&URLRequestSimpleJob::StartAsync, weak_factory_.GetWeakPtr())); } 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() {} bool URLRequestSimpleJob::ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) { DCHECK(bytes_read); buf_size = static_cast( std::min(static_cast(buf_size), byte_range_.last_byte_position() - next_data_offset_ + 1)); DCHECK_GE(buf_size, 0); if (buf_size == 0) { *bytes_read = 0; return true; } // 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::OnReadCompleted, weak_factory_.GetWeakPtr(), buf_size)); next_data_offset_ += buf_size; SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); return false; } void URLRequestSimpleJob::OnReadCompleted(int bytes_read) { SetStatus(URLRequestStatus()); NotifyReadComplete(bytes_read); } 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* data, const CompletionCallback& callback) const { scoped_refptr 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) { NotifyDone(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())) { NotifyDone(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