- Add support for custom scheme handlers (entry #49, initial version by heshiming).

cefclient:
- Add custom scheme handler test.

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@37 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2009-08-21 02:14:47 +00:00
parent f341b9f439
commit 087319efdb
19 changed files with 1229 additions and 70 deletions

View File

@ -50,6 +50,8 @@ class CefHandler;
class CefPostData;
class CefPostDataElement;
class CefRequest;
class CefSchemeHandler;
class CefSchemeHandlerFactory;
class CefStreamReader;
class CefStreamWriter;
class CefV8Handler;
@ -141,6 +143,16 @@ bool CefRegisterExtension(const std::wstring& extension_name,
CefRefPtr<CefV8Handler> handler);
// Register a custom scheme handler factory for the specified |scheme_name| and
// |host_name|. All URLs beginning with scheme_name://host_name/ can be handled
// by CefSchemeHandler instances returned by the factory. Specify an empty
// |host_name| value to match all host names.
/*--cef()--*/
bool CefRegisterScheme(const std::wstring& scheme_name,
const std::wstring& host_name,
CefRefPtr<CefSchemeHandlerFactory> factory);
// Interface defining the the reference count implementation methods. All
// framework classes must implement the CefBase class.
class CefBase
@ -930,4 +942,47 @@ public:
std::wstring& exception) =0;
};
// Class that creates CefSchemeHandler instances.
/*--cef(source=client)--*/
class CefSchemeHandlerFactory : public CefBase
{
public:
// Return a new scheme handler instance to handle the request.
/*--cef()--*/
virtual CefRefPtr<CefSchemeHandler> Create() =0;
};
// Class used to represent a custom scheme handler interface.
/*--cef(source=client)--*/
class CefSchemeHandler : public CefBase
{
public:
// Process the request. All response generation should take place in this
// method. If there is no response set |response_length| to zero and
// ReadResponse() will not be called. If the response length is not known then
// set |response_length| to -1 and ReadResponse() will be called until it
// returns false or until the value of |bytes_read| is set to 0. Otherwise,
// set |response_length| to a positive value and ReadResponse() will be called
// until it returns false, the value of |bytes_read| is set to 0 or the
// specified number of bytes have been read. If there is a response set
// |mime_type| to the mime type for the response.
/*--cef()--*/
virtual bool ProcessRequest(CefRefPtr<CefRequest> request,
std::wstring& mime_type, int* response_length) =0;
// Cancel processing of the request.
/*--cef()--*/
virtual void Cancel() =0;
// Copy up to |bytes_to_read| bytes into |data_out|. If the copy succeeds
// set |bytes_read| to the number of bytes copied and return true. If the
// copy fails return false and ReadResponse() will not be called again.
/*--cef()--*/
virtual bool ReadResponse(void* data_out, int bytes_to_read,
int* bytes_read) =0;
};
#endif // _CEF_H

View File

@ -126,6 +126,13 @@ CEF_EXPORT void cef_do_message_loop_work();
CEF_EXPORT int cef_register_extension(const wchar_t* extension_name,
const wchar_t* javascript_code, struct _cef_v8handler_t* handler);
// Register a custom scheme handler factory for the specified |scheme_name| and
// |host_name|. All URLs beginning with scheme_name://host_name/ can be handled
// by cef_scheme_handler_t instances returned by the factory. Specify an NULL
// |host_name| value to match all host names.
CEF_EXPORT int cef_register_scheme(const wchar_t* scheme_name,
const wchar_t* host_name, struct _cef_scheme_handler_factory_t* factory);
typedef struct _cef_base_t
{
// Size of the data structure.
@ -769,6 +776,50 @@ CEF_EXPORT cef_v8value_t* cef_v8value_create_function(const wchar_t* name,
cef_v8handler_t* handler);
// Structure that creates cef_scheme_handler_t instances.
typedef struct _cef_scheme_handler_factory_t
{
// Base structure.
cef_base_t base;
// Return a new scheme handler instance to handle the request.
struct _cef_scheme_handler_t* (CEF_CALLBACK *create)(
struct _cef_scheme_handler_factory_t* self);
} cef_scheme_handler_factory_t;
// Structure used to represent a custom scheme handler structure.
typedef struct _cef_scheme_handler_t
{
// Base structure.
cef_base_t base;
// Process the request. All response generation should take place in this
// function. If there is no response set |response_length| to zero and
// read_response() will not be called. If the response length is not known
// then set |response_length| to -1 and read_response() will be called until
// it returns false (0) or until the value of |bytes_read| is set to 0.
// Otherwise, set |response_length| to a positive value and read_response()
// will be called until it returns false (0), the value of |bytes_read| is set
// to 0 or the specified number of bytes have been read. If there is a
// response set |mime_type| to the mime type for the response.
int (CEF_CALLBACK *process_request)(struct _cef_scheme_handler_t* self,
struct _cef_request_t* request, cef_string_t* mime_type,
int* response_length);
// Cancel processing of the request.
void (CEF_CALLBACK *cancel)(struct _cef_scheme_handler_t* self);
// Copy up to |bytes_to_read| bytes into |data_out|. If the copy succeeds set
// |bytes_read| to the number of bytes copied and return true (1). If the copy
// fails return false (0) and read_response() will not be called again.
int (CEF_CALLBACK *read_response)(struct _cef_scheme_handler_t* self,
void* data_out, int bytes_to_read, int* bytes_read);
} cef_scheme_handler_t;
#ifdef __cplusplus
}
#endif

View File

@ -373,6 +373,10 @@
RelativePath=".\request_impl.h"
>
</File>
<File
RelativePath=".\scheme_impl.cc"
>
</File>
<File
RelativePath=".\simple_clipboard_impl.cc"
>

411
libcef/scheme_impl.cc Normal file
View File

@ -0,0 +1,411 @@
// Copyright (c) 2009 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2006-2009 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.
#include "precompiled_libcef.h"
#include "base/lazy_instance.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/worker_pool.h"
#include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
#include "net/base/upload_data.h"
#include "net/http/http_util.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_filter.h"
#include "net/url_request/url_request_job.h"
#include "include/cef.h"
#include "tracker.h"
#include "context.h"
#include "request_impl.h"
#include <map>
// Memory manager.
base::LazyInstance<CefTrackManager> g_scheme_tracker(base::LINKER_INITIALIZED);
class TrackBase : public CefTrackObject
{
public:
TrackBase(CefBase* base) { base_ = base; }
protected:
CefRefPtr<CefBase> base_;
};
static void TrackAdd(CefTrackObject* object)
{
g_scheme_tracker.Pointer()->Add(object);
}
static void TrackDelete(CefTrackObject* object)
{
g_scheme_tracker.Pointer()->Delete(object);
}
// URLRequestJob implementation.
class CefUrlRequestJob : public URLRequestJob {
public:
CefUrlRequestJob(URLRequest* request, CefRefPtr<CefSchemeHandler> handler)
: URLRequestJob(request),
url_(request->url()),
handler_(handler),
response_length_(0),
remaining_bytes_(0) { }
virtual ~CefUrlRequestJob(){}
virtual void Start()
{
handler_->Cancel();
// Continue asynchronously.
DCHECK(!async_resolver_);
async_resolver_ = new AsyncResolver(this);
WorkerPool::PostTask(FROM_HERE, NewRunnableMethod(
async_resolver_.get(), &AsyncResolver::Resolve, url_), true);
return;
}
virtual void Kill()
{
if (async_resolver_) {
async_resolver_->Cancel();
async_resolver_ = NULL;
}
URLRequestJob::Kill();
}
virtual bool ReadRawData(net::IOBuffer* dest, int dest_size, int *bytes_read)
{
DCHECK_NE(dest_size, 0);
DCHECK(bytes_read);
// When remaining_bytes_>=0, it means the handler knows the content size
// before hand. We continue to read until
if (remaining_bytes_>=0) {
if (remaining_bytes_ < dest_size)
dest_size = static_cast<int>(remaining_bytes_);
// If we should copy zero bytes because |remaining_bytes_| is zero, short
// circuit here.
if (!dest_size) {
*bytes_read = 0;
return true;
}
// remaining_bytes > 0
bool rv = handler_->ReadResponse(dest->data(), dest_size, bytes_read);
remaining_bytes_ -= *bytes_read;
if (!rv) {
// handler indicated no further data to read
*bytes_read = 0;
}
return true;
} else {
// The handler returns -1 for GetResponseLength, this means the handler
// doesn't know the content size before hand. We do basically the same
// thing, except for checking the return value for handler_->ReadResponse,
// which is an indicator for no further data to be read.
bool rv = handler_->ReadResponse(dest->data(), dest_size, bytes_read);
if (!rv)
// handler indicated no further data to read
*bytes_read = 0;
return true;
}
}
virtual bool IsRedirectResponse(GURL* location, int* http_status_code)
{
return false;
}
virtual bool GetContentEncodings(
std::vector<Filter::FilterType>* encoding_types)
{
DCHECK(encoding_types->empty());
return !encoding_types->empty();
}
virtual bool GetMimeType(std::string* mime_type) const
{
DCHECK(request_);
// call handler to get mime type
*mime_type = mime_type_;
return true;
}
virtual void SetExtraRequestHeaders(const std::string& headers)
{
}
CefRefPtr<CefSchemeHandler> handler_;
std::string mime_type_;
int response_length_;
protected:
GURL url_;
private:
void DidResolve(const GURL& url)
{
async_resolver_ = NULL;
// We may have been orphaned...
if (!request_)
return;
remaining_bytes_ = response_length_;
if (remaining_bytes_>0)
set_expected_content_size(remaining_bytes_);
NotifyHeadersComplete();
}
int64 remaining_bytes_;
std::string m_response;
class AsyncResolver :
public base::RefCountedThreadSafe<AsyncResolver> {
public:
explicit AsyncResolver(CefUrlRequestJob* owner)
: owner_(owner), owner_loop_(MessageLoop::current()) {
}
void Resolve(const GURL& url) {
AutoLock locked(lock_);
//////////////////////////////////////////////////////////////////////////
// safe to perform long operation here
CefRefPtr<CefRequest> req(CefRequest::CreateRequest());
req->SetURL(UTF8ToWide(url.spec()));
req->SetMethod(UTF8ToWide(owner_->request()->method()));
// check to see if we have post data
net::UploadData* data = owner_->request()->get_upload();
if (data) {
CefRefPtr<CefPostData> postdata(CefPostData::CreatePostData());
static_cast<CefPostDataImpl*>(postdata.get())->Set(*data);
req->SetPostData(postdata);
}
owner_->handler_->Cancel();
std::wstring mime_type;
int response_length = 0;
// handler should complete content generation in ProcessRequest
bool res = owner_->handler_->ProcessRequest(req, mime_type,
&response_length);
if (res) {
owner_->mime_type_ = WideToUTF8(mime_type);
owner_->response_length_ = response_length;
}
//////////////////////////////////////////////////////////////////////////
if (owner_loop_) {
owner_loop_->PostTask(FROM_HERE, NewRunnableMethod(
this, &AsyncResolver::ReturnResults, url));
}
}
void Cancel() {
owner_->handler_->Cancel();
owner_ = NULL;
AutoLock locked(lock_);
owner_loop_ = NULL;
}
private:
void ReturnResults(const GURL& url) {
if (owner_)
owner_->DidResolve(url);
}
CefUrlRequestJob* owner_;
Lock lock_;
MessageLoop* owner_loop_;
};
friend class AsyncResolver;
scoped_refptr<AsyncResolver> async_resolver_;
DISALLOW_COPY_AND_ASSIGN(CefUrlRequestJob);
};
// URLRequestFilter clone that manages the CefSchemeHandlerFactory pointers.
class CefUrlRequestFilter {
public:
// scheme,hostname -> ProtocolFactory
typedef std::map<std::pair<std::string, std::string>,
CefSchemeHandlerFactory*> HandlerMap;
// Singleton instance for use.
static CefUrlRequestFilter* GetInstance()
{
if (!shared_instance_)
shared_instance_ = new CefUrlRequestFilter;
return shared_instance_;
}
static URLRequestJob* Factory(URLRequest* request,
const std::string& scheme)
{
// Returning null here just means that the built-in handler will be used.
return GetInstance()->FindRequestHandler(request, scheme);
}
void AddHostnameHandler(const std::string& scheme,
const std::string& hostname,
CefSchemeHandlerFactory* factory)
{
handler_map_[make_pair(scheme, hostname)] = factory;
// Register with the ProtocolFactory.
URLRequest::RegisterProtocolFactory(scheme,
&CefUrlRequestFilter::Factory);
}
void RemoveHostnameHandler(const std::string& scheme,
const std::string& hostname)
{
HandlerMap::iterator iter =
handler_map_.find(make_pair(scheme, hostname));
DCHECK(iter != handler_map_.end());
handler_map_.erase(iter);
}
// Clear all the existing URL handlers and unregister with the
// ProtocolFactory. Resets the hit count.
void ClearHandlers()
{
// Unregister with the ProtocolFactory.
std::set<std::string> schemes;
for (HandlerMap::const_iterator i = handler_map_.begin();
i != handler_map_.end(); ++i) {
schemes.insert(i->first.first);
}
for (std::set<std::string>::const_iterator scheme = schemes.begin();
scheme != schemes.end(); ++scheme) {
URLRequest::RegisterProtocolFactory(*scheme, NULL);
}
handler_map_.clear();
hit_count_ = 0;
}
CefSchemeHandlerFactory* FindRequestHandlerFactory(URLRequest* request,
const std::string& scheme)
{
CefSchemeHandlerFactory* factory = NULL;
if (request->url().is_valid()) {
// Check for a map with a hostname first.
const std::string& hostname = request->url().host();
HandlerMap::iterator i = handler_map_.find(make_pair(scheme, hostname));
if (i != handler_map_.end())
factory = i->second;
}
if (!factory) {
// Check for a map with no specified hostname.
HandlerMap::iterator i =
handler_map_.find(make_pair(scheme, std::string()));
if (i != handler_map_.end())
factory = i->second;
}
return factory;
}
// Returns the number of times a handler was used to service a request.
int hit_count() const { return hit_count_; }
protected:
CefUrlRequestFilter() : hit_count_(0) { }
// Helper method that looks up the request in the handler_map_.
URLRequestJob* FindRequestHandler(URLRequest* request,
const std::string& scheme)
{
URLRequestJob* job = NULL;
CefSchemeHandlerFactory* factory =
FindRequestHandlerFactory(request, scheme);
if (factory) {
CefRefPtr<CefSchemeHandler> handler = factory->Create();
if (handler.get())
job = new CefUrlRequestJob(request, handler);
}
if (job) {
DLOG(INFO) << "URLRequestFilter hit for " << request->url().spec();
hit_count_++;
}
return job;
}
// Maps hostnames to factories. Hostnames take priority over URLs.
HandlerMap handler_map_;
int hit_count_;
private:
// Singleton instance.
static CefUrlRequestFilter* shared_instance_;
DISALLOW_EVIL_CONSTRUCTORS(CefUrlRequestFilter);
};
CefUrlRequestFilter* CefUrlRequestFilter::shared_instance_ = NULL;
class SchemeRequestJobWrapper {
public:
SchemeRequestJobWrapper(const std::string& scheme_name,
const std::string& host_name,
CefSchemeHandlerFactory* factory)
: factory_(factory), scheme_name_(scheme_name), host_name_(host_name)
{
// The reference will be released when the application exits.
TrackAdd(new TrackBase(factory));
}
void RegisterScheme()
{
// we need to store the pointer of this handler because
// we can't pass it as a parameter to the factory method
CefUrlRequestFilter::GetInstance()->AddHostnameHandler(
scheme_name_, host_name_, factory_);
}
void AddRef() {}
void Release() {}
private:
CefSchemeHandlerFactory* factory_;
std::string scheme_name_;
std::string host_name_;
};
bool CefRegisterScheme(const std::wstring& scheme_name,
const std::wstring& host_name,
CefRefPtr<CefSchemeHandlerFactory> factory)
{
// Verify that the context is already initialized
if(!_Context.get())
return false;
SchemeRequestJobWrapper* wrapper = new SchemeRequestJobWrapper(
WideToUTF8(scheme_name), WideToUTF8(host_name), factory);
PostTask(FROM_HERE, NewRunnableMethod(wrapper,
&SchemeRequestJobWrapper::RegisterScheme));
return true;
}

View File

@ -0,0 +1,85 @@
// Copyright (c) 2009 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.
//
// ---------------------------------------------------------------------------
//
// A portion of this file was generated by the CEF translator tool. When
// making changes by hand only do so within the body of existing function
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
#include "../precompiled_libcef.h"
#include "cpptoc/scheme_handler_cpptoc.h"
#include "ctocpp/request_ctocpp.h"
#include "../transfer_util.h"
// MEMBER FUNCTIONS - Body may be edited by hand.
int CEF_CALLBACK scheme_handler_process_request(
struct _cef_scheme_handler_t* self, cef_request_t* request,
cef_string_t* mime_type, int* response_length)
{
DCHECK(self);
DCHECK(request);
DCHECK(mime_type);
DCHECK(response_length);
if(!self || !request || !mime_type || !response_length)
return 0;
std::wstring mimeTypeStr;
if(*mime_type)
mimeTypeStr = *mime_type;
bool rv = CefSchemeHandlerCppToC::Get(self)->ProcessRequest(
CefRequestCToCpp::Wrap(request), mimeTypeStr, response_length);
transfer_string_contents(mimeTypeStr, mime_type);
return rv?1:0;
}
void CEF_CALLBACK scheme_handler_cancel(struct _cef_scheme_handler_t* self)
{
DCHECK(self);
if(!self)
return;
CefSchemeHandlerCppToC::Get(self)->Cancel();
}
int CEF_CALLBACK scheme_handler_read_response(
struct _cef_scheme_handler_t* self, void* data_out, int bytes_to_read,
int* bytes_read)
{
DCHECK(self);
DCHECK(data_out);
DCHECK(bytes_read);
if(!self || !data_out || !bytes_read)
return 0;
bool rv = CefSchemeHandlerCppToC::Get(self)->ReadResponse(
data_out, bytes_to_read, bytes_read);
return rv?1:0;
}
// CONSTRUCTOR - Do not edit by hand.
CefSchemeHandlerCppToC::CefSchemeHandlerCppToC(CefSchemeHandler* cls)
: CefCppToC<CefSchemeHandlerCppToC, CefSchemeHandler, cef_scheme_handler_t>(
cls)
{
struct_.struct_.process_request = scheme_handler_process_request;
struct_.struct_.cancel = scheme_handler_cancel;
struct_.struct_.read_response = scheme_handler_read_response;
}
#ifdef _DEBUG
long CefCppToC<CefSchemeHandlerCppToC, CefSchemeHandler,
cef_scheme_handler_t>::DebugObjCt = 0;
#endif

View File

@ -0,0 +1,35 @@
// Copyright (c) 2009 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.
//
// ---------------------------------------------------------------------------
//
// This file was generated by the CEF translator tool and should not edited
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
#ifndef _SCHEMEHANDLER_CPPTOC_H
#define _SCHEMEHANDLER_CPPTOC_H
#ifndef USING_CEF_SHARED
#pragma message("Warning: "__FILE__" may be accessed wrapper-side only")
#else // USING_CEF_SHARED
#include "cef.h"
#include "cef_capi.h"
#include "cpptoc.h"
// Wrap a C++ class with a C structure.
// This class may be instantiated and accessed wrapper-side only.
class CefSchemeHandlerCppToC
: public CefCppToC<CefSchemeHandlerCppToC, CefSchemeHandler,
cef_scheme_handler_t>
{
public:
CefSchemeHandlerCppToC(CefSchemeHandler* cls);
virtual ~CefSchemeHandlerCppToC() {}
};
#endif // USING_CEF_SHARED
#endif // _SCHEMEHANDLER_CPPTOC_H

View File

@ -0,0 +1,44 @@
// Copyright (c) 2009 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.
//
// ---------------------------------------------------------------------------
//
// A portion of this file was generated by the CEF translator tool. When
// making changes by hand only do so within the body of existing function
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
#include "../precompiled_libcef.h"
#include "cpptoc/scheme_handler_cpptoc.h"
#include "cpptoc/scheme_handler_factory_cpptoc.h"
// MEMBER FUNCTIONS - Body may be edited by hand.
struct _cef_scheme_handler_t* CEF_CALLBACK scheme_handler_factory_create(
struct _cef_scheme_handler_factory_t* self)
{
CefRefPtr<CefSchemeHandler> rv =
CefSchemeHandlerFactoryCppToC::Get(self)->Create();
return CefSchemeHandlerCppToC::Wrap(rv);
}
// CONSTRUCTOR - Do not edit by hand.
CefSchemeHandlerFactoryCppToC::CefSchemeHandlerFactoryCppToC(
CefSchemeHandlerFactory* cls)
: CefCppToC<CefSchemeHandlerFactoryCppToC, CefSchemeHandlerFactory,
cef_scheme_handler_factory_t>(cls)
{
struct_.struct_.create = scheme_handler_factory_create;
}
#ifdef _DEBUG
long CefCppToC<CefSchemeHandlerFactoryCppToC, CefSchemeHandlerFactory,
cef_scheme_handler_factory_t>::DebugObjCt = 0;
#endif

View File

@ -0,0 +1,35 @@
// Copyright (c) 2009 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.
//
// ---------------------------------------------------------------------------
//
// This file was generated by the CEF translator tool and should not edited
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
#ifndef _SCHEMEHANDLERFACTORY_CPPTOC_H
#define _SCHEMEHANDLERFACTORY_CPPTOC_H
#ifndef USING_CEF_SHARED
#pragma message("Warning: "__FILE__" may be accessed wrapper-side only")
#else // USING_CEF_SHARED
#include "cef.h"
#include "cef_capi.h"
#include "cpptoc.h"
// Wrap a C++ class with a C structure.
// This class may be instantiated and accessed wrapper-side only.
class CefSchemeHandlerFactoryCppToC
: public CefCppToC<CefSchemeHandlerFactoryCppToC, CefSchemeHandlerFactory,
cef_scheme_handler_factory_t>
{
public:
CefSchemeHandlerFactoryCppToC(CefSchemeHandlerFactory* cls);
virtual ~CefSchemeHandlerFactoryCppToC() {}
};
#endif // USING_CEF_SHARED
#endif // _SCHEMEHANDLERFACTORY_CPPTOC_H

View File

@ -0,0 +1,61 @@
// Copyright (c) 2009 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.
//
// ---------------------------------------------------------------------------
//
// A portion of this file was generated by the CEF translator tool. When
// making changes by hand only do so within the body of existing static and
// virtual method implementations. See the translator.README.txt file in the
// tools directory for more information.
//
#include "../precompiled_libcef.h"
#include "cpptoc/request_cpptoc.h"
#include "ctocpp/scheme_handler_ctocpp.h"
#include "../transfer_util.h"
// VIRTUAL METHODS - Body may be edited by hand.
bool CefSchemeHandlerCToCpp::ProcessRequest(CefRefPtr<CefRequest> request,
std::wstring& mime_type, int* response_length)
{
if(CEF_MEMBER_MISSING(struct_, process_request))
return false;
cef_string_t mimeTypeRet = NULL;
if(!mime_type.empty())
mimeTypeRet = cef_string_alloc(mime_type.c_str());
int rv = struct_->process_request(struct_, CefRequestCppToC::Wrap(request),
&mimeTypeRet, response_length);
transfer_string_contents(mimeTypeRet, mime_type, true);
return rv;
}
void CefSchemeHandlerCToCpp::Cancel()
{
if(CEF_MEMBER_MISSING(struct_, cancel))
return;
struct_->cancel(struct_);
}
bool CefSchemeHandlerCToCpp::ReadResponse(void* data_out, int bytes_to_read,
int* bytes_read)
{
if(CEF_MEMBER_MISSING(struct_, read_response))
return false;
return struct_->read_response(struct_, data_out, bytes_to_read, bytes_read);
}
#ifdef _DEBUG
long CefCToCpp<CefSchemeHandlerCToCpp, CefSchemeHandler,
cef_scheme_handler_t>::DebugObjCt = 0;
#endif

View File

@ -0,0 +1,44 @@
// Copyright (c) 2009 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.
//
// -------------------------------------------------------------------------
//
// This file was generated by the CEF translator tool and should not edited
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
#ifndef _SCHEMEHANDLER_CTOCPP_H
#define _SCHEMEHANDLER_CTOCPP_H
#ifndef BUILDING_CEF_SHARED
#pragma message("Warning: "__FILE__" may be accessed DLL-side only")
#else // BUILDING_CEF_SHARED
#include "cef.h"
#include "cef_capi.h"
#include "ctocpp.h"
// Wrap a C structure with a C++ class.
// This class may be instantiated and accessed DLL-side only.
class CefSchemeHandlerCToCpp
: public CefCToCpp<CefSchemeHandlerCToCpp, CefSchemeHandler,
cef_scheme_handler_t>
{
public:
CefSchemeHandlerCToCpp(cef_scheme_handler_t* str)
: CefCToCpp<CefSchemeHandlerCToCpp, CefSchemeHandler,
cef_scheme_handler_t>(str) {}
virtual ~CefSchemeHandlerCToCpp() {}
// CefSchemeHandler methods
virtual bool ProcessRequest(CefRefPtr<CefRequest> request,
std::wstring& mime_type, int* response_length);
virtual void Cancel();
virtual bool ReadResponse(void* data_out, int bytes_to_read, int* bytes_read);
};
#endif // BUILDING_CEF_SHARED
#endif // _SCHEMEHANDLER_CTOCPP_H

View File

@ -0,0 +1,35 @@
// Copyright (c) 2009 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.
//
// ---------------------------------------------------------------------------
//
// A portion of this file was generated by the CEF translator tool. When
// making changes by hand only do so within the body of existing static and
// virtual method implementations. See the translator.README.txt file in the
// tools directory for more information.
//
#include "../precompiled_libcef.h"
#include "ctocpp/scheme_handler_ctocpp.h"
#include "ctocpp/scheme_handler_factory_ctocpp.h"
// VIRTUAL METHODS - Body may be edited by hand.
CefRefPtr<CefSchemeHandler> CefSchemeHandlerFactoryCToCpp::Create()
{
if(CEF_MEMBER_MISSING(struct_, create))
return NULL;
_cef_scheme_handler_t* rv = struct_->create(struct_);
return CefSchemeHandlerCToCpp::Wrap(rv);
}
#ifdef _DEBUG
long CefCToCpp<CefSchemeHandlerFactoryCToCpp, CefSchemeHandlerFactory,
cef_scheme_handler_factory_t>::DebugObjCt = 0;
#endif

View File

@ -0,0 +1,41 @@
// Copyright (c) 2009 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.
//
// -------------------------------------------------------------------------
//
// This file was generated by the CEF translator tool and should not edited
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
#ifndef _SCHEMEHANDLERFACTORY_CTOCPP_H
#define _SCHEMEHANDLERFACTORY_CTOCPP_H
#ifndef BUILDING_CEF_SHARED
#pragma message("Warning: "__FILE__" may be accessed DLL-side only")
#else // BUILDING_CEF_SHARED
#include "cef.h"
#include "cef_capi.h"
#include "ctocpp.h"
// Wrap a C structure with a C++ class.
// This class may be instantiated and accessed DLL-side only.
class CefSchemeHandlerFactoryCToCpp
: public CefCToCpp<CefSchemeHandlerFactoryCToCpp, CefSchemeHandlerFactory,
cef_scheme_handler_factory_t>
{
public:
CefSchemeHandlerFactoryCToCpp(cef_scheme_handler_factory_t* str)
: CefCToCpp<CefSchemeHandlerFactoryCToCpp, CefSchemeHandlerFactory,
cef_scheme_handler_factory_t>(str) {}
virtual ~CefSchemeHandlerFactoryCToCpp() {}
// CefSchemeHandlerFactory methods
virtual CefRefPtr<CefSchemeHandler> Create();
};
#endif // BUILDING_CEF_SHARED
#endif // _SCHEMEHANDLERFACTORY_CTOCPP_H

View File

@ -16,6 +16,8 @@
#include "cpptoc/stream_writer_cpptoc.h"
#include "cpptoc/v8value_cpptoc.h"
#include "ctocpp/handler_ctocpp.h"
#include "ctocpp/scheme_handler_ctocpp.h"
#include "ctocpp/scheme_handler_factory_ctocpp.h"
#include "ctocpp/v8handler_ctocpp.h"
#include "base/string_util.h"
@ -43,6 +45,8 @@ CEF_EXPORT void cef_shutdown()
DCHECK(CefStreamWriterCppToC::DebugObjCt == 0);
DCHECK(CefV8ValueCppToC::DebugObjCt == 0);
DCHECK(CefHandlerCToCpp::DebugObjCt == 0);
DCHECK(CefSchemeHandlerCToCpp::DebugObjCt == 0);
DCHECK(CefSchemeHandlerFactoryCToCpp::DebugObjCt == 0);
DCHECK(CefV8HandlerCToCpp::DebugObjCt == 0);
#endif // _DEBUG
}
@ -107,3 +111,22 @@ CEF_EXPORT int cef_register_plugin(const cef_plugin_info_t* plugin_info)
return CefRegisterPlugin(pluginInfo);
}
CEF_EXPORT int cef_register_scheme(const wchar_t* scheme_name,
const wchar_t* host_name, struct _cef_scheme_handler_factory_t* factory)
{
DCHECK(scheme_name);
DCHECK(factory);
if(!scheme_name || !factory)
return 0;
std::wstring nameStr, codeStr;
if(scheme_name)
nameStr = scheme_name;
if(host_name)
codeStr = host_name;
return CefRegisterScheme(nameStr, codeStr,
CefSchemeHandlerFactoryCToCpp::Wrap(factory));
}

View File

@ -430,6 +430,54 @@
RelativePath=".\ctocpp\handler_ctocpp.h"
>
</File>
<File
RelativePath=".\ctocpp\scheme_handler_ctocpp.cc"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
PrecompiledHeaderThrough="../precompiled_libcef.h"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
PrecompiledHeaderThrough="../precompiled_libcef.h"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\ctocpp\scheme_handler_ctocpp.h"
>
</File>
<File
RelativePath=".\ctocpp\scheme_handler_factory_ctocpp.cc"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
PrecompiledHeaderThrough="../precompiled_libcef.h"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
PrecompiledHeaderThrough="../precompiled_libcef.h"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\ctocpp\scheme_handler_factory_ctocpp.h"
>
</File>
<File
RelativePath=".\ctocpp\v8handler_ctocpp.cc"
>

View File

@ -8,6 +8,8 @@
#include "cef_nplugin.h"
#include "cef_nplugin_capi.h"
#include "../cpptoc/handler_cpptoc.h"
#include "../cpptoc/scheme_handler_cpptoc.h"
#include "../cpptoc/scheme_handler_factory_cpptoc.h"
#include "../cpptoc/v8handler_cpptoc.h"
#include "../ctocpp/browser_ctocpp.h"
#include "../ctocpp/post_data_ctocpp.h"
@ -31,6 +33,8 @@ void CefShutdown()
#ifdef _DEBUG
// Check that all wrapper objects have been destroyed
DCHECK(CefHandlerCppToC::DebugObjCt == 0);
DCHECK(CefSchemeHandlerCppToC::DebugObjCt == 0);
DCHECK(CefSchemeHandlerFactoryCppToC::DebugObjCt == 0);
DCHECK(CefV8HandlerCppToC::DebugObjCt == 0);
DCHECK(CefBrowserCToCpp::DebugObjCt == 0);
DCHECK(CefRequestCToCpp::DebugObjCt == 0);
@ -95,3 +99,11 @@ bool CefRegisterPlugin(const struct CefPluginInfo& plugin_info)
return (cef_register_plugin(&pluginInfo) ? true : false);
}
bool CefRegisterScheme(const std::wstring& scheme_name,
const std::wstring& host_name,
CefRefPtr<CefSchemeHandlerFactory> factory)
{
return cef_register_scheme(scheme_name.c_str(), host_name.c_str(),
CefSchemeHandlerFactoryCppToC::Wrap(factory));
}

View File

@ -141,6 +141,22 @@
RelativePath="..\cpptoc\handler_cpptoc.h"
>
</File>
<File
RelativePath="..\cpptoc\scheme_handler_cpptoc.cc"
>
</File>
<File
RelativePath="..\cpptoc\scheme_handler_cpptoc.h"
>
</File>
<File
RelativePath="..\cpptoc\scheme_handler_factory_cpptoc.cc"
>
</File>
<File
RelativePath="..\cpptoc\scheme_handler_factory_cpptoc.h"
>
</File>
<File
RelativePath="..\cpptoc\v8handler_cpptoc.cc"
>

View File

@ -33,11 +33,107 @@ INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
// Convert a std::string to a std::wstring
std::wstring StringToWString(const std::string& s)
{
std::wstring temp(s.length(),L' ');
std::copy(s.begin(), s.end(), temp.begin());
return temp;
wchar_t* wch;
UINT bytes = MultiByteToWideChar(CP_ACP, 0, s.c_str(), s.size()+1, NULL, 0);
wch = new wchar_t[bytes];
if(wch)
bytes = MultiByteToWideChar(CP_ACP, 0, s.c_str(), s.size()+1, wch, bytes);
std::wstring str = wch;
delete [] wch;
return str;
}
// Convert a std::wstring to a std::string
std::string WStringToString(const std::wstring& s)
{
char* ch;
UINT bytes = WideCharToMultiByte(CP_ACP, 0, s.c_str(), s.size()+1, NULL, 0,
NULL, NULL);
ch = new char[bytes];
if(ch)
bytes = WideCharToMultiByte(CP_ACP, 0, s.c_str(), s.size()+1, ch, bytes,
NULL, NULL);
std::string str = ch;
delete [] ch;
return str;
}
// Load a resource of type BINARY
bool LoadBinaryResource(int binaryId, DWORD &dwSize, LPBYTE &pBytes)
{
HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(binaryId),
MAKEINTRESOURCE(256));
if(hRes)
{
HGLOBAL hGlob = LoadResource(hInst, hRes);
if(hGlob)
{
dwSize = SizeofResource(hInst, hRes);
pBytes = (LPBYTE)LockResource(hGlob);
if(dwSize > 0 && pBytes)
return true;
}
}
return false;
}
// Dump the contents of the request into a string.
void DumpRequestContents(CefRefPtr<CefRequest> request, std::wstring& str)
{
std::wstringstream ss;
ss << L"URL: " << request->GetURL();
ss << L"\nMethod: " << request->GetMethod();
CefRequest::HeaderMap headerMap;
request->GetHeaderMap(headerMap);
if(headerMap.size() > 0) {
ss << L"\nHeaders:";
CefRequest::HeaderMap::const_iterator it = headerMap.begin();
for(; it != headerMap.end(); ++it) {
ss << L"\n\t" << (*it).first << L": " << (*it).second;
}
}
CefRefPtr<CefPostData> postData = request->GetPostData();
if(postData.get()) {
CefPostData::ElementVector elements;
postData->GetElements(elements);
if(elements.size() > 0) {
ss << L"\nPost Data:";
CefRefPtr<CefPostDataElement> element;
CefPostData::ElementVector::const_iterator it = elements.begin();
for(; it != elements.end(); ++it) {
element = (*it);
if(element->GetType() == PDE_TYPE_BYTES) {
// the element is composed of bytes
ss << L"\n\tBytes: ";
if(element->GetBytesCount() == 0)
ss << L"(empty)";
else {
// retrieve the data.
size_t size = element->GetBytesCount();
char* bytes = new char[size];
element->GetBytes(size, bytes);
ss << StringToWString(std::string(bytes, size));
delete [] bytes;
}
} else if(element->GetType() == PDE_TYPE_FILE) {
ss << L"\n\tFile: " << element->GetFile();
}
}
}
}
str = ss.str();
}
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif
// Implementation of the V8 handler class for the "cef.test" extension.
class ClientV8ExtensionHandler : public CefThreadSafeBase<CefV8Handler>
{
@ -97,6 +193,123 @@ private:
std::wstring test_param_;
};
// Implementation of the schema handler for client:// requests.
class ClientSchemeHandler : public CefThreadSafeBase<CefSchemeHandler>
{
public:
ClientSchemeHandler() : size_(0), offset_(0), bytes_(NULL) {}
// Process the request. All response generation should take place in this
// method. If there is no response set |response_length| to zero and
// ReadResponse() will not be called. If the response length is not known then
// set |response_length| to -1 and ReadResponse() will be called until it
// returns false or until the value of |bytes_read| is set to 0. Otherwise,
// set |response_length| to a positive value and ReadResponse() will be called
// until it returns false, the value of |bytes_read| is set to 0 or the
// specified number of bytes have been read. If there is a response set
// |mime_type| to the mime type for the response.
virtual bool ProcessRequest(CefRefPtr<CefRequest> request,
std::wstring& mime_type, int* response_length)
{
bool handled = false;
Lock();
std::wstring url = request->GetURL();
if(wcsstr(url.c_str(), L"handler.html") != NULL) {
// Build the response html
html_ = "<html><head><title>Client Scheme Handler</title></head><body>"
"This contents of this page page are served by the "
"ClientSchemeHandler class handling the client:// protocol."
"<br>You should see an image:"
"<br/><img src=\"client://tests/client.gif\"><pre>";
// Output a string representation of the request
std::wstring dump;
DumpRequestContents(request, dump);
html_.append(WStringToString(dump));
html_.append("</pre><br>Try the test form:"
"<form method=\"POST\" action=\"handler.html\">"
"<input type=\"text\" name=\"field1\">"
"<input type=\"text\" name=\"field2\">"
"<input type=\"submit\">"
"</form></body></html>");
handled = true;
size_ = html_.size();
bytes_ = (LPBYTE)html_.c_str();
// Set the resulting mime type
mime_type = L"text/html";
}
else if(wcsstr(url.c_str(), L"client.gif") != NULL) {
// Load the response image
if(LoadBinaryResource(IDS_LOGO, size_, bytes_)) {
handled = true;
// Set the resulting mime type
mime_type = L"image/jpg";
}
}
// Set the resulting response length
*response_length = size_;
Unlock();
return handled;
}
// Cancel processing of the request.
virtual void Cancel()
{
}
// Copy up to |bytes_to_read| bytes into |data_out|. If the copy succeeds
// set |bytes_read| to the number of bytes copied and return true. If the
// copy fails return false and ReadResponse() will not be called again.
virtual bool ReadResponse(void* data_out, int bytes_to_read,
int* bytes_read)
{
bool has_data = false;
*bytes_read = 0;
Lock();
if(offset_ < size_) {
// Copy the next block of data into the buffer.
int transfer_size = min(bytes_to_read, static_cast<int>(size_ - offset_));
memcpy(data_out, bytes_ + offset_, transfer_size);
offset_ += transfer_size;
*bytes_read = transfer_size;
has_data = true;
}
Unlock();
return has_data;
}
private:
DWORD size_, offset_;
LPBYTE bytes_;
std::string html_;
};
// Implementation of the factory for for creating schema handlers.
class ClientSchemeHandlerFactory :
public CefThreadSafeBase<CefSchemeHandlerFactory>
{
public:
// Return a new scheme handler instance to handle the request.
virtual CefRefPtr<CefSchemeHandler> Create()
{
return new ClientSchemeHandler();
}
};
// Program entry point function.
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
@ -156,6 +369,10 @@ int APIENTRY _tWinMain(HINSTANCE hInstance,
L"})();";
CefRegisterExtension(L"v8/test", code, new ClientV8ExtensionHandler());
// Register the scheme handler factory for requests using the client://
// protocol in the tests domain.
CefRegisterScheme(L"client", L"tests", new ClientSchemeHandlerFactory());
MSG msg;
HACCEL hAccelTable;
@ -260,26 +477,6 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
return TRUE;
}
// Load a resource of type BINARY
bool LoadBinaryResource(int binaryId, DWORD &dwSize, LPBYTE &pBytes)
{
HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(binaryId),
MAKEINTRESOURCE(256));
if(hRes)
{
HGLOBAL hGlob = LoadResource(hInst, hRes);
if(hGlob)
{
dwSize = SizeofResource(hInst, hRes);
pBytes = (LPBYTE)LockResource(hGlob);
if(dwSize > 0 && pBytes)
return true;
}
}
return false;
}
// Implementation of the V8 handler class for the "window.cef_test.Dump"
// function.
class ClientV8FunctionHandler : public CefThreadSafeBase<CefV8Handler>
@ -577,54 +774,10 @@ public:
std::wstring url = request->GetURL();
if(url == L"http://tests/request") {
// Show the request contents
std::wstringstream ss;
ss << L"URL: " << url;
ss << L"\nMethod: " << request->GetMethod();
CefRequest::HeaderMap headerMap;
request->GetHeaderMap(headerMap);
if(headerMap.size() > 0) {
ss << L"\nHeaders:";
CefRequest::HeaderMap::const_iterator it = headerMap.begin();
for(; it != headerMap.end(); ++it) {
ss << L"\n\t" << (*it).first << L": " << (*it).second;
}
}
CefRefPtr<CefPostData> postData = request->GetPostData();
if(postData.get()) {
CefPostData::ElementVector elements;
postData->GetElements(elements);
if(elements.size() > 0) {
ss << L"\nPost Data:";
CefRefPtr<CefPostDataElement> element;
CefPostData::ElementVector::const_iterator it = elements.begin();
for(; it != elements.end(); ++it) {
element = (*it);
if(element->GetType() == PDE_TYPE_BYTES) {
// the element is composed of bytes
ss << L"\n\tBytes: ";
if(element->GetBytesCount() == 0)
ss << L"(empty)";
else {
// retrieve the data.
size_t size = element->GetBytesCount();
char* bytes = new char[size];
element->GetBytes(size, bytes);
ss << StringToWString(std::string(bytes, size));
delete [] bytes;
}
} else if(element->GetType() == PDE_TYPE_FILE) {
ss << L"\n\tFile: " << element->GetFile();
}
}
}
}
std::wstring str = ss.str();
std::wstring dump;
DumpRequestContents(request, dump);
resourceStream = CefStreamReader::CreateForData(
(void*)str.c_str(), str.size() * sizeof(wchar_t));
(void*)dump.c_str(), dump.size() * sizeof(wchar_t));
mimeType = L"text/plain";
} else if(wcsstr(url.c_str(), L"logo.gif") != NULL) {
// Any time we find "logo.gif" in the URL substitute in our own image
@ -1110,6 +1263,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
browser->GetMainFrame()->LoadRequest(request);
}
return 0;
case ID_TESTS_SCHEME_HANDLER: // Test the scheme handler
if(browser.get())
browser->GetMainFrame()->LoadURL(L"client://tests/handler.html");
return 0;
}
}
break;

View File

@ -63,6 +63,7 @@ BEGIN
MENUITEM "Plugin", ID_TESTS_PLUGIN
MENUITEM "Popup Window", ID_TESTS_POPUP
MENUITEM "Request", ID_TESTS_REQUEST
MENUITEM "Scheme Handler", ID_TESTS_SCHEME_HANDLER
END
END

View File

@ -27,6 +27,7 @@
#define ID_TESTS_PLUGIN 32774
#define ID_TESTS_POPUP 32775
#define ID_TESTS_REQUEST 32776
#define ID_TESTS_SCHEME_HANDLER 32777
#define IDC_STATIC -1
#define IDS_LOGO 1000