- Add download handling support via new CefDownloadHandler and CefDownloadItem interfaces (issue #516).

- Fix setting of CefKeyEvent.focus_on_editable_field when the underlying RenderViewHost changes.
- Fix potential crash if URLRequest objects are still in-progress upon shutdown.

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@715 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt
2012-06-28 17:21:18 +00:00
parent 14bbc90ddb
commit 421001ba9d
51 changed files with 2685 additions and 171 deletions

View File

@ -181,12 +181,14 @@ CefBrowserContext::CefBrowserContext() {
}
CefBrowserContext::~CefBrowserContext() {
if (download_manager_.get())
download_manager_->Shutdown();
// Clear the download manager delegate here because otherwise we'll crash
// when it's accessed from the content::BrowserContext destructor.
if (download_manager_delegate_.get())
BrowserContext::GetDownloadManager(this)->SetDelegate(NULL);
if (resource_context_.get()) {
BrowserThread::DeleteSoon(
BrowserThread::IO, FROM_HERE, resource_context_.release());
BrowserThread::IO, FROM_HERE, resource_context_.release());
}
}
@ -200,6 +202,8 @@ bool CefBrowserContext::IsOffTheRecord() const {
content::DownloadManagerDelegate*
CefBrowserContext::GetDownloadManagerDelegate() {
DCHECK(!download_manager_delegate_.get());
download_manager_delegate_ = new CefDownloadManagerDelegate();
return download_manager_delegate_.get();
}

View File

@ -14,11 +14,11 @@
namespace content {
class DownloadManagerDelegate;
class ResourceContext;
class SpeechRecognitionPreferences;
}
class CefDownloadManagerDelegate;
class CefResourceContext;
class CefBrowserContext : public content::BrowserContext {
public:
@ -43,9 +43,8 @@ class CefBrowserContext : public content::BrowserContext {
private:
scoped_ptr<content::ResourceContext> resource_context_;
scoped_ptr<CefResourceContext> resource_context_;
scoped_refptr<CefDownloadManagerDelegate> download_manager_delegate_;
scoped_refptr<content::DownloadManager> download_manager_;
scoped_refptr<net::URLRequestContextGetter> url_request_getter_;
scoped_refptr<content::GeolocationPermissionContext>
geolocation_permission_context_;

View File

@ -13,6 +13,8 @@
#include "libcef/browser/devtools_delegate.h"
#include "libcef/browser/navigate_params.h"
#include "libcef/browser/thread_util.h"
#include "libcef/browser/url_request_context_getter.h"
#include "libcef/browser/url_request_context_getter_proxy.h"
#include "libcef/common/cef_messages.h"
#include "libcef/common/http_header_utils.h"
#include "libcef/common/main_delegate.h"
@ -600,7 +602,8 @@ net::URLRequestContextGetter* CefBrowserHostImpl::GetRequestContext() {
if (!request_context_proxy_) {
request_context_proxy_ =
new CefURLRequestContextGetterProxy(this,
_Context->browser_context()->GetRequestContext());
static_cast<CefURLRequestContextGetter*>(
_Context->browser_context()->GetRequestContext()));
}
return request_context_proxy_.get();
}
@ -1128,19 +1131,13 @@ void CefBrowserHostImpl::RequestMediaAccessPermission(
void CefBrowserHostImpl::RenderViewCreated(
content::RenderViewHost* render_view_host) {
base::AutoLock lock_scope(state_lock_);
SetRenderViewHost(render_view_host);
}
render_view_id_ = render_view_host->GetRoutingID();
render_process_id_ = render_view_host->GetProcess()->GetID();
// Update the DevTools URLs, if any.
CefDevToolsDelegate* devtools_delegate = _Context->devtools_delegate();
if (devtools_delegate) {
devtools_url_http_ = devtools_delegate->GetDevToolsURL(render_view_host,
true);
devtools_url_chrome_ = devtools_delegate->GetDevToolsURL(render_view_host,
false);
}
void CefBrowserHostImpl::RenderViewDeleted(
content::RenderViewHost* render_view_host) {
registrar_->Remove(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
content::Source<content::RenderViewHost>(render_view_host));
}
void CefBrowserHostImpl::RenderViewReady() {
@ -1368,8 +1365,8 @@ CefBrowserHostImpl::CefBrowserHostImpl(const CefWindowInfo& window_info,
settings_(settings),
client_(client),
opener_(opener),
render_process_id_(web_contents->GetRenderProcessHost()->GetID()),
render_view_id_(routing_id()),
render_process_id_(0),
render_view_id_(0),
unique_id_(0),
received_page_title_(false),
is_loading_(false),
@ -1387,21 +1384,35 @@ CefBrowserHostImpl::CefBrowserHostImpl(const CefWindowInfo& window_info,
registrar_.reset(new content::NotificationRegistrar);
registrar_->Add(this, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
content::Source<content::WebContents>(web_contents));
registrar_->Add(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
content::Source<content::RenderViewHost>(
web_contents->GetRenderViewHost()));
response_manager_.reset(new CefResponseManager);
placeholder_frame_ =
new CefFrameHostImpl(this, CefFrameHostImpl::kInvalidFrameId, true);
// Retrieve the DevTools URLs, if any.
CefDevToolsDelegate* devtools_delegate = _Context->devtools_delegate();
if (devtools_delegate) {
devtools_url_http_ = devtools_delegate->GetDevToolsURL(
web_contents->GetRenderViewHost(), true);
devtools_url_chrome_ = devtools_delegate->GetDevToolsURL(
web_contents->GetRenderViewHost(), false);
SetRenderViewHost(web_contents->GetRenderViewHost());
}
void CefBrowserHostImpl::SetRenderViewHost(content::RenderViewHost* rvh) {
{
base::AutoLock lock_scope(state_lock_);
render_view_id_ = rvh->GetRoutingID();
render_process_id_ = rvh->GetProcess()->GetID();
// Update the DevTools URLs, if any.
CefDevToolsDelegate* devtools_delegate = _Context->devtools_delegate();
if (devtools_delegate) {
devtools_url_http_ = devtools_delegate->GetDevToolsURL(rvh, true);
devtools_url_chrome_ = devtools_delegate->GetDevToolsURL(rvh, false);
}
}
if (!registrar_->IsRegistered(
this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
content::Source<content::RenderViewHost>(rvh))) {
registrar_->Add(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
content::Source<content::RenderViewHost>(rvh));
}
}

View File

@ -18,7 +18,6 @@
#include "libcef/browser/frame_host_impl.h"
#include "libcef/browser/javascript_dialog_creator.h"
#include "libcef/browser/menu_creator.h"
#include "libcef/browser/url_request_context_getter_proxy.h"
#include "libcef/common/response_manager.h"
#include "base/memory/scoped_ptr.h"
@ -29,6 +28,7 @@
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "net/url_request/url_request_context_getter.h"
namespace content {
struct NativeWebKeyboardEvent;
@ -239,8 +239,10 @@ class CefBrowserHostImpl : public CefBrowserHost,
const content::MediaResponseCallback& callback) OVERRIDE;
// content::WebContentsObserver methods.
virtual void RenderViewCreated(content::RenderViewHost* render_view_host)
OVERRIDE;
virtual void RenderViewCreated(
content::RenderViewHost* render_view_host) OVERRIDE;
virtual void RenderViewDeleted(
content::RenderViewHost* render_view_host) OVERRIDE;
virtual void RenderViewReady() OVERRIDE;
virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE;
virtual void DidCommitProvisionalLoadForFrame(
@ -288,6 +290,9 @@ class CefBrowserHostImpl : public CefBrowserHost,
content::WebContents* web_contents,
CefWindowHandle opener);
// Initialize settings based on the specified RenderViewHost.
void SetRenderViewHost(content::RenderViewHost* rvh);
// Updates and returns an existing frame or creates a new frame. Pass
// CefFrameHostImpl::kUnspecifiedFrameId for |parent_frame_id| if unknown.
CefRefPtr<CefFrame> GetOrCreateFrame(int64 frame_id,
@ -404,7 +409,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
scoped_ptr<content::NotificationRegistrar> registrar_;
// Used for proxying cookie requests.
scoped_refptr<CefURLRequestContextGetterProxy> request_context_proxy_;
scoped_refptr<net::URLRequestContextGetter> request_context_proxy_;
// Manages response registrations.
scoped_ptr<CefResponseManager> response_manager_;

View File

@ -54,18 +54,19 @@ void CefBrowserMainParts::PreMainMessageLoopStart() {
}
int CefBrowserMainParts::PreCreateThreads() {
PlatformInitialize();
net::NetModule::SetResourceProvider(&ResourceProvider);
// Initialize the GpuDataManager before IO access restrictions are applied and
// before the IO thread is started.
content::GpuDataManager::GetInstance();
return 0;
}
void CefBrowserMainParts::PreMainMessageLoopRun() {
browser_context_.reset(new CefBrowserContext());
PlatformInitialize();
net::NetModule::SetResourceProvider(&ResourceProvider);
// Initialize the GpuDataManager before IO access restrictions are applied.
content::GpuDataManager::GetInstance();
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kRemoteDebuggingPort)) {
std::string port_str =
@ -82,13 +83,11 @@ void CefBrowserMainParts::PreMainMessageLoopRun() {
}
void CefBrowserMainParts::PostMainMessageLoopRun() {
PlatformCleanup();
if (devtools_delegate_)
devtools_delegate_->Stop();
browser_context_.reset();
}
bool CefBrowserMainParts::MainMessageLoopRun(int* result_code) {
return false;
void CefBrowserMainParts::PostDestroyThreads() {
PlatformCleanup();
}

View File

@ -31,8 +31,8 @@ class CefBrowserMainParts : public content::BrowserMainParts {
virtual void PreMainMessageLoopStart() OVERRIDE;
virtual int PreCreateThreads() OVERRIDE;
virtual void PreMainMessageLoopRun() OVERRIDE;
virtual bool MainMessageLoopRun(int* result_code) OVERRIDE;
virtual void PostMainMessageLoopRun() OVERRIDE;
virtual void PostDestroyThreads() OVERRIDE;
CefBrowserContext* browser_context() const { return browser_context_.get(); }
CefDevToolsDelegate* devtools_delegate() const { return devtools_delegate_; }

View File

@ -0,0 +1,107 @@
// 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/browser/download_item_impl.h"
#include "libcef/common/time_util.h"
#include "content/public/browser/download_item.h"
#include "googleurl/src/gurl.h"
CefDownloadItemImpl::CefDownloadItemImpl(content::DownloadItem* value)
: CefValueBase<CefDownloadItem, content::DownloadItem>(
value, NULL, kOwnerNoDelete, true,
new CefValueControllerNonThreadSafe()) {
// Indicate that this object owns the controller.
SetOwnsController();
}
bool CefDownloadItemImpl::IsValid() {
return !detached();
}
bool CefDownloadItemImpl::IsInProgress() {
CEF_VALUE_VERIFY_RETURN(false, false);
return const_value().IsInProgress();
}
bool CefDownloadItemImpl::IsComplete() {
CEF_VALUE_VERIFY_RETURN(false, false);
return const_value().IsComplete();
}
bool CefDownloadItemImpl::IsCanceled() {
CEF_VALUE_VERIFY_RETURN(false, false);
return const_value().IsCancelled();
}
int64 CefDownloadItemImpl::GetCurrentSpeed() {
CEF_VALUE_VERIFY_RETURN(false, 0);
return const_value().CurrentSpeed();
}
int CefDownloadItemImpl::GetPercentComplete() {
CEF_VALUE_VERIFY_RETURN(false, -1);
return const_value().PercentComplete();
}
int64 CefDownloadItemImpl::GetTotalBytes() {
CEF_VALUE_VERIFY_RETURN(false, 0);
return const_value().GetTotalBytes();
}
int64 CefDownloadItemImpl::GetReceivedBytes() {
CEF_VALUE_VERIFY_RETURN(false, 0);
return const_value().GetReceivedBytes();
}
CefTime CefDownloadItemImpl::GetStartTime() {
CefTime time;
CEF_VALUE_VERIFY_RETURN(false, time);
cef_time_from_basetime(const_value().GetStartTime(), time);
return time;
}
CefTime CefDownloadItemImpl::GetEndTime() {
CefTime time;
CEF_VALUE_VERIFY_RETURN(false, time);
cef_time_from_basetime(const_value().GetEndTime(), time);
return time;
}
CefString CefDownloadItemImpl::GetFullPath() {
CEF_VALUE_VERIFY_RETURN(false, CefString());
return const_value().GetFullPath().value();
}
int32 CefDownloadItemImpl::GetId() {
CEF_VALUE_VERIFY_RETURN(false, 0);
return const_value().GetId();
}
CefString CefDownloadItemImpl::GetURL() {
CEF_VALUE_VERIFY_RETURN(false, CefString());
return const_value().GetURL().spec();
}
CefString CefDownloadItemImpl::GetSuggestedFileName() {
CEF_VALUE_VERIFY_RETURN(false, CefString());
return const_value().GetSuggestedFilename();
}
CefString CefDownloadItemImpl::GetContentDisposition() {
CEF_VALUE_VERIFY_RETURN(false, CefString());
return const_value().GetContentDisposition();
}
CefString CefDownloadItemImpl::GetMimeType() {
CEF_VALUE_VERIFY_RETURN(false, CefString());
return const_value().GetMimeType();
}
CefString CefDownloadItemImpl::GetReferrerCharset() {
CEF_VALUE_VERIFY_RETURN(false, CefString());
return const_value().GetReferrerCharset();
}

View File

@ -0,0 +1,45 @@
// 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.
#ifndef CEF_LIBCEF_BROWSER_DOWNLOAD_ITEM_IMPL_H_
#define CEF_LIBCEF_BROWSER_DOWNLOAD_ITEM_IMPL_H_
#pragma once
#include "include/cef_download_item.h"
#include "libcef/common/value_base.h"
namespace content {
class DownloadItem;
}
// CefDownloadItem implementation
class CefDownloadItemImpl
: public CefValueBase<CefDownloadItem, content::DownloadItem> {
public:
explicit CefDownloadItemImpl(content::DownloadItem* value);
// CefDownloadItem methods.
virtual bool IsValid() OVERRIDE;
virtual bool IsInProgress() OVERRIDE;
virtual bool IsComplete() OVERRIDE;
virtual bool IsCanceled() OVERRIDE;
virtual int64 GetCurrentSpeed() OVERRIDE;
virtual int GetPercentComplete() OVERRIDE;
virtual int64 GetTotalBytes() OVERRIDE;
virtual int64 GetReceivedBytes() OVERRIDE;
virtual CefTime GetStartTime() OVERRIDE;
virtual CefTime GetEndTime() OVERRIDE;
virtual CefString GetFullPath() OVERRIDE;
virtual int32 GetId() OVERRIDE;
virtual CefString GetURL() OVERRIDE;
virtual CefString GetSuggestedFileName() OVERRIDE;
virtual CefString GetContentDisposition() OVERRIDE;
virtual CefString GetMimeType() OVERRIDE;
virtual CefString GetReferrerCharset() OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(CefDownloadItemImpl);
};
#endif // CEF_LIBCEF_BROWSER_DOWNLOAD_ITEM_IMPL_H_

View File

@ -4,65 +4,226 @@
#include "libcef/browser/download_manager_delegate.h"
#if defined(OS_WIN)
#include <windows.h>
#include <commdlg.h>
#endif
#include "include/cef_download_handler.h"
#include "libcef/browser/browser_context.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/context.h"
#include "libcef/browser/download_item_impl.h"
#include "libcef/browser/thread_util.h"
#include "base/bind.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/web_contents.h"
#include "net/base/net_util.h"
using content::BrowserThread;
using content::DownloadItem;
using content::DownloadManager;
using content::WebContents;
CefDownloadManagerDelegate::CefDownloadManagerDelegate()
: download_manager_(NULL) {
namespace {
// Helper function to retrieve the CefBrowserHostImpl.
CefRefPtr<CefBrowserHostImpl> GetBrowser(DownloadItem* item) {
content::WebContents* contents = item->GetWebContents();
if (!contents)
return NULL;
return CefBrowserHostImpl::GetBrowserForContents(contents).get();
}
// Helper function to retrieve the CefDownloadHandler.
CefRefPtr<CefDownloadHandler> GetDownloadHandler(
CefRefPtr<CefBrowserHostImpl> browser) {
CefRefPtr<CefClient> client = browser->GetClient();
if (client.get())
return client->GetDownloadHandler();
return NULL;
}
// Helper function to retrieve the DownloadManager.
scoped_refptr<content::DownloadManager> GetDownloadManager() {
return content::BrowserContext::GetDownloadManager(
_Context->browser_context());
}
// CefBeforeDownloadCallback implementation.
class CefBeforeDownloadCallbackImpl : public CefBeforeDownloadCallback {
public:
CefBeforeDownloadCallbackImpl(int32 download_id,
const FilePath& suggested_name)
: download_id_(download_id),
suggested_name_(suggested_name) {
}
virtual void Continue(const CefString& download_path,
bool show_dialog) OVERRIDE {
if (CEF_CURRENTLY_ON_UIT()) {
if (download_id_ <= 0)
return;
scoped_refptr<content::DownloadManager> manager = GetDownloadManager();
if (manager) {
FilePath path = FilePath(download_path);
CEF_POST_TASK(CEF_FILET,
base::Bind(&CefBeforeDownloadCallbackImpl::GenerateFilename,
download_id_, suggested_name_, path, show_dialog));
}
download_id_ = 0;
} else {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBeforeDownloadCallbackImpl::Continue, this,
download_path, show_dialog));
}
}
private:
static void GenerateFilename(int32 download_id,
const FilePath& suggested_name,
const FilePath& download_path,
bool show_dialog) {
FilePath suggested_path = download_path;
if (!suggested_path.empty()) {
// Create the directory if necessary.
FilePath dir_path = suggested_path.DirName();
if (!file_util::DirectoryExists(dir_path) &&
!file_util::CreateDirectory(dir_path)) {
NOTREACHED() << "failed to create the download directory";
suggested_path.clear();
}
}
if (suggested_path.empty()) {
if (PathService::Get(base::DIR_TEMP, &suggested_path)) {
// Use the temp directory.
suggested_path = suggested_path.Append(suggested_name);
} else {
// Use the current working directory.
suggested_path = suggested_name;
}
}
content::DownloadItem::TargetDisposition disposition = show_dialog ?
DownloadItem::TARGET_DISPOSITION_PROMPT :
DownloadItem::TARGET_DISPOSITION_OVERWRITE;
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBeforeDownloadCallbackImpl::RestartDownload,
download_id, suggested_path, disposition));
}
static void RestartDownload(int32 download_id,
const FilePath& suggested_path,
DownloadItem::TargetDisposition disposition) {
scoped_refptr<content::DownloadManager> manager = GetDownloadManager();
if (!manager)
return;
DownloadItem* item = manager->GetActiveDownloadItem(download_id);
if (!item)
return;
item->OnTargetPathDetermined(suggested_path,
disposition,
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
manager->RestartDownload(download_id);
}
int32 download_id_;
FilePath suggested_name_;
IMPLEMENT_REFCOUNTING(CefBeforeDownloadCallbackImpl);
DISALLOW_COPY_AND_ASSIGN(CefBeforeDownloadCallbackImpl);
};
// CefDownloadItemCallback implementation.
class CefDownloadItemCallbackImpl : public CefDownloadItemCallback {
public:
explicit CefDownloadItemCallbackImpl(int32 download_id)
: download_id_(download_id) {
}
virtual void Cancel() OVERRIDE {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefDownloadItemCallbackImpl::DoCancel, this));
}
private:
void DoCancel() {
if (download_id_ <= 0)
return;
scoped_refptr<content::DownloadManager> manager = GetDownloadManager();
if (manager) {
content::DownloadItem* item =
manager->GetActiveDownloadItem(download_id_);
if (item && item->IsInProgress())
item->Cancel(true);
}
download_id_ = 0;
}
int32 download_id_;
IMPLEMENT_REFCOUNTING(CefDownloadItemCallbackImpl);
DISALLOW_COPY_AND_ASSIGN(CefDownloadItemCallbackImpl);
};
} // namespace
CefDownloadManagerDelegate::CefDownloadManagerDelegate() {
}
CefDownloadManagerDelegate::~CefDownloadManagerDelegate() {
}
void CefDownloadManagerDelegate::SetDownloadManager(
DownloadManager* download_manager) {
download_manager_ = download_manager;
}
bool CefDownloadManagerDelegate::ShouldStartDownload(int32 download_id) {
DownloadItem* download =
download_manager_->GetActiveDownloadItem(download_id);
scoped_refptr<content::DownloadManager> manager = GetDownloadManager();
DownloadItem* item = manager->GetActiveDownloadItem(download_id);
if (!download->GetForcedFilePath().empty()) {
download->OnTargetPathDetermined(
download->GetForcedFilePath(),
if (!item->GetForcedFilePath().empty()) {
item->OnTargetPathDetermined(
item->GetForcedFilePath(),
DownloadItem::TARGET_DISPOSITION_OVERWRITE,
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
return true;
}
FilePath generated_name = net::GenerateFileName(
download->GetURL(),
download->GetContentDisposition(),
download->GetReferrerCharset(),
download->GetSuggestedFilename(),
download->GetMimeType(),
"download");
CefRefPtr<CefBrowserHostImpl> browser = GetBrowser(item);
CefRefPtr<CefDownloadHandler> handler;
if (browser.get())
handler = GetDownloadHandler(browser);
if (handler.get()) {
FilePath suggested_name = net::GenerateFileName(
item->GetURL(),
item->GetContentDisposition(),
item->GetReferrerCharset(),
item->GetSuggestedFilename(),
item->GetMimeType(),
"download");
CefRefPtr<CefDownloadItemImpl> download_item(new CefDownloadItemImpl(item));
CefRefPtr<CefBeforeDownloadCallback> callback(
new CefBeforeDownloadCallbackImpl(download_id, suggested_name));
handler->OnBeforeDownload(browser.get(), download_item.get(),
suggested_name.value(), callback);
download_item->Detach(NULL);
}
BrowserThread::PostTask(
BrowserThread::FILE,
FROM_HERE,
base::Bind(
&CefDownloadManagerDelegate::GenerateFilename,
this, download_id, generated_name));
return false;
}
@ -77,47 +238,35 @@ void CefDownloadManagerDelegate::ChooseDownloadPath(
NOTIMPLEMENTED();
#endif
scoped_refptr<content::DownloadManager> manager = GetDownloadManager();
if (result.empty()) {
download_manager_->FileSelectionCanceled(item->GetId());
manager->FileSelectionCanceled(item->GetId());
} else {
download_manager_->FileSelected(result, item->GetId());
manager->FileSelected(result, item->GetId());
}
}
void CefDownloadManagerDelegate::AddItemToPersistentStore(
content::DownloadItem* item) {
DownloadItem* item) {
static int next_id;
download_manager_->OnItemAddedToPersistentStore(item->GetId(), ++next_id);
scoped_refptr<content::DownloadManager> manager = GetDownloadManager();
manager->OnItemAddedToPersistentStore(item->GetId(), ++next_id);
}
void CefDownloadManagerDelegate::GenerateFilename(
int32 download_id,
const FilePath& generated_name) {
FilePath suggested_path = download_manager_->GetBrowserContext()->GetPath().
Append(FILE_PATH_LITERAL("Downloads"));
if (!file_util::DirectoryExists(suggested_path))
file_util::CreateDirectory(suggested_path);
void CefDownloadManagerDelegate::UpdateItemInPersistentStore(
DownloadItem* item) {
CefRefPtr<CefBrowserHostImpl> browser = GetBrowser(item);
CefRefPtr<CefDownloadHandler> handler;
if (browser.get())
handler = GetDownloadHandler(browser);
suggested_path = suggested_path.Append(generated_name);
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(
&CefDownloadManagerDelegate::RestartDownload,
this, download_id, suggested_path));
}
void CefDownloadManagerDelegate::RestartDownload(
int32 download_id,
const FilePath& suggested_path) {
DownloadItem* download =
download_manager_->GetActiveDownloadItem(download_id);
if (!download)
return;
// Since we have no download UI, show the user a dialog always.
download->OnTargetPathDetermined(suggested_path,
DownloadItem::TARGET_DISPOSITION_PROMPT,
content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
download_manager_->RestartDownload(download_id);
if (handler.get()) {
CefRefPtr<CefDownloadItemImpl> download_item(new CefDownloadItemImpl(item));
CefRefPtr<CefDownloadItemCallback> callback(
new CefDownloadItemCallbackImpl(item->GetId()));
handler->OnDownloadUpdated(browser.get(), download_item.get(), callback);
download_item->Detach(NULL);
}
}

View File

@ -22,28 +22,21 @@ class CefDownloadManagerDelegate
public:
CefDownloadManagerDelegate();
void SetDownloadManager(content::DownloadManager* manager);
// DownloadManagerDelegate methods.
virtual bool ShouldStartDownload(int32 download_id) OVERRIDE;
virtual void ChooseDownloadPath(content::DownloadItem* item) OVERRIDE;
virtual void AddItemToPersistentStore(content::DownloadItem* item) OVERRIDE;
virtual void UpdateItemInPersistentStore(
content::DownloadItem* item) OVERRIDE;
private:
friend class base::RefCountedThreadSafe<CefDownloadManagerDelegate>;
virtual ~CefDownloadManagerDelegate();
void GenerateFilename(int32 download_id,
const FilePath& generated_name);
void RestartDownload(int32 download_id,
const FilePath& suggested_path);
FilePath PlatformChooseDownloadPath(content::WebContents* web_contents,
const FilePath& suggested_path);
content::DownloadManager* download_manager_;
DISALLOW_COPY_AND_ASSIGN(CefDownloadManagerDelegate);
};

View File

@ -12,6 +12,11 @@ CefResourceContext::CefResourceContext(
}
CefResourceContext::~CefResourceContext() {
// Destroy the getter after content::ResourceContext has finished destructing.
// Otherwise, the URLRequestContext objects will be deleted before
// ResourceDispatcherHost has canceled any pending URLRequests.
content::BrowserThread::ReleaseSoon(
content::BrowserThread::IO, FROM_HERE, getter_.release());
}
net::HostResolver* CefResourceContext::GetHostResolver() {

View File

@ -13,10 +13,12 @@
#include "libcef/browser/context.h"
#include "libcef/browser/thread_util.h"
#include "libcef/browser/url_network_delegate.h"
#include "libcef/browser/url_request_context_proxy.h"
#include "libcef/browser/url_request_interceptor.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/string_split.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/worker_pool.h"
@ -137,6 +139,7 @@ CefURLRequestContextGetter::CefURLRequestContextGetter(
}
CefURLRequestContextGetter::~CefURLRequestContextGetter() {
STLDeleteElements(&url_request_context_proxies_);
}
net::URLRequestContext* CefURLRequestContextGetter::GetURLRequestContext() {
@ -353,6 +356,51 @@ void CefURLRequestContextGetter::SetCookieSupportedSchemes(
delete [] arr;
}
CefURLRequestContextProxy*
CefURLRequestContextGetter::CreateURLRequestContextProxy() {
CEF_REQUIRE_IOT();
CefURLRequestContextProxy* proxy = new CefURLRequestContextProxy(this);
url_request_context_proxies_.insert(proxy);
return proxy;
}
void CefURLRequestContextGetter::ReleaseURLRequestContextProxy(
CefURLRequestContextProxy* proxy) {
CEF_REQUIRE_IOT();
// Don't do anything if we're currently shutting down. The proxy objects will
// be deleted when this object is destroyed.
if (_Context->shutting_down())
return;
if (proxy->url_requests()->size() == 0) {
// Safe to delete the proxy.
RequestContextProxySet::iterator it =
url_request_context_proxies_.find(proxy);
DCHECK(it != url_request_context_proxies_.end());
url_request_context_proxies_.erase(it);
delete proxy;
} else {
proxy->increment_delete_try_count();
if (proxy->delete_try_count() <= 1) {
// Cancel the pending requests. This may result in additional tasks being
// posted on the IO thread.
std::set<const net::URLRequest*>::iterator it =
proxy->url_requests()->begin();
for (; it != proxy->url_requests()->end(); ++it)
const_cast<net::URLRequest*>(*it)->Cancel();
// Try to delete the proxy again later.
CEF_POST_TASK(CEF_IOT,
base::Bind(&CefURLRequestContextGetter::ReleaseURLRequestContextProxy,
this, proxy));
} else {
NOTREACHED() <<
"too many retries to delete URLRequestContext proxy object";
}
}
}
void CefURLRequestContextGetter::CreateProxyConfigService() {
if (proxy_config_service_.get())
return;

View File

@ -6,6 +6,7 @@
#define CEF_LIBCEF_BROWSER_URL_REQUEST_CONTEXT_GETTER_H_
#pragma once
#include <set>
#include <string>
#include <vector>
@ -16,6 +17,7 @@
#include "net/url_request/url_request_context_getter.h"
class CefRequestInterceptor;
class CefURLRequestContextProxy;
class MessageLoop;
namespace net {
@ -44,6 +46,12 @@ class CefURLRequestContextGetter : public net::URLRequestContextGetter {
void SetCookieStoragePath(const FilePath& path);
void SetCookieSupportedSchemes(const std::vector<std::string>& schemes);
// Manage URLRequestContext proxy objects. It's important that proxy objects
// not be destroyed while any in-flight URLRequests exist. These methods
// manage that requirement.
CefURLRequestContextProxy* CreateURLRequestContextProxy();
void ReleaseURLRequestContextProxy(CefURLRequestContextProxy* proxy);
private:
void CreateProxyConfigService();
@ -57,6 +65,9 @@ class CefURLRequestContextGetter : public net::URLRequestContextGetter {
scoped_ptr<net::URLRequestContext> url_request_context_;
scoped_ptr<net::URLSecurityManager> url_security_manager_;
typedef std::set<CefURLRequestContextProxy*> RequestContextProxySet;
RequestContextProxySet url_request_context_proxies_;
FilePath cookie_store_path_;
std::vector<std::string> cookie_supported_schemes_;

View File

@ -9,6 +9,8 @@
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/cookie_manager_impl.h"
#include "libcef/browser/thread_util.h"
#include "libcef/browser/url_request_context_getter.h"
#include "libcef/browser/url_request_context_proxy.h"
#include "base/logging.h"
#include "base/message_loop_proxy.h"
@ -117,69 +119,32 @@ class CefCookieStoreProxy : public net::CookieStore {
DISALLOW_COPY_AND_ASSIGN(CefCookieStoreProxy);
};
class CefRequestContextProxy : public net::URLRequestContext {
public:
CefRequestContextProxy(CefBrowserHostImpl* browser,
net::URLRequestContextGetter* parent)
: parent_(parent) {
net::URLRequestContext* context = parent->GetURLRequestContext();
// Cookie store that proxies to the browser implementation.
cookie_store_proxy_ = new CefCookieStoreProxy(browser, context);
set_cookie_store(cookie_store_proxy_);
// All other values refer to the parent request context.
set_net_log(context->net_log());
set_host_resolver(context->host_resolver());
set_cert_verifier(context->cert_verifier());
set_server_bound_cert_service(context->server_bound_cert_service());
set_fraudulent_certificate_reporter(
context->fraudulent_certificate_reporter());
set_proxy_service(context->proxy_service());
set_ssl_config_service(context->ssl_config_service());
set_http_auth_handler_factory(context->http_auth_handler_factory());
set_http_transaction_factory(context->http_transaction_factory());
set_ftp_transaction_factory(context->ftp_transaction_factory());
set_network_delegate(context->network_delegate());
set_http_server_properties(context->http_server_properties());
set_transport_security_state(context->transport_security_state());
set_accept_charset(context->accept_charset());
set_accept_language(context->accept_language());
set_referrer_charset(context->referrer_charset());
set_job_factory(context->job_factory());
}
virtual const std::string& GetUserAgent(const GURL& url) const OVERRIDE {
return parent_->GetURLRequestContext()->GetUserAgent(url);
}
private:
net::URLRequestContextGetter* parent_;
scoped_refptr<net::CookieStore> cookie_store_proxy_;
DISALLOW_COPY_AND_ASSIGN(CefRequestContextProxy);
};
} // namespace
CefURLRequestContextGetterProxy::CefURLRequestContextGetterProxy(
CefBrowserHostImpl* browser,
net::URLRequestContextGetter* parent)
CefURLRequestContextGetter* parent)
: browser_(browser),
parent_(parent) {
parent_(parent),
context_proxy_(NULL) {
DCHECK(browser);
DCHECK(parent);
}
CefURLRequestContextGetterProxy::~CefURLRequestContextGetterProxy() {
if (context_proxy_)
parent_->ReleaseURLRequestContextProxy(context_proxy_);
}
net::URLRequestContext*
CefURLRequestContextGetterProxy::GetURLRequestContext() {
CEF_REQUIRE_IOT();
if (!context_proxy_.get()) {
context_proxy_.reset(
new CefRequestContextProxy(browser_, parent_));
if (!context_proxy_) {
context_proxy_ = parent_->CreateURLRequestContextProxy();
context_proxy_->Initialize(browser_);
}
return context_proxy_.get();
return context_proxy_;
}
scoped_refptr<base::SingleThreadTaskRunner>

View File

@ -10,11 +10,14 @@
#include "net/url_request/url_request_context_getter.h"
class CefBrowserHostImpl;
class CefURLRequestContextGetter;
class CefURLRequestContextProxy;
class CefURLRequestContextGetterProxy : public net::URLRequestContextGetter {
public:
CefURLRequestContextGetterProxy(CefBrowserHostImpl* browser,
net::URLRequestContextGetter* parent);
CefURLRequestContextGetter* parent);
virtual ~CefURLRequestContextGetterProxy();
// net::URLRequestContextGetter implementation.
virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
@ -23,8 +26,10 @@ class CefURLRequestContextGetterProxy : public net::URLRequestContextGetter {
private:
CefBrowserHostImpl* browser_;
scoped_refptr<net::URLRequestContextGetter> parent_;
scoped_ptr<net::URLRequestContext> context_proxy_;
scoped_refptr<CefURLRequestContextGetter> parent_;
// The |context_proxy_| object is owned by |parent_|.
CefURLRequestContextProxy* context_proxy_;
DISALLOW_COPY_AND_ASSIGN(CefURLRequestContextGetterProxy);
};

View File

@ -0,0 +1,164 @@
// 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/browser/url_request_context_proxy.h"
#include <string>
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/cookie_manager_impl.h"
#include "libcef/browser/thread_util.h"
#include "base/logging.h"
#include "base/message_loop_proxy.h"
#include "net/cookies/cookie_store.h"
#include "net/url_request/url_request_context_getter.h"
namespace {
class CefCookieStoreProxy : public net::CookieStore {
public:
explicit CefCookieStoreProxy(CefBrowserHostImpl* browser,
net::URLRequestContext* parent)
: parent_(parent),
browser_(browser) {
}
// net::CookieStore methods.
virtual void SetCookieWithOptionsAsync(
const GURL& url,
const std::string& cookie_line,
const net::CookieOptions& options,
const SetCookiesCallback& callback) OVERRIDE {
scoped_refptr<net::CookieStore> cookie_store = GetCookieStore();
cookie_store->SetCookieWithOptionsAsync(url, cookie_line, options,
callback);
}
virtual void GetCookiesWithOptionsAsync(
const GURL& url, const net::CookieOptions& options,
const GetCookiesCallback& callback) OVERRIDE {
scoped_refptr<net::CookieStore> cookie_store = GetCookieStore();
cookie_store->GetCookiesWithOptionsAsync(url, options, callback);
}
void GetCookiesWithInfoAsync(
const GURL& url,
const net::CookieOptions& options,
const GetCookieInfoCallback& callback) OVERRIDE {
scoped_refptr<net::CookieStore> cookie_store = GetCookieStore();
cookie_store->GetCookiesWithInfoAsync(url, options, callback);
}
virtual void DeleteCookieAsync(const GURL& url,
const std::string& cookie_name,
const base::Closure& callback) OVERRIDE {
scoped_refptr<net::CookieStore> cookie_store = GetCookieStore();
cookie_store->DeleteCookieAsync(url, cookie_name, callback);
}
virtual void DeleteAllCreatedBetweenAsync(const base::Time& delete_begin,
const base::Time& delete_end,
const DeleteCallback& callback)
OVERRIDE {
scoped_refptr<net::CookieStore> cookie_store = GetCookieStore();
cookie_store->DeleteAllCreatedBetweenAsync(delete_begin, delete_end,
callback);
}
virtual void DeleteSessionCookiesAsync(const DeleteCallback& callback)
OVERRIDE {
scoped_refptr<net::CookieStore> cookie_store = GetCookieStore();
cookie_store->DeleteSessionCookiesAsync(callback);
}
virtual net::CookieMonster* GetCookieMonster() OVERRIDE {
scoped_refptr<net::CookieStore> cookie_store = GetCookieStore();
return cookie_store->GetCookieMonster();
}
private:
net::CookieStore* GetCookieStore() {
CEF_REQUIRE_IOT();
scoped_refptr<net::CookieStore> cookie_store;
CefRefPtr<CefClient> client = browser_->GetClient();
if (client.get()) {
CefRefPtr<CefRequestHandler> handler = client->GetRequestHandler();
if (handler.get()) {
// Get the manager from the handler.
CefRefPtr<CefCookieManager> manager =
handler->GetCookieManager(browser_,
browser_->GetLoadingURL().spec());
if (manager.get()) {
cookie_store =
reinterpret_cast<CefCookieManagerImpl*>(
manager.get())->cookie_monster();
DCHECK(cookie_store);
}
}
}
if (!cookie_store) {
// Use the global cookie store.
cookie_store = parent_->cookie_store();
}
DCHECK(cookie_store);
return cookie_store;
}
// This pointer is guaranteed by the CefRequestContextProxy object.
net::URLRequestContext* parent_;
CefBrowserHostImpl* browser_;
DISALLOW_COPY_AND_ASSIGN(CefCookieStoreProxy);
};
} // namespace
CefURLRequestContextProxy::CefURLRequestContextProxy(
net::URLRequestContextGetter* parent)
: parent_(parent),
delete_try_count_(0) {
}
CefURLRequestContextProxy::~CefURLRequestContextProxy() {
}
const std::string& CefURLRequestContextProxy::GetUserAgent(const GURL& url) const {
return parent_->GetURLRequestContext()->GetUserAgent(url);
}
void CefURLRequestContextProxy::Initialize(CefBrowserHostImpl* browser) {
CEF_REQUIRE_IOT();
net::URLRequestContext* context = parent_->GetURLRequestContext();
// Cookie store that proxies to the browser implementation.
cookie_store_proxy_ = new CefCookieStoreProxy(browser, context);
set_cookie_store(cookie_store_proxy_);
// All other values refer to the parent request context.
set_net_log(context->net_log());
set_host_resolver(context->host_resolver());
set_cert_verifier(context->cert_verifier());
set_server_bound_cert_service(context->server_bound_cert_service());
set_fraudulent_certificate_reporter(
context->fraudulent_certificate_reporter());
set_proxy_service(context->proxy_service());
set_ssl_config_service(context->ssl_config_service());
set_http_auth_handler_factory(context->http_auth_handler_factory());
set_http_transaction_factory(context->http_transaction_factory());
set_ftp_transaction_factory(context->ftp_transaction_factory());
set_network_delegate(context->network_delegate());
set_http_server_properties(context->http_server_properties());
set_transport_security_state(context->transport_security_state());
set_accept_charset(context->accept_charset());
set_accept_language(context->accept_language());
set_referrer_charset(context->referrer_charset());
set_job_factory(context->job_factory());
}

View File

@ -0,0 +1,43 @@
// 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.
#ifndef CEF_LIBCEF_BROWSER_URL_REQUEST_CONTEXT_PROXY_H_
#define CEF_LIBCEF_BROWSER_URL_REQUEST_CONTEXT_PROXY_H_
#pragma once
#include "base/memory/scoped_ptr.h"
#include "net/url_request/url_request_context.h"
class CefBrowserHostImpl;
namespace net {
class CookieStore;
class URLRequestContextGetter;
}
class CefURLRequestContextProxy : public net::URLRequestContext {
public:
explicit CefURLRequestContextProxy(net::URLRequestContextGetter* parent);
virtual ~CefURLRequestContextProxy();
virtual const std::string& GetUserAgent(const GURL& url) const OVERRIDE;
void Initialize(CefBrowserHostImpl* browser);
// We may try to delete this proxy multiple times if URLRequests are still
// pending. Keep track of the number of tries so that they don't become
// excessive.
int delete_try_count() const { return delete_try_count_; }
void increment_delete_try_count() { delete_try_count_++; }
private:
net::URLRequestContextGetter* parent_;
scoped_refptr<net::CookieStore> cookie_store_proxy_;
int delete_try_count_;
DISALLOW_COPY_AND_ASSIGN(CefURLRequestContextProxy);
};
#endif // CEF_LIBCEF_BROWSER_URL_REQUEST_CONTEXT_PROXY_H_