electron/atom/browser/net/atom_url_request.cc

263 lines
7.8 KiB
C++
Raw Normal View History

// Copyright (c) 2013 GitHub, Inc.
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/net/atom_url_request.h"
#include "atom/browser/api/atom_api_url_request.h"
#include "atom/browser/atom_browser_context.h"
#include "base/callback.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/io_buffer.h"
2016-09-21 15:35:03 +00:00
namespace {
const int kBufferSize = 4096;
} // namespace
namespace atom {
2016-09-21 15:35:03 +00:00
AtomURLRequest::AtomURLRequest(base::WeakPtr<api::URLRequest> delegate)
: delegate_(delegate)
2016-09-21 15:35:03 +00:00
, buffer_(new net::IOBuffer(kBufferSize)) {
}
AtomURLRequest::~AtomURLRequest() {
}
2016-09-21 15:35:03 +00:00
scoped_refptr<AtomURLRequest> AtomURLRequest::Create(
AtomBrowserContext* browser_context,
2016-09-21 15:35:03 +00:00
const std::string& method,
const std::string& url,
base::WeakPtr<api::URLRequest> delegate) {
2016-09-21 15:35:03 +00:00
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(browser_context);
DCHECK(!url.empty());
auto request_context_getter = browser_context->url_request_context_getter();
DCHECK(request_context_getter);
auto context = request_context_getter->GetURLRequestContext();
DCHECK(context);
scoped_refptr<AtomURLRequest> atom_url_request = new AtomURLRequest(delegate);
2016-09-21 15:35:03 +00:00
atom_url_request->request_ = context->CreateRequest(GURL(url),
net::RequestPriority::DEFAULT_PRIORITY,
atom_url_request.get());
2016-09-21 15:35:03 +00:00
atom_url_request->request_->set_method(method);
return atom_url_request;
}
2016-09-21 15:35:03 +00:00
void AtomURLRequest::Write() const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
}
2016-09-21 15:35:03 +00:00
void AtomURLRequest::End() const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
2016-09-21 15:35:03 +00:00
base::Bind(&AtomURLRequest::DoStart, this));
}
2016-09-21 15:35:03 +00:00
void AtomURLRequest::Abort() const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
}
2016-09-21 15:35:03 +00:00
void AtomURLRequest::SetHeader(const std::string& name,
const std::string& value) const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
request_->SetExtraRequestHeaderByName(name, value, true);
}
2016-09-21 15:35:03 +00:00
std::string AtomURLRequest::GetHeader(const std::string& name) const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::string result;
const auto& extra_headers = request_->extra_request_headers();
if (!extra_headers.GetHeader(name, &result)) {
net::HttpRequestHeaders* request_headers = nullptr;
if (request_->GetFullRequestHeaders(request_headers) && request_headers) {
request_headers->GetHeader(name, &result);
}
}
return result;
}
2016-09-21 15:35:03 +00:00
void AtomURLRequest::RemoveHeader(const std::string& name) const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
request_->RemoveRequestHeaderByName(name);
}
2016-09-21 15:35:03 +00:00
scoped_refptr<const net::HttpResponseHeaders>
AtomURLRequest::GetResponseHeaders() const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
return request_->response_headers();
}
2016-09-21 15:35:03 +00:00
void AtomURLRequest::PassLoginInformation(const base::string16& username,
const base::string16& password) const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (username.empty() || password.empty()) {
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&AtomURLRequest::DoCancelAuth, this));
}
else {
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::Bind(&AtomURLRequest::DoSetAuth, this, username, password));
}
}
2016-09-21 15:35:03 +00:00
void AtomURLRequest::DoStart() const {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
2016-09-21 15:35:03 +00:00
request_->Start();
}
2016-09-21 15:35:03 +00:00
void AtomURLRequest::DoSetAuth(const base::string16& username,
const base::string16& password) const {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
request_->SetAuth(net::AuthCredentials(username, password));
}
2016-09-21 15:35:03 +00:00
void AtomURLRequest::DoCancelAuth() const {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
request_->CancelAuth();
}
2016-09-21 15:35:03 +00:00
void AtomURLRequest::OnAuthRequired(net::URLRequest* request,
net::AuthChallengeInfo* auth_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(&AtomURLRequest::InformDelegateAuthenticationRequired,
this,
scoped_refptr<net::AuthChallengeInfo>(auth_info)));
}
void AtomURLRequest::OnResponseStarted(net::URLRequest* request) {
2016-09-21 15:35:03 +00:00
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK_EQ(request, request_.get());
2016-09-21 15:35:03 +00:00
if (request_->status().is_success()) {
// Cache net::HttpResponseHeaders instance, a read-only objects
// so that headers and other http metainformation can be simultaneously
// read from UI thread while request data is simulataneously streaming
// on IO thread.
2016-09-21 15:35:03 +00:00
response_headers_ = request_->response_headers();
}
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(&AtomURLRequest::InformDelegateResponseStarted, this));
ReadResponse();
}
void AtomURLRequest::ReadResponse() {
2016-09-21 15:35:03 +00:00
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// Some servers may treat HEAD requests as GET requests. To free up the
// network connection as soon as possible, signal that the request has
// completed immediately, without trying to read any data back (all we care
// about is the response code and headers, which we already have).
int bytes_read = 0;
2016-09-21 15:35:03 +00:00
if (request_->status().is_success() /* TODO && (request_type_ != URLFetcher::HEAD)*/) {
if (!request_->Read(buffer_.get(), kBufferSize, &bytes_read))
bytes_read = -1;
}
2016-09-21 15:35:03 +00:00
OnReadCompleted(request_.get(), bytes_read);
}
void AtomURLRequest::OnReadCompleted(net::URLRequest* request, int bytes_read) {
2016-09-21 15:35:03 +00:00
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
2016-09-21 15:35:03 +00:00
DCHECK_EQ(request, request_.get());
do {
2016-09-21 15:35:03 +00:00
if (!request_->status().is_success() || bytes_read <= 0)
break;
const auto result = CopyAndPostBuffer(bytes_read);
if (!result) {
// Failed to transfer data to UI thread.
return;
}
2016-09-21 15:35:03 +00:00
} while (request_->Read(buffer_.get(), kBufferSize, &bytes_read));
2016-09-21 15:35:03 +00:00
const auto status = request_->status();
if (!status.is_io_pending() /* TODO || request_type_ == URLFetcher::HEAD*/ ) {
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(&AtomURLRequest::InformDelegateResponseCompleted, this));
}
}
bool AtomURLRequest::CopyAndPostBuffer(int bytes_read) {
2016-09-21 15:35:03 +00:00
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// data is only a wrapper for the async buffer_.
// Make a deep copy of payload and transfer ownership to the UI thread.
scoped_refptr<net::IOBufferWithSize> buffer_copy(new net::IOBufferWithSize(bytes_read));
memcpy(buffer_copy->data(), buffer_->data(), bytes_read);
return content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::Bind(&AtomURLRequest::InformDelegateResponseData, this, buffer_copy));
}
2016-09-21 15:35:03 +00:00
void AtomURLRequest::InformDelegateAuthenticationRequired(
scoped_refptr<net::AuthChallengeInfo> auth_info) const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (delegate_) {
delegate_->OnAuthenticationRequired(auth_info);
}
}
void AtomURLRequest::InformDelegateResponseStarted() const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (delegate_) {
delegate_->OnResponseStarted();
}
}
2016-09-21 15:35:03 +00:00
void AtomURLRequest::InformDelegateResponseData(
scoped_refptr<net::IOBufferWithSize> data) const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Transfer ownership of the data buffer, data will be released
// by the delegate's OnResponseData.
if (delegate_) {
delegate_->OnResponseData(data);
}
}
2016-09-21 15:35:03 +00:00
void AtomURLRequest::InformDelegateResponseCompleted() const {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (delegate_) {
delegate_->OnResponseCompleted();
}
}
} // namespace atom