Add a new CefBrowserHost::StartDownload method for starting a download that can then be handled via CefDownloadHandler (issue #883).

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1100 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2013-02-13 22:47:04 +00:00
parent d65179c135
commit 7f3d1ccf78
10 changed files with 356 additions and 0 deletions

View File

@ -247,6 +247,7 @@
'tests/unittests/dialog_unittest.cc',
'tests/unittests/display_unittest.cc',
'tests/unittests/dom_unittest.cc',
'tests/unittests/download_unittest.cc',
'tests/unittests/geolocation_unittest.cc',
'tests/unittests/jsdialog_unittest.cc',
'tests/unittests/navigation_unittest.cc',

View File

@ -298,6 +298,12 @@ typedef struct _cef_browser_host_t {
const cef_string_t* default_file_name, cef_string_list_t accept_types,
struct _cef_run_file_dialog_callback_t* callback);
///
// Download the file at |url| using cef_download_handler_t.
///
void (CEF_CALLBACK *start_download)(struct _cef_browser_host_t* self,
const cef_string_t* url);
///
// Returns true (1) if window rendering is disabled.
///

View File

@ -339,6 +339,12 @@ class CefBrowserHost : public virtual CefBase {
const std::vector<CefString>& accept_types,
CefRefPtr<CefRunFileDialogCallback> callback) =0;
///
// Download the file at |url| using CefDownloadHandler.
///
/*--cef()--*/
virtual void StartDownload(const CefString& url) =0;
///
// Returns true if window rendering is disabled.
///

View File

@ -29,6 +29,8 @@
#include "base/bind_helpers.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/download_url_parameters.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
@ -555,6 +557,35 @@ void CefBrowserHostImpl::RunFileDialog(
base::Bind(&CefRunFileDialogCallbackWrapper::Callback, wrapper));
}
void CefBrowserHostImpl::StartDownload(const CefString& url) {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::StartDownload, this, url));
return;
}
GURL gurl = GURL(url.ToString());
if (gurl.is_empty() || !gurl.is_valid())
return;
if (!web_contents())
return;
CefBrowserContext* context = _Context->browser_context();
if (!context)
return;
scoped_refptr<content::DownloadManager> manager =
content::BrowserContext::GetDownloadManager(context);
if (!manager)
return;
scoped_ptr<content::DownloadUrlParameters> params;
params.reset(
content::DownloadUrlParameters::FromWebContents(web_contents(), gurl));
manager->DownloadUrl(params.Pass());
}
bool CefBrowserHostImpl::IsWindowRenderingDisabled() {
return IsWindowRenderingDisabled(window_info_);
}

View File

@ -124,6 +124,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
const CefString& default_file_name,
const std::vector<CefString>& accept_types,
CefRefPtr<CefRunFileDialogCallback> callback) OVERRIDE;
virtual void StartDownload(const CefString& url) OVERRIDE;
virtual bool IsWindowRenderingDisabled() OVERRIDE;
virtual void WasResized() OVERRIDE;
virtual void Invalidate(const CefRect& dirtyRect,

View File

@ -262,6 +262,23 @@ void CEF_CALLBACK browser_host_run_file_dialog(struct _cef_browser_host_t* self,
CefRunFileDialogCallbackCToCpp::Wrap(callback));
}
void CEF_CALLBACK browser_host_start_download(struct _cef_browser_host_t* self,
const cef_string_t* url) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: url; type: string_byref_const
DCHECK(url);
if (!url)
return;
// Execute
CefBrowserHostCppToC::Get(self)->StartDownload(
CefString(url));
}
int CEF_CALLBACK browser_host_is_window_rendering_disabled(
struct _cef_browser_host_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
@ -449,6 +466,7 @@ CefBrowserHostCppToC::CefBrowserHostCppToC(CefBrowserHost* cls)
struct_.struct_.get_zoom_level = browser_host_get_zoom_level;
struct_.struct_.set_zoom_level = browser_host_set_zoom_level;
struct_.struct_.run_file_dialog = browser_host_run_file_dialog;
struct_.struct_.start_download = browser_host_start_download;
struct_.struct_.is_window_rendering_disabled =
browser_host_is_window_rendering_disabled;
struct_.struct_.was_resized = browser_host_was_resized;

View File

@ -215,6 +215,22 @@ void CefBrowserHostCToCpp::RunFileDialog(FileDialogMode mode,
cef_string_list_free(accept_typesList);
}
void CefBrowserHostCToCpp::StartDownload(const CefString& url) {
if (CEF_MEMBER_MISSING(struct_, start_download))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: url; type: string_byref_const
DCHECK(!url.empty());
if (url.empty())
return;
// Execute
struct_->start_download(struct_,
url.GetStruct());
}
bool CefBrowserHostCToCpp::IsWindowRenderingDisabled() {
if (CEF_MEMBER_MISSING(struct_, is_window_rendering_disabled))
return false;

View File

@ -51,6 +51,7 @@ class CefBrowserHostCToCpp
const CefString& default_file_name,
const std::vector<CefString>& accept_types,
CefRefPtr<CefRunFileDialogCallback> callback) OVERRIDE;
virtual void StartDownload(const CefString& url) OVERRIDE;
virtual bool IsWindowRenderingDisabled() OVERRIDE;
virtual void WasResized() OVERRIDE;
virtual void Invalidate(const CefRect& dirtyRect,

View File

@ -0,0 +1,265 @@
// Copyright (c) 2013 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 "include/cef_scheme.h"
#include "base/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "tests/unittests/test_handler.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
const char kTestDomain[] = "test-download";
const char kTestEntryUrl[] = "http://test-download/test.html";
const char kTestDownloadUrl[] = "http://test-download/download.txt";
const char kTestFileName[] = "download_test.txt";
const char kTestContentDisposition[] =
"attachment; filename=\"download_test.txt\"";
const char kTestMimeType[] = "text/plain";
const char kTestContent[] = "Download test text";
class DownloadSchemeHandler : public CefResourceHandler {
public:
explicit DownloadSchemeHandler(TrackCallback* got_download_request)
: got_download_request_(got_download_request),
offset_(0) {}
virtual bool ProcessRequest(CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback)
OVERRIDE {
std::string url = request->GetURL();
if (url == kTestEntryUrl) {
content_ = "<html><body>Download Test</body></html>";
mime_type_ = "text/html";
} else if (url == kTestDownloadUrl) {
got_download_request_->yes();
content_ = kTestContent;
mime_type_ = kTestMimeType;
content_disposition_ = kTestContentDisposition;
} else {
EXPECT_TRUE(false); // Not reached.
return false;
}
callback->Continue();
return true;
}
virtual void GetResponseHeaders(CefRefPtr<CefResponse> response,
int64& response_length,
CefString& redirectUrl) OVERRIDE {
response_length = content_.size();
response->SetStatus(200);
response->SetMimeType(mime_type_);
if (!content_disposition_.empty()) {
CefResponse::HeaderMap headerMap;
response->GetHeaderMap(headerMap);
headerMap.insert(
std::make_pair("Content-Disposition", content_disposition_));
response->SetHeaderMap(headerMap);
}
}
virtual bool ReadResponse(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefCallback> callback)
OVERRIDE {
bool has_data = false;
bytes_read = 0;
size_t size = content_.size();
if (offset_ < size) {
int transfer_size =
std::min(bytes_to_read, static_cast<int>(size - offset_));
memcpy(data_out, content_.c_str() + offset_, transfer_size);
offset_ += transfer_size;
bytes_read = transfer_size;
has_data = true;
}
return has_data;
}
virtual void Cancel() OVERRIDE {
}
private:
TrackCallback* got_download_request_;
std::string content_;
std::string mime_type_;
std::string content_disposition_;
size_t offset_;
IMPLEMENT_REFCOUNTING(SchemeHandler);
};
class DownloadSchemeHandlerFactory : public CefSchemeHandlerFactory {
public:
explicit DownloadSchemeHandlerFactory(TrackCallback* got_download_request)
: got_download_request_(got_download_request) {}
virtual CefRefPtr<CefResourceHandler> Create(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& scheme_name,
CefRefPtr<CefRequest> request) OVERRIDE {
return new DownloadSchemeHandler(got_download_request_);
}
private:
TrackCallback* got_download_request_;
IMPLEMENT_REFCOUNTING(SchemeHandlerFactory);
};
class DownloadTestHandler : public TestHandler {
public:
DownloadTestHandler() {}
virtual void RunTest() OVERRIDE {
CefRegisterSchemeHandlerFactory("http", kTestDomain,
new DownloadSchemeHandlerFactory(&got_download_request_));
// Create a new temporary directory.
EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
test_path_ = temp_dir_.path().AppendASCII(kTestFileName);
// Create the browser
CreateBrowser(kTestEntryUrl);
}
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) OVERRIDE {
EXPECT_STREQ(kTestEntryUrl, frame->GetURL().ToString().c_str());
// Begin the download.
browser->GetHost()->StartDownload(kTestDownloadUrl);
}
virtual void OnBeforeDownload(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDownloadItem> download_item,
const CefString& suggested_name,
CefRefPtr<CefBeforeDownloadCallback> callback) OVERRIDE {
EXPECT_TRUE(CefCurrentlyOn(TID_UI));
EXPECT_FALSE(got_on_before_download_);
EXPECT_FALSE(got_on_download_updated_);
got_on_before_download_.yes();
EXPECT_TRUE(browser->IsSame(GetBrowser()));
EXPECT_STREQ(kTestFileName, suggested_name.ToString().c_str());
EXPECT_TRUE(download_item.get());
EXPECT_TRUE(callback.get());
download_id_ = download_item->GetId();
EXPECT_LT(0, download_id_);
EXPECT_TRUE(download_item->IsValid());
EXPECT_TRUE(download_item->IsInProgress());
EXPECT_FALSE(download_item->IsComplete());
EXPECT_FALSE(download_item->IsCanceled());
EXPECT_EQ(0LL, download_item->GetCurrentSpeed());
EXPECT_EQ(0, download_item->GetPercentComplete());
EXPECT_EQ(static_cast<int64>(sizeof(kTestContent)-1),
download_item->GetTotalBytes());
EXPECT_EQ(0LL, download_item->GetReceivedBytes());
EXPECT_EQ(0L, download_item->GetFullPath().length());
EXPECT_STREQ(kTestDownloadUrl, download_item->GetURL().ToString().c_str());
EXPECT_EQ(0L, download_item->GetSuggestedFileName().length());
EXPECT_STREQ(kTestContentDisposition,
download_item->GetContentDisposition().ToString().c_str());
EXPECT_STREQ(kTestMimeType, download_item->GetMimeType().ToString().c_str());
callback->Continue(test_path_.value(), false);
}
virtual void OnDownloadUpdated(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDownloadItem> download_item,
CefRefPtr<CefDownloadItemCallback> callback) OVERRIDE {
EXPECT_TRUE(CefCurrentlyOn(TID_UI));
EXPECT_TRUE(got_on_before_download_);
got_on_download_updated_.yes();
EXPECT_TRUE(browser->IsSame(GetBrowser()));
EXPECT_TRUE(download_item.get());
EXPECT_TRUE(callback.get());
EXPECT_EQ(download_id_, download_item->GetId());
EXPECT_TRUE(download_item->IsValid());
EXPECT_FALSE(download_item->IsCanceled());
EXPECT_LT(0LL, download_item->GetCurrentSpeed());
EXPECT_LT(0, download_item->GetPercentComplete());
EXPECT_EQ(static_cast<int64>(sizeof(kTestContent)-1),
download_item->GetTotalBytes());
EXPECT_STREQ(kTestDownloadUrl, download_item->GetURL().ToString().c_str());
EXPECT_STREQ(kTestContentDisposition,
download_item->GetContentDisposition().ToString().c_str());
EXPECT_STREQ(kTestMimeType,
download_item->GetMimeType().ToString().c_str());
std::string full_path = download_item->GetFullPath();
if (!full_path.empty()) {
got_full_path_.yes();
EXPECT_STREQ(CefString(test_path_.value()).ToString().c_str(),
full_path.c_str());
}
if (download_item->IsComplete()) {
EXPECT_FALSE(download_item->IsInProgress());
EXPECT_EQ(100, download_item->GetPercentComplete());
EXPECT_EQ(static_cast<int64>(sizeof(kTestContent)-1),
download_item->GetReceivedBytes());
DestroyTest();
} else {
EXPECT_TRUE(download_item->IsInProgress());
EXPECT_LT(0LL, download_item->GetReceivedBytes());
}
}
virtual void DestroyTest() OVERRIDE {
CefRegisterSchemeHandlerFactory("http", kTestDomain, NULL);
EXPECT_TRUE(got_download_request_);
EXPECT_TRUE(got_on_before_download_);
EXPECT_TRUE(got_on_download_updated_);
EXPECT_TRUE(got_full_path_);
// Verify the file contents.
std::string contents;
EXPECT_TRUE(file_util::ReadFileToString(test_path_, &contents));
EXPECT_STREQ(kTestContent, contents.c_str());
EXPECT_TRUE(temp_dir_.Delete());
TestHandler::DestroyTest();
}
private:
base::ScopedTempDir temp_dir_;
FilePath test_path_;
int download_id_;
TrackCallback got_download_request_;
TrackCallback got_on_before_download_;
TrackCallback got_on_download_updated_;
TrackCallback got_full_path_;
};
} // namespace
// Verify that downloads work.
TEST(DownloadTest, Download) {
CefRefPtr<DownloadTestHandler> handler = new DownloadTestHandler();
handler->ExecuteTest();
}

View File

@ -33,6 +33,7 @@ class TrackCallback {
class TestHandler : public CefClient,
public CefDialogHandler,
public CefDisplayHandler,
public CefDownloadHandler,
public CefGeolocationHandler,
public CefJSDialogHandler,
public CefLifeSpanHandler,
@ -52,6 +53,9 @@ class TestHandler : public CefClient,
virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefDownloadHandler> GetDownloadHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefGeolocationHandler> GetGeolocationHandler() OVERRIDE {
return this;
}
@ -68,6 +72,13 @@ class TestHandler : public CefClient,
return this;
}
// CefDownloadHandler methods
virtual void OnBeforeDownload(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDownloadItem> download_item,
const CefString& suggested_name,
CefRefPtr<CefBeforeDownloadCallback> callback) OVERRIDE {}
// CefLifeSpanHandler methods
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;