305 lines
8.7 KiB
C++
305 lines
8.7 KiB
C++
// Copyright (c) 2011 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/web_urlrequest_impl.h"
|
|
#include "libcef/browser_webkit_init.h"
|
|
#include "libcef/cef_thread.h"
|
|
#include "libcef/request_impl.h"
|
|
#include "libcef/response_impl.h"
|
|
|
|
#include "base/bind.h"
|
|
#include "base/logging.h"
|
|
#include "base/memory/scoped_ptr.h"
|
|
#include "googleurl/src/gurl.h"
|
|
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLError.h"
|
|
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLLoaderClient.h"
|
|
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLRequest.h"
|
|
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLResponse.h"
|
|
#include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h"
|
|
#include "webkit/glue/weburlloader_impl.h"
|
|
|
|
using WebKit::WebURLError;
|
|
using WebKit::WebURLLoader;
|
|
using WebKit::WebURLRequest;
|
|
using WebKit::WebURLResponse;
|
|
|
|
namespace {
|
|
class CefWebURLLoaderClientImpl;
|
|
};
|
|
|
|
// Manages the lifespan of WebKit objects. Methods of this class will only be
|
|
// called on the UI thread.
|
|
class CefWebURLRequestImpl::Context
|
|
: public base::RefCountedThreadSafe<CefWebURLRequestImpl::Context,
|
|
CefThread::DeleteOnUIThread> {
|
|
public:
|
|
explicit Context(CefRefPtr<CefWebURLRequestImpl> client)
|
|
: client_(client) {
|
|
}
|
|
virtual ~Context() {
|
|
}
|
|
|
|
void initialize(CefRefPtr<CefRequest> request);
|
|
void destroy();
|
|
void cancel();
|
|
|
|
CefRefPtr<CefWebURLRequestImpl> client() { return client_; }
|
|
|
|
protected:
|
|
CefRefPtr<CefWebURLRequestImpl> client_;
|
|
scoped_ptr<webkit_glue::WebURLLoaderImpl> url_loader_;
|
|
scoped_ptr<CefWebURLLoaderClientImpl> url_client_;
|
|
};
|
|
|
|
|
|
namespace {
|
|
|
|
// Implements the WebURLLoaderClient interface. Methods of this class will only
|
|
// be called on the UI thread.
|
|
class CefWebURLLoaderClientImpl : public WebKit::WebURLLoaderClient {
|
|
public:
|
|
explicit CefWebURLLoaderClientImpl(CefWebURLRequestImpl::Context* context)
|
|
: context_(context) {
|
|
}
|
|
virtual ~CefWebURLLoaderClientImpl() {
|
|
}
|
|
|
|
// =====================================================================
|
|
// WebKit::WebURLLoaderClient API
|
|
//
|
|
|
|
// Called when following a redirect. |newRequest| contains the request
|
|
// generated by the redirect. The client may modify |newRequest|.
|
|
virtual void willSendRequest(WebKit::WebURLLoader*,
|
|
WebKit::WebURLRequest& newRequest,
|
|
const WebKit::WebURLResponse& redirectResponse) {
|
|
REQUIRE_UIT();
|
|
if (!context_)
|
|
return;
|
|
|
|
CefRefPtr<CefWebURLRequestImpl> client = context_->client();
|
|
if (client.get()) {
|
|
CefRefPtr<CefWebURLRequestClient> handler = client->GetHandler();
|
|
if (handler.get()) {
|
|
CefRefPtr<CefRequestImpl> cefRequest(new CefRequestImpl());
|
|
CefRefPtr<CefResponse> cefResponse(
|
|
new CefResponseImpl(redirectResponse));
|
|
|
|
cefRequest->Set(newRequest);
|
|
handler->OnRedirect(client.get(), cefRequest.get(), cefResponse);
|
|
cefRequest->Get(newRequest);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Called to report upload progress. The bytes reported correspond to
|
|
// the HTTP message body.
|
|
virtual void didSendData(
|
|
WebKit::WebURLLoader*,
|
|
unsigned long long bytesSent, // NOLINT(runtime/int)
|
|
unsigned long long totalBytesToBeSent) { // NOLINT(runtime/int)
|
|
REQUIRE_UIT();
|
|
if (!context_)
|
|
return;
|
|
|
|
CefRefPtr<CefWebURLRequestImpl> client = context_->client();
|
|
if (client.get()) {
|
|
CefRefPtr<CefWebURLRequestClient> handler = client->GetHandler();
|
|
if (handler.get())
|
|
handler->OnProgress(client.get(), bytesSent, totalBytesToBeSent);
|
|
}
|
|
}
|
|
|
|
// Called when response headers are received.
|
|
virtual void didReceiveResponse(WebKit::WebURLLoader*,
|
|
const WebKit::WebURLResponse& response) {
|
|
REQUIRE_UIT();
|
|
if (!context_)
|
|
return;
|
|
|
|
CefRefPtr<CefWebURLRequestImpl> client = context_->client();
|
|
if (client.get()) {
|
|
client->DoStateChange(WUR_STATE_HEADERS_RECEIVED);
|
|
CefRefPtr<CefWebURLRequestClient> handler = client->GetHandler();
|
|
if (handler.get()) {
|
|
CefRefPtr<CefResponse> cefResponse(new CefResponseImpl(response));
|
|
handler->OnHeadersReceived(client.get(), cefResponse);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Called when a chunk of response data is downloaded. This is only called
|
|
// if WebURLRequest's downloadToFile flag was set to true.
|
|
virtual void didDownloadData(WebKit::WebURLLoader*, int dataLength) {
|
|
NOTREACHED();
|
|
}
|
|
|
|
// Called when a chunk of response data is received.
|
|
virtual void didReceiveData(WebURLLoader*, const char* data, int dataLength,
|
|
int lengthReceived) {
|
|
REQUIRE_UIT();
|
|
if (!context_)
|
|
return;
|
|
|
|
CefRefPtr<CefWebURLRequestImpl> client = context_->client();
|
|
if (client.get()) {
|
|
client->DoStateChange(WUR_STATE_LOADING);
|
|
CefRefPtr<CefWebURLRequestClient> handler = client->GetHandler();
|
|
if (handler.get()) {
|
|
handler->OnData(client.get(), data, dataLength);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Called when a chunk of renderer-generated metadata is received from
|
|
// the cache.
|
|
virtual void didReceiveCachedMetadata(WebKit::WebURLLoader*, const char* data,
|
|
int dataLength) {
|
|
NOTREACHED();
|
|
}
|
|
|
|
// Called when the load completes successfully.
|
|
virtual void didFinishLoading(WebKit::WebURLLoader*, double finishTime) {
|
|
REQUIRE_UIT();
|
|
if (!context_)
|
|
return;
|
|
|
|
CefRefPtr<CefWebURLRequestImpl> client = context_->client();
|
|
if (client.get())
|
|
client->DoStateChange(WUR_STATE_DONE);
|
|
|
|
complete();
|
|
}
|
|
|
|
// Called when the load completes with an error.
|
|
virtual void didFail(WebKit::WebURLLoader*,
|
|
const WebKit::WebURLError& error) {
|
|
REQUIRE_UIT();
|
|
if (!context_)
|
|
return;
|
|
|
|
CefRefPtr<CefWebURLRequestImpl> client = context_->client();
|
|
if (client.get() && client->GetState() != WUR_STATE_ABORT) {
|
|
client->DoStateChange(WUR_STATE_ERROR);
|
|
CefRefPtr<CefWebURLRequestClient> handler = client->GetHandler();
|
|
if (handler.get()) {
|
|
handler->OnError(client.get(),
|
|
static_cast<CefWebURLRequestClient::ErrorCode>(error.reason));
|
|
}
|
|
}
|
|
|
|
complete();
|
|
}
|
|
|
|
void complete() {
|
|
context_->destroy();
|
|
context_ = NULL;
|
|
}
|
|
|
|
protected:
|
|
scoped_refptr<CefWebURLRequestImpl::Context> context_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
// CefWebURLManager
|
|
|
|
void CefWebURLRequestImpl::Context::initialize(
|
|
CefRefPtr<CefRequest> request) {
|
|
REQUIRE_UIT();
|
|
|
|
url_loader_.reset(
|
|
new webkit_glue::WebURLLoaderImpl(reinterpret_cast<BrowserWebKitInit*>(
|
|
WebKit::webKitPlatformSupport())));
|
|
url_client_.reset(new CefWebURLLoaderClientImpl(this));
|
|
|
|
WebURLRequest urlRequest;
|
|
static_cast<CefRequestImpl*>(request.get())->Get(urlRequest);
|
|
url_loader_->loadAsynchronously(urlRequest, url_client_.get());
|
|
}
|
|
|
|
void CefWebURLRequestImpl::Context::destroy() {
|
|
REQUIRE_UIT();
|
|
client_ = NULL;
|
|
}
|
|
|
|
void CefWebURLRequestImpl::Context::cancel() {
|
|
REQUIRE_UIT();
|
|
url_loader_->cancel();
|
|
url_client_->complete();
|
|
}
|
|
|
|
|
|
// CefWebURLRequest
|
|
|
|
// static
|
|
CefRefPtr<CefWebURLRequest>
|
|
CefWebURLRequest::CreateWebURLRequest(
|
|
CefRefPtr<CefRequest> request, CefRefPtr<CefWebURLRequestClient> client) {
|
|
CefRefPtr<CefWebURLRequestImpl> requester = new CefWebURLRequestImpl(client);
|
|
|
|
// Send the request from the UI thread.
|
|
CefThread::PostTask(CefThread::UI, FROM_HERE,
|
|
base::Bind(&CefWebURLRequestImpl::DoSend, requester.get(), request));
|
|
|
|
return requester.get();
|
|
}
|
|
|
|
|
|
// CefWebURLRequestImpl
|
|
|
|
CefWebURLRequestImpl::CefWebURLRequestImpl(
|
|
CefRefPtr<CefWebURLRequestClient> handler)
|
|
: handler_(handler),
|
|
state_(WUR_STATE_UNSENT) {
|
|
}
|
|
|
|
CefWebURLRequestImpl::~CefWebURLRequestImpl() {
|
|
}
|
|
|
|
CefWebURLRequestImpl::RequestState CefWebURLRequestImpl::GetState() {
|
|
AutoLock lock_scope(this);
|
|
return state_;
|
|
}
|
|
|
|
void CefWebURLRequestImpl::Cancel() {
|
|
CefThread::PostTask(CefThread::UI, FROM_HERE,
|
|
base::Bind(&CefWebURLRequestImpl::DoCancel, this));
|
|
}
|
|
|
|
void CefWebURLRequestImpl::DoSend(CefRefPtr<CefRequest> request) {
|
|
REQUIRE_UIT();
|
|
DCHECK(state_ == WUR_STATE_UNSENT);
|
|
|
|
context_ = new CefWebURLRequestImpl::Context(this);
|
|
context_->initialize(request);
|
|
|
|
DoStateChange(WUR_STATE_STARTED);
|
|
}
|
|
|
|
void CefWebURLRequestImpl::DoCancel() {
|
|
REQUIRE_UIT();
|
|
|
|
if (state_ < WUR_STATE_DONE) {
|
|
DoStateChange(WUR_STATE_ABORT);
|
|
context_->cancel();
|
|
}
|
|
}
|
|
|
|
void CefWebURLRequestImpl::DoStateChange(RequestState newState) {
|
|
REQUIRE_UIT();
|
|
|
|
if (state_ == newState)
|
|
return;
|
|
|
|
{
|
|
AutoLock lock_scope(this);
|
|
state_ = newState;
|
|
}
|
|
|
|
if (handler_.get())
|
|
handler_->OnStateChange(this, newState);
|
|
}
|