376 lines
11 KiB
C++
376 lines
11 KiB
C++
// Copyright (c) 2012 The Chromium Embedded Framework 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 "libcef/renderer/render_urlrequest_impl.h"
|
|
#include "libcef/common/request_impl.h"
|
|
#include "libcef/common/response_impl.h"
|
|
|
|
#include "base/logging.h"
|
|
#include "base/message_loop.h"
|
|
#include "third_party/WebKit/Source/Platform/chromium/public/Platform.h"
|
|
#include "third_party/WebKit/Source/Platform/chromium/public/WebString.h"
|
|
#include "third_party/WebKit/Source/Platform/chromium/public/WebURL.h"
|
|
#include "third_party/WebKit/Source/Platform/chromium/public/WebURLError.h"
|
|
#include "third_party/WebKit/Source/Platform/chromium/public/WebURLLoader.h"
|
|
#include "third_party/WebKit/Source/Platform/chromium/public/WebURLLoaderClient.h"
|
|
#include "third_party/WebKit/Source/Platform/chromium/public/WebURLRequest.h"
|
|
#include "third_party/WebKit/Source/Platform/chromium/public/WebURLResponse.h"
|
|
#include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h"
|
|
|
|
using WebKit::WebString;
|
|
using WebKit::WebURL;
|
|
using WebKit::WebURLError;
|
|
using WebKit::WebURLLoader;
|
|
using WebKit::WebURLRequest;
|
|
using WebKit::WebURLResponse;
|
|
|
|
|
|
namespace {
|
|
|
|
class CefWebURLLoaderClient : public WebKit::WebURLLoaderClient {
|
|
public:
|
|
CefWebURLLoaderClient(CefRenderURLRequest::Context* context,
|
|
int request_flags);
|
|
virtual ~CefWebURLLoaderClient();
|
|
|
|
// WebKit::WebURLLoaderClient methods.
|
|
virtual void willSendRequest(
|
|
WebURLLoader* loader,
|
|
WebURLRequest& newRequest,
|
|
const WebURLResponse& redirectResponse) OVERRIDE;
|
|
virtual void didSendData(
|
|
WebURLLoader* loader,
|
|
unsigned long long bytesSent,
|
|
unsigned long long totalBytesToBeSent) OVERRIDE;
|
|
virtual void didReceiveResponse(
|
|
WebURLLoader* loader,
|
|
const WebURLResponse& response) OVERRIDE;
|
|
virtual void didDownloadData(WebURLLoader* loader,
|
|
int dataLength) OVERRIDE;
|
|
virtual void didReceiveData(WebURLLoader* loader,
|
|
const char* data,
|
|
int dataLength,
|
|
int encodedDataLength) OVERRIDE;
|
|
virtual void didReceiveCachedMetadata(WebURLLoader* loader,
|
|
const char* data,
|
|
int dataLength) OVERRIDE;
|
|
virtual void didFinishLoading(WebURLLoader* loader,
|
|
double finishTime) OVERRIDE;
|
|
virtual void didFail(WebURLLoader* loader,
|
|
const WebURLError& error) OVERRIDE;
|
|
|
|
protected:
|
|
// The context_ pointer will outlive this object.
|
|
CefRenderURLRequest::Context* context_;
|
|
int request_flags_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
// CefRenderURLRequest::Context -----------------------------------------------
|
|
|
|
class CefRenderURLRequest::Context
|
|
: public base::RefCountedThreadSafe<CefRenderURLRequest::Context> {
|
|
public:
|
|
Context(CefRefPtr<CefRenderURLRequest> url_request,
|
|
CefRefPtr<CefRequest> request,
|
|
CefRefPtr<CefURLRequestClient> client)
|
|
: url_request_(url_request),
|
|
request_(request),
|
|
client_(client),
|
|
message_loop_proxy_(MessageLoop::current()->message_loop_proxy()),
|
|
status_(UR_IO_PENDING),
|
|
error_code_(ERR_NONE),
|
|
upload_data_size_(0),
|
|
got_upload_progress_complete_(false),
|
|
download_data_received_(0),
|
|
download_data_total_(-1) {
|
|
// Mark the request as read-only.
|
|
static_cast<CefRequestImpl*>(request_.get())->SetReadOnly(true);
|
|
}
|
|
|
|
virtual ~Context() {
|
|
}
|
|
|
|
inline bool CalledOnValidThread() {
|
|
return message_loop_proxy_->BelongsToCurrentThread();
|
|
}
|
|
|
|
bool Start() {
|
|
DCHECK(CalledOnValidThread());
|
|
|
|
GURL url = GURL(request_->GetURL().ToString());
|
|
if (!url.is_valid())
|
|
return false;
|
|
|
|
loader_.reset(WebKit::webKitPlatformSupport()->createURLLoader());
|
|
url_client_.reset(new CefWebURLLoaderClient(this, request_->GetFlags()));
|
|
|
|
WebURLRequest urlRequest;
|
|
static_cast<CefRequestImpl*>(request_.get())->Get(urlRequest);
|
|
|
|
if (urlRequest.reportUploadProgress()) {
|
|
// Attempt to determine the upload data size.
|
|
CefRefPtr<CefPostData> post_data = request_->GetPostData();
|
|
if (post_data.get()) {
|
|
CefPostData::ElementVector elements;
|
|
post_data->GetElements(elements);
|
|
if (elements.size() == 1 && elements[0]->GetType() == PDE_TYPE_BYTES) {
|
|
CefPostDataElementImpl* impl =
|
|
static_cast<CefPostDataElementImpl*>(elements[0].get());
|
|
upload_data_size_ = impl->GetBytesCount();
|
|
}
|
|
}
|
|
}
|
|
|
|
loader_->loadAsynchronously(urlRequest, url_client_.get());
|
|
return true;
|
|
}
|
|
|
|
void Cancel() {
|
|
DCHECK(CalledOnValidThread());
|
|
|
|
// The request may already be complete.
|
|
if (!loader_.get() || status_ != UR_IO_PENDING)
|
|
return;
|
|
|
|
status_ = UR_CANCELED;
|
|
error_code_ = ERR_ABORTED;
|
|
|
|
// Will result in a call to OnError().
|
|
loader_->cancel();
|
|
}
|
|
|
|
void OnResponse(const WebURLResponse& response) {
|
|
DCHECK(CalledOnValidThread());
|
|
|
|
response_ = CefResponse::Create();
|
|
CefResponseImpl* responseImpl =
|
|
static_cast<CefResponseImpl*>(response_.get());
|
|
responseImpl->Set(response);
|
|
responseImpl->SetReadOnly(true);
|
|
|
|
download_data_total_ = response.expectedContentLength();
|
|
}
|
|
|
|
void OnError(const WebURLError& error) {
|
|
DCHECK(CalledOnValidThread());
|
|
|
|
if (status_ == UR_IO_PENDING) {
|
|
status_ = UR_FAILED;
|
|
error_code_ = static_cast<CefURLRequest::ErrorCode>(error.reason);
|
|
}
|
|
|
|
OnComplete();
|
|
}
|
|
|
|
void OnComplete() {
|
|
DCHECK(CalledOnValidThread());
|
|
|
|
if (status_ == UR_IO_PENDING) {
|
|
status_ = UR_SUCCESS;
|
|
NotifyUploadProgressIfNecessary();
|
|
}
|
|
|
|
if (loader_.get())
|
|
loader_.reset(NULL);
|
|
|
|
DCHECK(url_request_.get());
|
|
client_->OnRequestComplete(url_request_.get());
|
|
|
|
// This may result in the Context object being deleted.
|
|
url_request_ = NULL;
|
|
}
|
|
|
|
void OnDownloadProgress(int64 current) {
|
|
DCHECK(CalledOnValidThread());
|
|
DCHECK(url_request_.get());
|
|
|
|
NotifyUploadProgressIfNecessary();
|
|
|
|
download_data_received_ += current;
|
|
client_->OnDownloadProgress(url_request_.get(), download_data_received_,
|
|
download_data_total_);
|
|
}
|
|
|
|
void OnDownloadData(const char* data, int dataLength) {
|
|
DCHECK(CalledOnValidThread());
|
|
DCHECK(url_request_.get());
|
|
client_->OnDownloadData(url_request_.get(), data, dataLength);
|
|
}
|
|
|
|
void OnUploadProgress(int64 current, int64 total) {
|
|
DCHECK(CalledOnValidThread());
|
|
DCHECK(url_request_.get());
|
|
if (current == total)
|
|
got_upload_progress_complete_ = true;
|
|
client_->OnUploadProgress(url_request_.get(), current, total);
|
|
}
|
|
|
|
CefRefPtr<CefRequest> request() { return request_; }
|
|
CefRefPtr<CefURLRequestClient> client() { return client_; }
|
|
CefURLRequest::Status status() { return status_; }
|
|
CefURLRequest::ErrorCode error_code() { return error_code_; }
|
|
CefRefPtr<CefResponse> response() { return response_; }
|
|
|
|
private:
|
|
void NotifyUploadProgressIfNecessary() {
|
|
if (!got_upload_progress_complete_ && upload_data_size_ > 0) {
|
|
// URLFetcher sends upload notifications using a timer and will not send
|
|
// a notification if the request completes too quickly. We therefore
|
|
// send the notification here if necessary.
|
|
client_->OnUploadProgress(url_request_.get(), upload_data_size_,
|
|
upload_data_size_);
|
|
got_upload_progress_complete_ = true;
|
|
}
|
|
}
|
|
|
|
// Members only accessed on the initialization thread.
|
|
CefRefPtr<CefRenderURLRequest> url_request_;
|
|
CefRefPtr<CefRequest> request_;
|
|
CefRefPtr<CefURLRequestClient> client_;
|
|
scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
|
|
CefURLRequest::Status status_;
|
|
CefURLRequest::ErrorCode error_code_;
|
|
CefRefPtr<CefResponse> response_;
|
|
scoped_ptr<WebKit::WebURLLoader> loader_;
|
|
scoped_ptr<CefWebURLLoaderClient> url_client_;
|
|
int64 upload_data_size_;
|
|
bool got_upload_progress_complete_;
|
|
int64 download_data_received_;
|
|
int64 download_data_total_;
|
|
};
|
|
|
|
|
|
// CefWebURLLoaderClient --------------------------------------------------
|
|
|
|
namespace {
|
|
|
|
CefWebURLLoaderClient::CefWebURLLoaderClient(
|
|
CefRenderURLRequest::Context* context,
|
|
int request_flags)
|
|
: context_(context),
|
|
request_flags_(request_flags) {
|
|
}
|
|
|
|
CefWebURLLoaderClient::~CefWebURLLoaderClient() {
|
|
}
|
|
|
|
void CefWebURLLoaderClient::willSendRequest(
|
|
WebURLLoader* loader,
|
|
WebURLRequest& newRequest,
|
|
const WebURLResponse& redirectResponse) {
|
|
}
|
|
|
|
void CefWebURLLoaderClient::didSendData(
|
|
WebURLLoader* loader,
|
|
unsigned long long bytesSent,
|
|
unsigned long long totalBytesToBeSent) {
|
|
if (request_flags_ & UR_FLAG_REPORT_UPLOAD_PROGRESS)
|
|
context_->OnUploadProgress(bytesSent, totalBytesToBeSent);
|
|
}
|
|
|
|
void CefWebURLLoaderClient::didReceiveResponse(
|
|
WebURLLoader* loader,
|
|
const WebURLResponse& response) {
|
|
context_->OnResponse(response);
|
|
}
|
|
|
|
void CefWebURLLoaderClient::didDownloadData(WebURLLoader* loader,
|
|
int dataLength) {
|
|
}
|
|
|
|
void CefWebURLLoaderClient::didReceiveData(WebURLLoader* loader,
|
|
const char* data,
|
|
int dataLength,
|
|
int encodedDataLength) {
|
|
context_->OnDownloadProgress(dataLength);
|
|
|
|
if (!(request_flags_ & UR_FLAG_NO_DOWNLOAD_DATA))
|
|
context_->OnDownloadData(data, dataLength);
|
|
}
|
|
|
|
void CefWebURLLoaderClient::didReceiveCachedMetadata(WebURLLoader* loader,
|
|
const char* data,
|
|
int dataLength) {
|
|
}
|
|
|
|
void CefWebURLLoaderClient::didFinishLoading(WebURLLoader* loader,
|
|
double finishTime) {
|
|
context_->OnComplete();
|
|
}
|
|
|
|
void CefWebURLLoaderClient::didFail(WebURLLoader* loader,
|
|
const WebURLError& error) {
|
|
context_->OnError(error);
|
|
}
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
// CefRenderURLRequest --------------------------------------------------------
|
|
|
|
CefRenderURLRequest::CefRenderURLRequest(
|
|
CefRefPtr<CefRequest> request,
|
|
CefRefPtr<CefURLRequestClient> client) {
|
|
context_ = new Context(this, request, client);
|
|
}
|
|
|
|
CefRenderURLRequest::~CefRenderURLRequest() {
|
|
}
|
|
|
|
bool CefRenderURLRequest::Start() {
|
|
if (!VerifyContext())
|
|
return false;
|
|
return context_->Start();
|
|
}
|
|
|
|
CefRefPtr<CefRequest> CefRenderURLRequest::GetRequest() {
|
|
if (!VerifyContext())
|
|
return NULL;
|
|
return context_->request();
|
|
}
|
|
|
|
CefRefPtr<CefURLRequestClient> CefRenderURLRequest::GetClient() {
|
|
if (!VerifyContext())
|
|
return NULL;
|
|
return context_->client();
|
|
}
|
|
|
|
CefURLRequest::Status CefRenderURLRequest::GetRequestStatus() {
|
|
if (!VerifyContext())
|
|
return UR_UNKNOWN;
|
|
return context_->status();
|
|
}
|
|
|
|
CefURLRequest::ErrorCode CefRenderURLRequest::GetRequestError() {
|
|
if (!VerifyContext())
|
|
return ERR_NONE;
|
|
return context_->error_code();
|
|
}
|
|
|
|
CefRefPtr<CefResponse> CefRenderURLRequest::GetResponse() {
|
|
if (!VerifyContext())
|
|
return NULL;
|
|
return context_->response();
|
|
}
|
|
|
|
void CefRenderURLRequest::Cancel() {
|
|
if (!VerifyContext())
|
|
return;
|
|
return context_->Cancel();
|
|
}
|
|
|
|
bool CefRenderURLRequest::VerifyContext() {
|
|
DCHECK(context_.get());
|
|
if (!context_->CalledOnValidThread()) {
|
|
NOTREACHED() << "called on invalid thread";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|