diff options
Diffstat (limited to 'src/core/extensions/extensions_browser_client_qt.cpp')
-rw-r--r-- | src/core/extensions/extensions_browser_client_qt.cpp | 241 |
1 files changed, 161 insertions, 80 deletions
diff --git a/src/core/extensions/extensions_browser_client_qt.cpp b/src/core/extensions/extensions_browser_client_qt.cpp index 59c15d2f5..8b5da3d60 100644 --- a/src/core/extensions/extensions_browser_client_qt.cpp +++ b/src/core/extensions/extensions_browser_client_qt.cpp @@ -63,13 +63,16 @@ #include "extensions/browser/event_router.h" #include "extensions/browser/extension_host_delegate.h" #include "extensions/browser/extension_protocols.h" +#include "extensions/browser/extensions_browser_interface_binders.h" #include "extensions/browser/mojo/interface_registration.h" #include "extensions/browser/url_request_util.h" #include "extensions/common/file_util.h" +#include "mojo/public/cpp/bindings/strong_binding.h" #include "net/base/completion_once_callback.h" #include "net/base/mime_util.h" -#include "net/url_request/url_request_simple_job.h" +#include "services/network/public/cpp/resource_response.h" #include "services/network/public/mojom/url_loader.mojom.h" +#include "third_party/zlib/google/compression_utils.h" #include "ui/base/resource/resource_bundle.h" #include "component_extension_resource_manager_qt.h" @@ -102,67 +105,164 @@ void DetermineCharset(const std::string &mime_type, } } -// A request for an extension resource in a Chrome .pak file. These are used -// by component extensions. -class URLRequestResourceBundleJob : public net::URLRequestSimpleJob +scoped_refptr<base::RefCountedMemory> GetResource(int resource_id, const std::string &extension_id) +{ + const ui::ResourceBundle &rb = ui::ResourceBundle::GetSharedInstance(); + scoped_refptr<base::RefCountedMemory> bytes = rb.LoadDataResourceBytes(resource_id); + auto *replacements = extensions::ExtensionsBrowserClient::Get()->GetComponentExtensionResourceManager() + ? extensions::ExtensionsBrowserClient::Get()->GetComponentExtensionResourceManager()->GetTemplateReplacementsForExtension( + extension_id) + : nullptr; + + bool is_gzipped = rb.IsGzipped(resource_id); + if (!bytes->size() || (!replacements && !is_gzipped)) { + return bytes; + } + + base::StringPiece input(reinterpret_cast<const char *>(bytes->front()), bytes->size()); + + std::string temp_str; + + base::StringPiece source = input; + if (is_gzipped) { + temp_str.resize(compression::GetUncompressedSize(input)); + source = temp_str; + CHECK(compression::GzipUncompress(input, source)); + } + + if (replacements) { + temp_str = ui::ReplaceTemplateExpressions(source, *replacements); + } + + DCHECK(!temp_str.empty()); + + return base::RefCountedString::TakeString(&temp_str); +} + +// Loads an extension resource in a Chrome .pak file. These are used by +// component extensions. +class ResourceBundleFileLoader : public network::mojom::URLLoader { public: - URLRequestResourceBundleJob(net::URLRequest *request, net::NetworkDelegate *network_delegate, - const base::FilePath &filename, int resource_id, - const std::string &content_security_policy, bool send_cors_header) - : net::URLRequestSimpleJob(request, network_delegate) - , filename_(filename) - , resource_id_(resource_id) - , weak_factory_(this) + static void CreateAndStart(const network::ResourceRequest &request, + mojo::PendingReceiver<network::mojom::URLLoader> loader, + mojo::PendingRemote<network::mojom::URLLoaderClient> client_info, + const base::FilePath &filename, int resource_id, + const std::string &content_security_policy, bool send_cors_header) { - // Leave cache headers out of resource bundle requests. - response_info_.headers = extensions::BuildHttpHeaders(content_security_policy, send_cors_header, base::Time()); + // Owns itself. Will live as long as its URLLoader and URLLoaderClientPtr + // bindings are alive - essentially until either the client gives up or all + // file data has been sent to it. + auto *bundle_loader = new ResourceBundleFileLoader(content_security_policy, send_cors_header); + bundle_loader->Start(request, std::move(loader), std::move(client_info), filename, resource_id); } - int GetRefCountedData(std::string *mime_type, std::string *charset, scoped_refptr<base::RefCountedMemory> *data, - net::CompletionOnceCallback callback) const override + + // mojom::URLLoader implementation: + void FollowRedirect(const std::vector<std::string> &removed_headers, + const net::HttpRequestHeaders &modified_headers, const base::Optional<GURL> &new_url) override { - const ui::ResourceBundle &rb = ui::ResourceBundle::GetSharedInstance(); - *data = rb.LoadDataResourceBytes(resource_id_); + NOTREACHED() << "No redirects for local file loads."; + } + // Current implementation reads all resource data at start of resource + // load, so priority, and pausing is not currently implemented. + void SetPriority(net::RequestPriority priority, int32_t intra_priority_value) override {} + void PauseReadingBodyFromNet() override {} + void ResumeReadingBodyFromNet() override {} - // Add the Content-Length header now that we know the resource length. - response_info_.headers->AddHeader(base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentLength, - base::NumberToString((*data)->size()).c_str())); +private: + ResourceBundleFileLoader(const std::string &content_security_policy, bool send_cors_header) : binding_(this) + { + response_headers_ = extensions::BuildHttpHeaders(content_security_policy, send_cors_header, base::Time()); + } + ~ResourceBundleFileLoader() override = default; - std::string *read_mime_type = new std::string; - base::PostTaskWithTraitsAndReplyWithResult( - FROM_HERE, { base::MayBlock() }, - base::BindOnce(&net::GetMimeTypeFromFile, filename_, base::Unretained(read_mime_type)), - base::BindOnce(&URLRequestResourceBundleJob::OnMimeTypeRead, weak_factory_.GetWeakPtr(), mime_type, - charset, *data, base::Owned(read_mime_type), std::move(callback))); + void Start(const network::ResourceRequest &request, + mojo::PendingReceiver<network::mojom::URLLoader> loader, + mojo::PendingRemote<network::mojom::URLLoaderClient> client_info_remote, + const base::FilePath &filename, int resource_id) + { + client_.Bind(std::move(client_info_remote)); + binding_.Bind(std::move(loader)); + binding_.set_connection_error_handler( + base::BindOnce(&ResourceBundleFileLoader::OnBindingError, base::Unretained(this))); + client_.set_connection_error_handler( + base::BindOnce(&ResourceBundleFileLoader::OnConnectionError, base::Unretained(this))); + auto data = GetResource(resource_id, request.url.host()); - return net::ERR_IO_PENDING; + std::string *read_mime_type = new std::string; + base::PostTaskAndReplyWithResult( + FROM_HERE, { base::ThreadPool(), base::MayBlock() }, + base::BindOnce(&net::GetMimeTypeFromFile, filename, base::Unretained(read_mime_type)), + base::BindOnce(&ResourceBundleFileLoader::OnMimeTypeRead, weak_factory_.GetWeakPtr(), std::move(data), + base::Owned(read_mime_type))); } - void GetResponseInfo(net::HttpResponseInfo *info) override { *info = response_info_; } + void OnMimeTypeRead(scoped_refptr<base::RefCountedMemory> data, std::string *read_mime_type, bool read_result) + { + network::ResourceResponseHead head; + head.request_start = base::TimeTicks::Now(); + head.response_start = base::TimeTicks::Now(); + head.content_length = data->size(); + head.mime_type = *read_mime_type; + DetermineCharset(head.mime_type, data.get(), &head.charset); + mojo::DataPipe pipe(data->size()); + if (!pipe.consumer_handle.is_valid()) { + client_->OnComplete(network::URLLoaderCompletionStatus(net::ERR_FAILED)); + client_.reset(); + MaybeDeleteSelf(); + return; + } + head.headers = response_headers_; + head.headers->AddHeader(base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentLength, + base::NumberToString(head.content_length).c_str())); + if (!head.mime_type.empty()) { + head.headers->AddHeader( + base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentType, head.mime_type.c_str())); + } + client_->OnReceiveResponse(head); + client_->OnStartLoadingResponseBody(std::move(pipe.consumer_handle)); -private: - ~URLRequestResourceBundleJob() override {} + uint32_t write_size = data->size(); + MojoResult result = pipe.producer_handle->WriteData(data->front(), &write_size, MOJO_WRITE_DATA_FLAG_NONE); + OnFileWritten(result); + } - void OnMimeTypeRead(std::string *out_mime_type, std::string *charset, scoped_refptr<base::RefCountedMemory> data, - std::string *read_mime_type, net::CompletionOnceCallback callback, bool read_result) + void OnConnectionError() { - response_info_.headers->AddHeader( - base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentType, read_mime_type->c_str())); - *out_mime_type = *read_mime_type; - DetermineCharset(*read_mime_type, data.get(), charset); - int result = read_result ? net::OK : net::ERR_INVALID_URL; - std::move(callback).Run(result); + client_.reset(); + MaybeDeleteSelf(); } - // We need the filename of the resource to determine the mime type. - base::FilePath filename_; + void OnBindingError() + { + binding_.Close(); + MaybeDeleteSelf(); + } - // The resource to load. - int resource_id_; + void MaybeDeleteSelf() + { + if (!binding_.is_bound() && !client_.is_bound()) + delete this; + } - net::HttpResponseInfo response_info_; + void OnFileWritten(MojoResult result) + { + // All the data has been written now. The consumer will be notified that + // there will be no more data to read from now. + if (result == MOJO_RESULT_OK) + client_->OnComplete(network::URLLoaderCompletionStatus(net::OK)); + else + client_->OnComplete(network::URLLoaderCompletionStatus(net::ERR_FAILED)); + client_.reset(); + MaybeDeleteSelf(); + } - mutable base::WeakPtrFactory<URLRequestResourceBundleJob> weak_factory_; + mojo::Binding<network::mojom::URLLoader> binding_; + network::mojom::URLLoaderClientPtr client_; + scoped_refptr<net::HttpResponseHeaders> response_headers_; + base::WeakPtrFactory<ResourceBundleFileLoader> weak_factory_{ this }; + + DISALLOW_COPY_AND_ASSIGN(ResourceBundleFileLoader); }; } // namespace @@ -235,38 +335,6 @@ bool ExtensionsBrowserClientQt::CanExtensionCrossIncognito(const Extension *exte return false; } -net::URLRequestJob *ExtensionsBrowserClientQt::MaybeCreateResourceBundleRequestJob(net::URLRequest *request, - net::NetworkDelegate *network_delegate, - const base::FilePath &directory_path, - const std::string &content_security_policy, - bool send_cors_header) -{ - base::FilePath resources_path; - base::FilePath relative_path; - // Try to load extension resources from chrome resource file if - // directory_path is a descendant of resources_path. resources_path - // corresponds to src/chrome/browser/resources in source tree. - if (base::PathService::Get(base::DIR_QT_LIBRARY_DATA, &resources_path) && - // Since component extension resources are included in - // component_extension_resources.pak file in resources_path, calculate - // extension relative path against resources_path. - resources_path.AppendRelativePath(directory_path, &relative_path)) { - base::FilePath request_path = extensions::file_util::ExtensionURLToRelativeFilePath(request->url()); - int resource_id = 0; - if (GetComponentExtensionResourceManager()->IsComponentExtensionResource(directory_path, request_path, &resource_id)) { - relative_path = relative_path.Append(request_path); - relative_path = relative_path.NormalizePathSeparators(); - return new URLRequestResourceBundleJob(request, - network_delegate, - relative_path, - resource_id, - content_security_policy, - send_cors_header); - } - } - return nullptr; -} - // Return the resource relative path and id for the given request. base::FilePath ExtensionsBrowserClientQt::GetBundleResourcePath(const network::ResourceRequest &request, const base::FilePath &extension_resources_path, @@ -300,14 +368,15 @@ base::FilePath ExtensionsBrowserClientQt::GetBundleResourcePath(const network::R // Creates and starts a URLLoader to load an extension resource from the // embedder's resource bundle (.pak) files. Used for component extensions. void ExtensionsBrowserClientQt::LoadResourceFromResourceBundle(const network::ResourceRequest &request, - network::mojom::URLLoaderRequest loader, + mojo::PendingReceiver<network::mojom::URLLoader> loader, const base::FilePath &resource_relative_path, int resource_id, const std::string &content_security_policy, - network::mojom::URLLoaderClientPtr client, + mojo::PendingRemote<network::mojom::URLLoaderClient> client, bool send_cors_header) { - NOTIMPLEMENTED(); + ResourceBundleFileLoader::CreateAndStart(request, std::move(loader), std::move(client), resource_relative_path, + resource_id, content_security_policy, send_cors_header); } @@ -395,6 +464,18 @@ void ExtensionsBrowserClientQt::RegisterExtensionInterfaces(service_manager::Bin RegisterInterfacesForExtension(registry, render_frame_host, extension); } +void ExtensionsBrowserClientQt::RegisterBrowserInterfaceBindersForFrame( + service_manager::BinderMapWithContext<content::RenderFrameHost*> *binder_map, + content::RenderFrameHost* render_frame_host, + const Extension* extension) const +{ + PopulateExtensionFrameBinders(binder_map, render_frame_host, extension); + + // FIXME Do we need something from here? + // PopulateChromeFrameBindersForExtension(binder_map, render_frame_host, + // extension); +} + std::unique_ptr<RuntimeAPIDelegate> ExtensionsBrowserClientQt::CreateRuntimeAPIDelegate(content::BrowserContext *context) const { // TODO(extensions): Implement to support Apps. @@ -409,7 +490,7 @@ const ComponentExtensionResourceManager *ExtensionsBrowserClientQt::GetComponent void ExtensionsBrowserClientQt::BroadcastEventToRenderers(events::HistogramValue histogram_value, const std::string &event_name, - std::unique_ptr<base::ListValue> args) + std::unique_ptr<base::ListValue> args, bool dispatch_to_off_the_record_profiles) { NOTIMPLEMENTED(); // TODO : do the event routing |