mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
- Add the CefHandler::HandleDownloadResponse() method and CefDownloadHandler class to support file download in response to 'Content-Disposition' headers (issue #6).
- Fix parsing error in cef_parser.py due to space between angle brackets in template type definitions, and add support for int64 type. - Update copyright messages in Python and generated files. git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@117 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
@@ -5,12 +5,14 @@
|
||||
#include "include/cef.h"
|
||||
#include "cefclient.h"
|
||||
#include "binding_test.h"
|
||||
#include "download_handler.h"
|
||||
#include "extension_test.h"
|
||||
#include "plugin_test.h"
|
||||
#include "resource_util.h"
|
||||
#include "scheme_test.h"
|
||||
#include "string_util.h"
|
||||
#include "uiplugin_test.h"
|
||||
#include "util.h"
|
||||
#include <sstream>
|
||||
#include <commdlg.h>
|
||||
|
||||
@@ -191,7 +193,35 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
|
||||
class ClientHandler : public CefThreadSafeBase<CefHandler>
|
||||
{
|
||||
public:
|
||||
// Implements the DownloadListener interface.
|
||||
class ClientDownloadListener : public CefThreadSafeBase<DownloadListener>
|
||||
{
|
||||
public:
|
||||
ClientDownloadListener(ClientHandler* handler) : handler_(handler) {}
|
||||
|
||||
// Called when the download is complete.
|
||||
virtual void NotifyDownloadComplete(const std::wstring& fileName)
|
||||
{
|
||||
handler_->SetLastDownloadFile(fileName);
|
||||
PostMessage(handler_->GetMainHwnd(), WM_COMMAND,
|
||||
ID_WARN_DOWNLOADCOMPLETE, 0);
|
||||
}
|
||||
|
||||
// Called if the download fails.
|
||||
virtual void NotifyDownloadError(const std::wstring& fileName)
|
||||
{
|
||||
handler_->SetLastDownloadFile(fileName);
|
||||
PostMessage(handler_->GetMainHwnd(), WM_COMMAND,
|
||||
ID_WARN_DOWNLOADERROR, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
ClientHandler* handler_;
|
||||
};
|
||||
|
||||
ClientHandler()
|
||||
: ALLOW_THIS_IN_INITIALIZER_LIST(
|
||||
m_DownloadListener(new ClientDownloadListener(this)))
|
||||
{
|
||||
m_MainHwnd = NULL;
|
||||
m_BrowserHwnd = NULL;
|
||||
@@ -399,6 +429,25 @@ public:
|
||||
return RV_CONTINUE;
|
||||
}
|
||||
|
||||
// Called when a server indicates via the 'Content-Disposition' header that a
|
||||
// response represents a file to download. |mime_type| is the mime type for
|
||||
// the download, |file_name| is the suggested target file name and
|
||||
// |content_length| is either the value of the 'Content-Size' header or -1 if
|
||||
// no size was provided. Set |handler| to the CefDownloadHandler instance that
|
||||
// will recieve the file contents. Return RV_CONTINUE to download the file
|
||||
// or RV_HANDLED to cancel the file download.
|
||||
/*--cef()--*/
|
||||
virtual RetVal HandleDownloadResponse(CefRefPtr<CefBrowser> browser,
|
||||
const std::wstring& mimeType,
|
||||
const std::wstring& fileName,
|
||||
int64 contentLength,
|
||||
CefRefPtr<CefDownloadHandler>& handler)
|
||||
{
|
||||
// Create the handler for the file download.
|
||||
handler = CreateDownloadHandler(m_DownloadListener, fileName);
|
||||
return RV_CONTINUE;
|
||||
}
|
||||
|
||||
// Event called before a context menu is displayed. To cancel display of the
|
||||
// default context menu return RV_HANDLED.
|
||||
virtual RetVal HandleBeforeMenu(CefRefPtr<CefBrowser> browser,
|
||||
@@ -407,7 +456,6 @@ public:
|
||||
return RV_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
// Event called to optionally override the default text for a context menu
|
||||
// item. |label| contains the default text and may be modified to substitute
|
||||
// alternate text. The return value is currently ignored.
|
||||
@@ -668,6 +716,22 @@ public:
|
||||
return str;
|
||||
}
|
||||
|
||||
void SetLastDownloadFile(const std::wstring& fileName)
|
||||
{
|
||||
Lock();
|
||||
m_LastDownloadFile = fileName;
|
||||
Unlock();
|
||||
}
|
||||
|
||||
std::wstring GetLastDownloadFile()
|
||||
{
|
||||
std::wstring str;
|
||||
Lock();
|
||||
str = m_LastDownloadFile;
|
||||
Unlock();
|
||||
return str;
|
||||
}
|
||||
|
||||
protected:
|
||||
// The child browser window
|
||||
CefRefPtr<CefBrowser> m_Browser;
|
||||
@@ -689,6 +753,10 @@ protected:
|
||||
bool m_bCanGoForward;
|
||||
|
||||
std::wstring m_LogFile;
|
||||
|
||||
// Support for downloading files.
|
||||
CefRefPtr<DownloadListener> m_DownloadListener;
|
||||
std::wstring m_LastDownloadFile;
|
||||
};
|
||||
|
||||
// global handler instance
|
||||
@@ -941,6 +1009,21 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
MB_OK | MB_ICONINFORMATION);
|
||||
}
|
||||
return 0;
|
||||
case ID_WARN_DOWNLOADCOMPLETE:
|
||||
case ID_WARN_DOWNLOADERROR:
|
||||
if(g_handler.get()) {
|
||||
std::wstringstream ss;
|
||||
ss << L"File \"" << g_handler->GetLastDownloadFile() << L"\" ";
|
||||
|
||||
if(wmId == ID_WARN_DOWNLOADCOMPLETE)
|
||||
ss << L"downloaded successfully.";
|
||||
else
|
||||
ss << L"failed to download.";
|
||||
|
||||
MessageBoxW(hWnd, ss.str().c_str(), L"File Download",
|
||||
MB_OK | MB_ICONINFORMATION);
|
||||
}
|
||||
return 0;
|
||||
case ID_FIND:
|
||||
if(!hFindDlg)
|
||||
{
|
||||
|
229
tests/cefclient/download_handler.cpp
Normal file
229
tests/cefclient/download_handler.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
// Copyright (c) 2010 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 "download_handler.h"
|
||||
#include "util.h"
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#endif // _WIN32
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
// Template for creating a task that executes a method with no arguments.
|
||||
template <class T, class Method>
|
||||
class Task : public CefThreadSafeBase<CefTask>
|
||||
{
|
||||
public:
|
||||
Task(T* object, Method method)
|
||||
: object_(object), method_(method) {}
|
||||
|
||||
virtual void Execute(CefThreadId threadId)
|
||||
{
|
||||
(object_->*method_)();
|
||||
}
|
||||
|
||||
protected:
|
||||
CefRefPtr<T> object_;
|
||||
Method method_;
|
||||
};
|
||||
|
||||
// Helper method for posting a task on a specific thread.
|
||||
template <class T, class Method>
|
||||
inline void PostOnThread(CefThreadId threadId,
|
||||
T* object,
|
||||
Method method) {
|
||||
CefRefPtr<CefTask> task = new Task<T,Method>(object, method);
|
||||
CefPostTask(threadId, task);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Implementation of the CefDownloadHandler interface.
|
||||
class ClientDownloadHandler : public CefThreadSafeBase<CefDownloadHandler>
|
||||
{
|
||||
public:
|
||||
ClientDownloadHandler(CefRefPtr<DownloadListener> listener,
|
||||
const std::wstring& fileName)
|
||||
: listener_(listener), filename_(fileName), file_(NULL)
|
||||
{
|
||||
// Open the file on the FILE thread.
|
||||
PostOnThread(TID_FILE, this, &ClientDownloadHandler::OnOpen);
|
||||
}
|
||||
|
||||
~ClientDownloadHandler()
|
||||
{
|
||||
ASSERT(pending_data_.empty());
|
||||
ASSERT(file_ == NULL);
|
||||
|
||||
if(!pending_data_.empty()) {
|
||||
// Delete remaining pending data.
|
||||
std::vector<std::vector<char>*>::iterator it = pending_data_.begin();
|
||||
for(; it != pending_data_.end(); ++it)
|
||||
delete (*it);
|
||||
}
|
||||
|
||||
if(file_) {
|
||||
// Close the dangling file pointer on the FILE thread.
|
||||
class TaskCloseFile : public CefThreadSafeBase<CefTask>
|
||||
{
|
||||
public:
|
||||
TaskCloseFile(FILE* file) : file_(file) {}
|
||||
virtual void Execute(CefThreadId threadId) { fclose(file_); }
|
||||
private:
|
||||
FILE* file_;
|
||||
};
|
||||
CefPostTask(TID_FILE, new TaskCloseFile(file_));
|
||||
|
||||
// Notify the listener that the download failed.
|
||||
listener_->NotifyDownloadError(filename_);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// The following methods are called on the UI thread.
|
||||
// --------------------------------------------------
|
||||
|
||||
// A portion of the file contents have been received. This method will be
|
||||
// called multiple times until the download is complete. Return |true| to
|
||||
// continue receiving data and |false| to cancel.
|
||||
virtual bool ReceivedData(void* data, int data_size)
|
||||
{
|
||||
ASSERT(CefCurrentlyOn(TID_UI));
|
||||
|
||||
if(data_size == 0)
|
||||
return true;
|
||||
|
||||
// Create a new vector for the data.
|
||||
std::vector<char>* buffer = new std::vector<char>(data_size);
|
||||
memcpy(&(*buffer)[0], data, data_size);
|
||||
|
||||
// Add the new data vector to the pending data queue.
|
||||
Lock();
|
||||
pending_data_.push_back(buffer);
|
||||
Unlock();
|
||||
|
||||
// Write data to file on the FILE thread.
|
||||
PostOnThread(TID_FILE, this, &ClientDownloadHandler::OnReceivedData);
|
||||
return true;
|
||||
}
|
||||
|
||||
// The download is complete.
|
||||
virtual void Complete()
|
||||
{
|
||||
ASSERT(CefCurrentlyOn(TID_UI));
|
||||
|
||||
// Flush and close the file on the FILE thread.
|
||||
PostOnThread(TID_FILE, this, &ClientDownloadHandler::OnComplete);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// The following methods are called on the FILE thread.
|
||||
// ----------------------------------------------------
|
||||
|
||||
void OnOpen()
|
||||
{
|
||||
ASSERT(CefCurrentlyOn(TID_FILE));
|
||||
|
||||
if(file_)
|
||||
return;
|
||||
|
||||
#ifdef _WIN32
|
||||
TCHAR szFolderPath[MAX_PATH];
|
||||
|
||||
// Save the file in the user's "My Documents" folder.
|
||||
if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL|CSIDL_FLAG_CREATE,
|
||||
NULL, 0, szFolderPath))) {
|
||||
LPWSTR name = PathFindFileName(filename_.c_str());
|
||||
LPWSTR ext = PathFindExtension(filename_.c_str());
|
||||
int ct = 0;
|
||||
std::wstringstream ss;
|
||||
|
||||
if(ext) {
|
||||
name[ext-name] = 0;
|
||||
ext++;
|
||||
}
|
||||
|
||||
// Make sure the file name is unique.
|
||||
do {
|
||||
if(ct > 0)
|
||||
ss.str(L"");
|
||||
ss << szFolderPath << L"\\" << name;
|
||||
if(ct > 0)
|
||||
ss << L" (" << ct << L")";
|
||||
if(ext)
|
||||
ss << L"." << ext;
|
||||
ct++;
|
||||
} while(PathFileExists(ss.str().c_str()));
|
||||
|
||||
Lock();
|
||||
filename_ = ss.str();
|
||||
Unlock();
|
||||
|
||||
file_ = _wfopen(ss.str().c_str(), L"wb");
|
||||
ASSERT(file_ != NULL);
|
||||
}
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
void OnComplete()
|
||||
{
|
||||
ASSERT(CefCurrentlyOn(TID_FILE));
|
||||
|
||||
if(!file_)
|
||||
return;
|
||||
|
||||
// Make sure any pending data is written.
|
||||
OnReceivedData();
|
||||
|
||||
fclose(file_);
|
||||
file_ = NULL;
|
||||
|
||||
// Notify the listener that the download completed.
|
||||
listener_->NotifyDownloadComplete(filename_);
|
||||
}
|
||||
|
||||
void OnReceivedData()
|
||||
{
|
||||
ASSERT(CefCurrentlyOn(TID_FILE));
|
||||
|
||||
std::vector<std::vector<char>*> data;
|
||||
|
||||
// Remove all data from the pending data queue.
|
||||
Lock();
|
||||
if(!pending_data_.empty()) {
|
||||
data = pending_data_;
|
||||
pending_data_.clear();
|
||||
}
|
||||
Unlock();
|
||||
|
||||
if(data.empty())
|
||||
return;
|
||||
|
||||
// Write all pending data to file.
|
||||
std::vector<std::vector<char>*>::iterator it = data.begin();
|
||||
for(; it != data.end(); ++it) {
|
||||
std::vector<char>* buffer = *it;
|
||||
if(file_)
|
||||
fwrite(&(*buffer)[0], buffer->size(), 1, file_);
|
||||
delete buffer;
|
||||
}
|
||||
data.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
CefRefPtr<DownloadListener> listener_;
|
||||
std::wstring filename_;
|
||||
FILE* file_;
|
||||
std::vector<std::vector<char>*> pending_data_;
|
||||
};
|
||||
|
||||
CefRefPtr<CefDownloadHandler> CreateDownloadHandler(
|
||||
CefRefPtr<DownloadListener> listener, const std::wstring& fileName)
|
||||
{
|
||||
return new ClientDownloadHandler(listener, fileName);
|
||||
}
|
21
tests/cefclient/download_handler.h
Normal file
21
tests/cefclient/download_handler.h
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2010 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.
|
||||
|
||||
#pragma once
|
||||
#include "include/cef.h"
|
||||
|
||||
// Implement this interface to receive download notifications.
|
||||
class DownloadListener : public CefBase
|
||||
{
|
||||
public:
|
||||
// Called when the download is complete.
|
||||
virtual void NotifyDownloadComplete(const std::wstring& fileName) =0;
|
||||
|
||||
// Called if the download fails.
|
||||
virtual void NotifyDownloadError(const std::wstring& fileName) =0;
|
||||
};
|
||||
|
||||
// Create a new download handler to manage download of a single file.
|
||||
CefRefPtr<CefDownloadHandler> CreateDownloadHandler(
|
||||
CefRefPtr<DownloadListener> listener, const std::wstring& fileName);
|
@@ -22,8 +22,10 @@
|
||||
#define IDC_NAV_RELOAD 202
|
||||
#define IDC_NAV_STOP 203
|
||||
#define ID_WARN_CONSOLEMESSAGE 32000
|
||||
#define ID_FIND 32001
|
||||
#define ID_PRINT 32002
|
||||
#define ID_WARN_DOWNLOADCOMPLETE 32001
|
||||
#define ID_WARN_DOWNLOADERROR 32002
|
||||
#define ID_FIND 32101
|
||||
#define ID_PRINT 32102
|
||||
#define ID_TESTS_GETSOURCE 32769
|
||||
#define ID_TESTS_GETTEXT 32770
|
||||
#define ID_TESTS_JAVASCRIPT_BINDING 32771
|
||||
|
@@ -22,11 +22,11 @@ public:
|
||||
|
||||
// Read raw binary data.
|
||||
virtual size_t Read(void* ptr, size_t size, size_t n);
|
||||
|
||||
|
||||
// Seek to the specified offset position. |whence| may be any one of
|
||||
// SEEK_CUR, SEEK_END or SEEK_SET.
|
||||
virtual int Seek(long offset, int whence);
|
||||
|
||||
|
||||
// Return the current offset position.
|
||||
virtual long Tell();
|
||||
|
||||
|
48
tests/cefclient/util.h
Normal file
48
tests/cefclient/util.h
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2010 The Chromium Embedded Framework Authors.
|
||||
// Portions copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define ASSERT(condition) if(!(condition)) { DebugBreak(); }
|
||||
#else
|
||||
#define ASSERT(condition) ((void)0)
|
||||
#endif
|
||||
|
||||
// MSVC_PUSH_DISABLE_WARNING pushes |n| onto a stack of warnings to be disabled.
|
||||
// The warning remains disabled until popped by MSVC_POP_WARNING.
|
||||
#define MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \
|
||||
__pragma(warning(disable:n))
|
||||
|
||||
// MSVC_PUSH_WARNING_LEVEL pushes |n| as the global warning level. The level
|
||||
// remains in effect until popped by MSVC_POP_WARNING(). Use 0 to disable all
|
||||
// warnings.
|
||||
#define MSVC_PUSH_WARNING_LEVEL(n) __pragma(warning(push, n))
|
||||
|
||||
// Pop effects of innermost MSVC_PUSH_* macro.
|
||||
#define MSVC_POP_WARNING() __pragma(warning(pop))
|
||||
|
||||
// Allows |this| to be passed as an argument in constructor initializer lists.
|
||||
// This uses push/pop instead of the seemingly simpler suppress feature to avoid
|
||||
// having the warning be disabled for more than just |code|.
|
||||
//
|
||||
// Example usage:
|
||||
// Foo::Foo() : x(NULL), ALLOW_THIS_IN_INITIALIZER_LIST(y(this)), z(3) {}
|
||||
//
|
||||
// Compiler warning C4355: 'this': used in base member initializer list:
|
||||
// http://msdn.microsoft.com/en-us/library/3c594ae3(VS.80).aspx
|
||||
#define ALLOW_THIS_IN_INITIALIZER_LIST(code) MSVC_PUSH_DISABLE_WARNING(4355) \
|
||||
code \
|
||||
MSVC_POP_WARNING()
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#ifndef min
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
Reference in New Issue
Block a user