mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Add support for loading extensions (issue #1947)
- Add CefRequestContext::LoadExtension, CefExtension, CefExtensionHandler and related methods/interfaces. - Add chrome://extensions-support that lists supported Chrome APIs. - Add CefBrowserHost::SetAutoResizeEnabled and CefDisplayHandler::OnAutoResize to support browser resize based on preferred web contents size. - views: Add support for custom CefMenuButton popups. - cefclient: Run with `--load-extension=set_page_color` command-line flag for an extension loading example. Add `--use-views` on Windows and Linux for an even better example.
This commit is contained in:
239
tests/shared/browser/extension_util.cc
Normal file
239
tests/shared/browser/extension_util.cc
Normal file
@ -0,0 +1,239 @@
|
||||
// Copyright (c) 2017 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 "tests/shared/browser/extension_util.h"
|
||||
|
||||
#include "include/base/cef_bind.h"
|
||||
#include "include/cef_parser.h"
|
||||
#include "include/cef_path_util.h"
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
#include "tests/shared/browser/file_util.h"
|
||||
#include "tests/shared/browser/resource_util.h"
|
||||
|
||||
namespace client {
|
||||
namespace extension_util {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string GetResourcesPath() {
|
||||
CefString resources_dir;
|
||||
if (CefGetPath(PK_DIR_RESOURCES, resources_dir) && !resources_dir.empty()) {
|
||||
return resources_dir.ToString() + file_util::kPathSep;
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
// Internal extension paths may be prefixed with PK_DIR_RESOURCES and always
|
||||
// use forward slash as path separator.
|
||||
std::string GetInternalPath(const std::string& extension_path) {
|
||||
const std::string& resources_path = GetResourcesPath();
|
||||
std::string internal_path;
|
||||
if (!resources_path.empty() && extension_path.find(resources_path) == 0U) {
|
||||
internal_path = extension_path.substr(resources_path.size());
|
||||
} else {
|
||||
internal_path = extension_path;
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Normalize path separators.
|
||||
std::replace(internal_path.begin(), internal_path.end(), '\\', '/');
|
||||
#endif
|
||||
|
||||
return internal_path;
|
||||
}
|
||||
|
||||
typedef base::Callback<void(CefRefPtr<CefDictionaryValue> /*manifest*/)>
|
||||
ManifestCallback;
|
||||
|
||||
void RunManifestCallback(const ManifestCallback& callback,
|
||||
CefRefPtr<CefDictionaryValue> manifest) {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
// Execute on the browser UI thread.
|
||||
CefPostTask(TID_UI, base::Bind(RunManifestCallback, callback, manifest));
|
||||
return;
|
||||
}
|
||||
callback.Run(manifest);
|
||||
}
|
||||
|
||||
// Asynchronously reads the manifest and executes |callback| on the UI thread.
|
||||
void GetInternalManifest(const std::string& extension_path,
|
||||
const ManifestCallback& callback) {
|
||||
if (!CefCurrentlyOn(TID_FILE)) {
|
||||
// Execute on the browser FILE thread.
|
||||
CefPostTask(TID_FILE,
|
||||
base::Bind(GetInternalManifest, extension_path, callback));
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string& manifest_path = GetInternalExtensionResourcePath(
|
||||
file_util::JoinPath(extension_path, "manifest.json"));
|
||||
std::string manifest_contents;
|
||||
if (!LoadBinaryResource(manifest_path.c_str(), manifest_contents) ||
|
||||
manifest_contents.empty()) {
|
||||
LOG(ERROR) << "Failed to load manifest from " << manifest_path;
|
||||
RunManifestCallback(callback, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
cef_json_parser_error_t error_code;
|
||||
CefString error_msg;
|
||||
CefRefPtr<CefValue> value = CefParseJSONAndReturnError(
|
||||
manifest_contents, JSON_PARSER_RFC, error_code, error_msg);
|
||||
if (!value || value->GetType() != VTYPE_DICTIONARY) {
|
||||
if (error_msg.empty())
|
||||
error_msg = "Incorrectly formatted dictionary contents.";
|
||||
LOG(ERROR) << "Failed to parse manifest from " << manifest_path << "; "
|
||||
<< error_msg.ToString();
|
||||
RunManifestCallback(callback, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
RunManifestCallback(callback, value->GetDictionary());
|
||||
}
|
||||
|
||||
void LoadExtensionWithManifest(CefRefPtr<CefRequestContext> request_context,
|
||||
const std::string& extension_path,
|
||||
CefRefPtr<CefExtensionHandler> handler,
|
||||
CefRefPtr<CefDictionaryValue> manifest) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
// Load the extension internally. Resource requests will be handled via
|
||||
// AddInternalExtensionToResourceManager.
|
||||
request_context->LoadExtension(extension_path, manifest, handler);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool IsInternalExtension(const std::string& extension_path) {
|
||||
// List of internally handled extensions.
|
||||
static const char* extensions[] = {"set_page_color"};
|
||||
|
||||
const std::string& internal_path = GetInternalPath(extension_path);
|
||||
for (size_t i = 0; i < arraysize(extensions); ++i) {
|
||||
// Exact match or first directory component.
|
||||
const std::string& extension = extensions[i];
|
||||
if (internal_path == extension ||
|
||||
internal_path.find(extension + '/') == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string GetInternalExtensionResourcePath(
|
||||
const std::string& extension_path) {
|
||||
return "extensions/" + GetInternalPath(extension_path);
|
||||
}
|
||||
|
||||
std::string GetExtensionResourcePath(const std::string& extension_path,
|
||||
bool* internal) {
|
||||
const bool is_internal = IsInternalExtension(extension_path);
|
||||
if (internal)
|
||||
*internal = is_internal;
|
||||
if (is_internal)
|
||||
return GetInternalExtensionResourcePath(extension_path);
|
||||
return extension_path;
|
||||
}
|
||||
|
||||
bool GetExtensionResourceContents(const std::string& extension_path,
|
||||
std::string& contents) {
|
||||
CEF_REQUIRE_FILE_THREAD();
|
||||
|
||||
if (IsInternalExtension(extension_path)) {
|
||||
const std::string& contents_path =
|
||||
GetInternalExtensionResourcePath(extension_path);
|
||||
return LoadBinaryResource(contents_path.c_str(), contents);
|
||||
}
|
||||
|
||||
return file_util::ReadFileToString(extension_path, &contents);
|
||||
}
|
||||
|
||||
void LoadExtension(CefRefPtr<CefRequestContext> request_context,
|
||||
const std::string& extension_path,
|
||||
CefRefPtr<CefExtensionHandler> handler) {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
// Execute on the browser UI thread.
|
||||
CefPostTask(TID_UI, base::Bind(LoadExtension, request_context,
|
||||
extension_path, handler));
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsInternalExtension(extension_path)) {
|
||||
// Read the extension manifest and load asynchronously.
|
||||
GetInternalManifest(extension_path,
|
||||
base::Bind(LoadExtensionWithManifest, request_context,
|
||||
extension_path, handler));
|
||||
} else {
|
||||
// Load the extension from disk.
|
||||
request_context->LoadExtension(extension_path, NULL, handler);
|
||||
}
|
||||
}
|
||||
|
||||
void AddInternalExtensionToResourceManager(
|
||||
CefRefPtr<CefExtension> extension,
|
||||
CefRefPtr<CefResourceManager> resource_manager) {
|
||||
DCHECK(IsInternalExtension(extension->GetPath()));
|
||||
|
||||
if (!CefCurrentlyOn(TID_IO)) {
|
||||
// Execute on the browser IO thread.
|
||||
CefPostTask(TID_IO, base::Bind(AddInternalExtensionToResourceManager,
|
||||
extension, resource_manager));
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string& origin = GetExtensionOrigin(extension->GetIdentifier());
|
||||
const std::string& resource_path =
|
||||
GetInternalExtensionResourcePath(extension->GetPath());
|
||||
|
||||
// Add provider for bundled resource files.
|
||||
#if defined(OS_WIN)
|
||||
// Read resources from the binary.
|
||||
resource_manager->AddProvider(
|
||||
CreateBinaryResourceProvider(origin, resource_path), 50, std::string());
|
||||
#elif defined(OS_POSIX)
|
||||
// Read resources from a directory on disk.
|
||||
std::string resource_dir;
|
||||
if (GetResourceDir(resource_dir)) {
|
||||
resource_dir += "/" + resource_path;
|
||||
resource_manager->AddDirectoryProvider(origin, resource_dir, 50,
|
||||
std::string());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string GetExtensionOrigin(const std::string& extension_id) {
|
||||
return "chrome-extension://" + extension_id + "/";
|
||||
}
|
||||
|
||||
std::string GetExtensionURL(CefRefPtr<CefExtension> extension) {
|
||||
CefRefPtr<CefDictionaryValue> browser_action =
|
||||
extension->GetManifest()->GetDictionary("browser_action");
|
||||
if (browser_action) {
|
||||
const std::string& default_popup =
|
||||
browser_action->GetString("default_popup");
|
||||
if (!default_popup.empty())
|
||||
return GetExtensionOrigin(extension->GetIdentifier()) + default_popup;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string GetExtensionIconPath(CefRefPtr<CefExtension> extension,
|
||||
bool* internal) {
|
||||
CefRefPtr<CefDictionaryValue> browser_action =
|
||||
extension->GetManifest()->GetDictionary("browser_action");
|
||||
if (browser_action) {
|
||||
const std::string& default_icon = browser_action->GetString("default_icon");
|
||||
if (!default_icon.empty()) {
|
||||
return GetExtensionResourcePath(
|
||||
file_util::JoinPath(extension->GetPath(), default_icon), internal);
|
||||
}
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
} // namespace extension_util
|
||||
} // namespace client
|
80
tests/shared/browser/extension_util.h
Normal file
80
tests/shared/browser/extension_util.h
Normal file
@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2017 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_TESTS_CEFCLIENT_BROWSER_EXTENSION_UTIL_H_
|
||||
#define CEF_TESTS_CEFCLIENT_BROWSER_EXTENSION_UTIL_H_
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "include/cef_extension.h"
|
||||
#include "include/cef_extension_handler.h"
|
||||
#include "include/wrapper/cef_resource_manager.h"
|
||||
|
||||
namespace client {
|
||||
namespace extension_util {
|
||||
|
||||
// Returns true if |extension_path| can be handled internally via
|
||||
// LoadBinaryResource. This checks a hard-coded list of allowed extension path
|
||||
// components.
|
||||
bool IsInternalExtension(const std::string& extension_path);
|
||||
|
||||
// Returns the path relative to the resource directory after removing the
|
||||
// PK_DIR_RESOURCES prefix. This will be the relative path expected by
|
||||
// LoadBinaryResource (uses '/' as path separator on all platforms). Only call
|
||||
// this method for internal extensions, either when IsInternalExtension returns
|
||||
// true or when the extension is handled internally through some means other
|
||||
// than LoadBinaryResource. Use GetExtensionResourcePath instead if you are
|
||||
// unsure whether the extension is internal or external.
|
||||
std::string GetInternalExtensionResourcePath(const std::string& extension_path);
|
||||
|
||||
// Returns the resource path for |extension_path|. For external extensions this
|
||||
// will be the full file path on disk. For internal extensions this will be the
|
||||
// relative path expected by LoadBinaryResource (uses '/' as path separator on
|
||||
// all platforms). Internal extensions must be on the hard-coded list enforced
|
||||
// by IsInternalExtension. If |internal| is non-NULL it will be set to true if
|
||||
// the extension is handled internally.
|
||||
std::string GetExtensionResourcePath(const std::string& extension_path,
|
||||
bool* internal);
|
||||
|
||||
// Read the contents of |extension_path| into |contents|. For external
|
||||
// extensions this will read the file from disk. For internal extensions this
|
||||
// will call LoadBinaryResource. Internal extensions must be on the hard-coded
|
||||
// list enforced by IsInternalExtension. Returns true on success. Must be
|
||||
// called on the FILE thread.
|
||||
bool GetExtensionResourceContents(const std::string& extension_path,
|
||||
std::string& contents);
|
||||
|
||||
// Load |extension_path| in |request_context|. May be an internal or external
|
||||
// extension. Internal extensions must be on the hard-coded list enforced by
|
||||
// IsInternalExtension.
|
||||
void LoadExtension(CefRefPtr<CefRequestContext> request_context,
|
||||
const std::string& extension_path,
|
||||
CefRefPtr<CefExtensionHandler> handler);
|
||||
|
||||
// Register an internal handler for extension resources. Internal extensions
|
||||
// must be on the hard-coded list enforced by IsInternalExtension.
|
||||
void AddInternalExtensionToResourceManager(
|
||||
CefRefPtr<CefExtension> extension,
|
||||
CefRefPtr<CefResourceManager> resource_manager);
|
||||
|
||||
// Returns the URL origin for |extension_id|.
|
||||
std::string GetExtensionOrigin(const std::string& extension_id);
|
||||
|
||||
// Parse browser_action manifest values as defined at
|
||||
// https://developer.chrome.com/extensions/browserAction
|
||||
|
||||
// Look for a browser_action.default_popup manifest value.
|
||||
std::string GetExtensionURL(CefRefPtr<CefExtension> extension);
|
||||
|
||||
// Look for a browser_action.default_icon manifest value and return the resource
|
||||
// path. If |internal| is non-NULL it will be set to true if the extension is
|
||||
// handled internally.
|
||||
std::string GetExtensionIconPath(CefRefPtr<CefExtension> extension,
|
||||
bool* internal);
|
||||
|
||||
} // namespace extension_util
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_BROWSER_EXTENSION_UTIL_H_
|
121
tests/shared/browser/file_util.cc
Normal file
121
tests/shared/browser/file_util.cc
Normal file
@ -0,0 +1,121 @@
|
||||
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
|
||||
// 2012 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 "tests/shared/browser/file_util.h"
|
||||
|
||||
#include "include/base/cef_build.h"
|
||||
#include "include/base/cef_scoped_ptr.h"
|
||||
#include "include/cef_task.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
|
||||
namespace client {
|
||||
namespace file_util {
|
||||
|
||||
namespace {
|
||||
|
||||
bool AllowFileIO() {
|
||||
if (CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)) {
|
||||
NOTREACHED() << "file IO is not allowed on the current thread";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#if defined(OS_WIN)
|
||||
const char kPathSep = '\\';
|
||||
#else
|
||||
const char kPathSep = '/';
|
||||
#endif
|
||||
|
||||
bool ReadFileToString(const std::string& path,
|
||||
std::string* contents,
|
||||
size_t max_size) {
|
||||
if (!AllowFileIO())
|
||||
return false;
|
||||
|
||||
if (contents)
|
||||
contents->clear();
|
||||
FILE* file = fopen(path.c_str(), "rb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
const size_t kBufferSize = 1 << 16;
|
||||
scoped_ptr<char[]> buf(new char[kBufferSize]);
|
||||
size_t len;
|
||||
size_t size = 0;
|
||||
bool read_status = true;
|
||||
|
||||
// Many files supplied in |path| have incorrect size (proc files etc).
|
||||
// Hence, the file is read sequentially as opposed to a one-shot read.
|
||||
while ((len = fread(buf.get(), 1, kBufferSize, file)) > 0) {
|
||||
if (contents)
|
||||
contents->append(buf.get(), std::min(len, max_size - size));
|
||||
|
||||
if ((max_size - size) < len) {
|
||||
read_status = false;
|
||||
break;
|
||||
}
|
||||
|
||||
size += len;
|
||||
}
|
||||
read_status = read_status && !ferror(file);
|
||||
fclose(file);
|
||||
|
||||
return read_status;
|
||||
}
|
||||
|
||||
int WriteFile(const std::string& path, const char* data, int size) {
|
||||
if (!AllowFileIO())
|
||||
return -1;
|
||||
|
||||
FILE* file = fopen(path.c_str(), "wb");
|
||||
if (!file)
|
||||
return -1;
|
||||
|
||||
int written = 0;
|
||||
|
||||
do {
|
||||
size_t write = fwrite(data + written, 1, size - written, file);
|
||||
if (write == 0)
|
||||
break;
|
||||
written += static_cast<int>(write);
|
||||
} while (written < size);
|
||||
|
||||
fclose(file);
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
std::string JoinPath(const std::string& path1, const std::string& path2) {
|
||||
if (path1.empty() && path2.empty())
|
||||
return std::string();
|
||||
if (path1.empty())
|
||||
return path2;
|
||||
if (path2.empty())
|
||||
return path1;
|
||||
|
||||
std::string result = path1;
|
||||
if (result[result.size() - 1] != kPathSep)
|
||||
result += kPathSep;
|
||||
if (path2[0] == kPathSep)
|
||||
result += path2.substr(1);
|
||||
else
|
||||
result += path2;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string GetFileExtension(const std::string& path) {
|
||||
size_t sep = path.find_last_of(".");
|
||||
if (sep != std::string::npos)
|
||||
return path.substr(sep + 1);
|
||||
return std::string();
|
||||
}
|
||||
|
||||
} // namespace file_util
|
||||
} // namespace client
|
45
tests/shared/browser/file_util.h
Normal file
45
tests/shared/browser/file_util.h
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
|
||||
// 2012 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.
|
||||
|
||||
#ifndef CEF_TESTS_SHARED_BROWSER_FILE_UTIL_H_
|
||||
#define CEF_TESTS_SHARED_BROWSER_FILE_UTIL_H_
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
namespace client {
|
||||
namespace file_util {
|
||||
|
||||
// Platform-specific path separator.
|
||||
extern const char kPathSep;
|
||||
|
||||
// Reads the file at |path| into |contents| and returns true on success and
|
||||
// false on error. In case of I/O error, |contents| holds the data that could
|
||||
// be read from the file before the error occurred. When the file size exceeds
|
||||
// max_size|, the function returns false with |contents| holding the file
|
||||
// truncated to |max_size|. |contents| may be NULL, in which case this function
|
||||
// is useful for its side effect of priming the disk cache (could be used for
|
||||
// unit tests). Calling this function on the browser process UI or IO threads is
|
||||
// not allowed.
|
||||
bool ReadFileToString(const std::string& path,
|
||||
std::string* contents,
|
||||
size_t max_size = std::numeric_limits<size_t>::max());
|
||||
|
||||
// Writes the given buffer into the file, overwriting any data that was
|
||||
// previously there. Returns the number of bytes written, or -1 on error.
|
||||
// Calling this function on the browser process UI or IO threads is not allowed.
|
||||
int WriteFile(const std::string& path, const char* data, int size);
|
||||
|
||||
// Combines |path1| and |path2| with the correct platform-specific path
|
||||
// separator.
|
||||
std::string JoinPath(const std::string& path1, const std::string& path2);
|
||||
|
||||
// Extracts the file extension from |path|.
|
||||
std::string GetFileExtension(const std::string& path);
|
||||
|
||||
} // namespace file_util
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_SHARED_BROWSER_FILE_UTIL_H_
|
@ -1,32 +0,0 @@
|
||||
// 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 "tests/shared/browser/resource_util.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "include/base/cef_logging.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
CefRefPtr<CefImage> LoadImageIcon(const char* icon_name) {
|
||||
CefRefPtr<CefImage> icon = CefImage::CreateImage();
|
||||
std::string image, resource;
|
||||
|
||||
resource = std::string(icon_name) + ".1x.png";
|
||||
if (LoadBinaryResource(resource.c_str(), image))
|
||||
icon->AddPNG(1.0f, image.c_str(), image.size());
|
||||
|
||||
resource = std::string(icon_name) + ".2x.png";
|
||||
if (LoadBinaryResource(resource.c_str(), image))
|
||||
icon->AddPNG(2.0f, image.c_str(), image.size());
|
||||
|
||||
// Icons must be 16 in DIP.
|
||||
DCHECK_EQ(16U, std::max(icon->GetWidth(), icon->GetHeight()));
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
} // namespace client
|
@ -30,15 +30,10 @@ CefRefPtr<CefStreamReader> GetBinaryResourceReader(const char* resource_name);
|
||||
#if defined(OS_WIN)
|
||||
// Create a new provider for loading binary resources.
|
||||
CefResourceManager::Provider* CreateBinaryResourceProvider(
|
||||
const std::string& url_path);
|
||||
const std::string& url_path,
|
||||
const std::string& resource_path_prefix);
|
||||
#endif
|
||||
|
||||
// Load an image icon at different scale factors. The image representations are
|
||||
// expected to be 16 DIP in size. For example, if |icon_name| is "image" then
|
||||
// the expected file names are "image.1x.png" for the 1x scale image (16 pixels)
|
||||
// and "image.2x.png" for the 2x scale image (32 pixels).
|
||||
CefRefPtr<CefImage> LoadImageIcon(const char* icon_name);
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_SHARED_BROWSER_RESOURCE_UTIL_H_
|
||||
|
@ -33,9 +33,14 @@ bool LoadBinaryResource(int binaryId, DWORD& dwSize, LPBYTE& pBytes) {
|
||||
// Provider of binary resources.
|
||||
class BinaryResourceProvider : public CefResourceManager::Provider {
|
||||
public:
|
||||
explicit BinaryResourceProvider(const std::string& url_path)
|
||||
: url_path_(url_path) {
|
||||
BinaryResourceProvider(const std::string& url_path,
|
||||
const std::string& resource_path_prefix)
|
||||
: url_path_(url_path), resource_path_prefix_(resource_path_prefix) {
|
||||
DCHECK(!url_path.empty());
|
||||
if (!resource_path_prefix_.empty() &&
|
||||
resource_path_prefix_[resource_path_prefix_.length() - 1] != '/') {
|
||||
resource_path_prefix_ += "/";
|
||||
}
|
||||
}
|
||||
|
||||
bool OnRequest(scoped_refptr<CefResourceManager::Request> request) OVERRIDE {
|
||||
@ -49,8 +54,11 @@ class BinaryResourceProvider : public CefResourceManager::Provider {
|
||||
|
||||
CefRefPtr<CefResourceHandler> handler;
|
||||
|
||||
const std::string& relative_path = url.substr(url_path_.length());
|
||||
std::string relative_path = url.substr(url_path_.length());
|
||||
if (!relative_path.empty()) {
|
||||
if (!resource_path_prefix_.empty())
|
||||
relative_path = resource_path_prefix_ + relative_path;
|
||||
|
||||
CefRefPtr<CefStreamReader> stream =
|
||||
GetBinaryResourceReader(relative_path.data());
|
||||
if (stream.get()) {
|
||||
@ -65,6 +73,7 @@ class BinaryResourceProvider : public CefResourceManager::Provider {
|
||||
|
||||
private:
|
||||
std::string url_path_;
|
||||
std::string resource_path_prefix_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BinaryResourceProvider);
|
||||
};
|
||||
@ -109,8 +118,9 @@ CefRefPtr<CefStreamReader> GetBinaryResourceReader(const char* resource_name) {
|
||||
}
|
||||
|
||||
CefResourceManager::Provider* CreateBinaryResourceProvider(
|
||||
const std::string& url_path) {
|
||||
return new BinaryResourceProvider(url_path);
|
||||
const std::string& url_path,
|
||||
const std::string& resource_path_prefix) {
|
||||
return new BinaryResourceProvider(url_path, resource_path_prefix);
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
Reference in New Issue
Block a user