fix: webRequest module should work with file:// protocol (9-x-y) (#22919)

* fix: webRequest module should work with file:// protocol

* test: do not trigger unhandled promise rejections
This commit is contained in:
Cheng Zhao
2020-04-02 05:36:24 +09:00
committed by GitHub
parent 050844dc38
commit f255d47073
6 changed files with 102 additions and 9 deletions

View File

@@ -12,6 +12,7 @@
#include "content/public/browser/child_process_security_policy.h"
#include "shell/browser/browser.h"
#include "shell/browser/electron_browser_context.h"
#include "shell/browser/net/asar/asar_url_loader.h"
#include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/net_converter.h"
#include "shell/common/gin_helper/dictionary.h"
@@ -40,6 +41,34 @@ struct CustomScheme {
SchemeOptions options;
};
// Provide support for accessing asar archives in file:// protocol.
class AsarURLLoaderFactory : public network::mojom::URLLoaderFactory {
public:
AsarURLLoaderFactory() {}
private:
// network::mojom::URLLoaderFactory:
void CreateLoaderAndStart(
mojo::PendingReceiver<network::mojom::URLLoader> loader,
int32_t routing_id,
int32_t request_id,
uint32_t options,
const network::ResourceRequest& request,
mojo::PendingRemote<network::mojom::URLLoaderClient> client,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
override {
asar::CreateAsarURLLoader(request, std::move(loader), std::move(client),
new net::HttpResponseHeaders(""));
}
void Clone(
mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader) override {
receivers_.Add(this, std::move(loader));
}
mojo::ReceiverSet<network::mojom::URLLoaderFactory> receivers_;
};
} // namespace
namespace gin {
@@ -169,7 +198,25 @@ Protocol::Protocol(v8::Isolate* isolate,
Protocol::~Protocol() = default;
void Protocol::RegisterURLLoaderFactories(
URLLoaderFactoryType type,
content::ContentBrowserClient::NonNetworkURLLoaderFactoryMap* factories) {
// Override the default FileURLLoaderFactory to support asar archives.
if (type == URLLoaderFactoryType::kNavigation) {
// Always allow navigating to file:// URLs.
//
// Note that Chromium calls |emplace| to create the default file factory
// after this call, so it won't override our asar factory.
DCHECK(!base::Contains(*factories, url::kFileScheme));
factories->emplace(url::kFileScheme,
std::make_unique<AsarURLLoaderFactory>());
} else if (type == URLLoaderFactoryType::kDocumentSubResource) {
// Only support requesting file:// subresource URLs when Chromium does so,
// it is usually supported under file:// or about:blank documents.
auto file_factory = factories->find(url::kFileScheme);
if (file_factory != factories->end())
file_factory->second = std::make_unique<AsarURLLoaderFactory>();
}
for (const auto& it : handlers_) {
factories->emplace(it.first, std::make_unique<ElectronURLLoaderFactory>(
it.second.first, it.second.second));

View File

@@ -43,8 +43,12 @@ class Protocol : public gin_helper::TrackableObject<Protocol> {
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype);
using URLLoaderFactoryType =
content::ContentBrowserClient::URLLoaderFactoryType;
// Used by ElectronBrowserClient for creating URLLoaderFactory.
void RegisterURLLoaderFactories(
URLLoaderFactoryType type,
content::ContentBrowserClient::NonNetworkURLLoaderFactoryMap* factories);
const HandlersMap& intercept_handlers() const { return intercept_handlers_; }

View File

@@ -292,11 +292,12 @@ int WebRequest::OnHeadersReceived(
const net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
GURL* allowed_unsafe_redirect_url) {
const std::string& status_line =
original_response_headers ? original_response_headers->GetStatusLine()
: std::string();
return HandleResponseEvent(
kOnHeadersReceived, info, std::move(callback),
std::make_pair(override_response_headers,
original_response_headers->GetStatusLine()),
request);
std::make_pair(override_response_headers, status_line), request);
}
void WebRequest::OnSendHeaders(extensions::WebRequestInfo* info,

View File

@@ -1176,8 +1176,10 @@ void ElectronBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories(
web_contents->GetBrowserContext(),
false /* we don't support extensions::WebViewGuest */));
#endif
if (protocol)
protocol->RegisterURLLoaderFactories(factories);
if (protocol) {
protocol->RegisterURLLoaderFactories(URLLoaderFactoryType::kNavigation,
factories);
}
}
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
@@ -1238,8 +1240,10 @@ void ElectronBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
if (web_contents) {
api::Protocol* protocol = api::Protocol::FromWrappedClass(
v8::Isolate::GetCurrent(), web_contents->GetBrowserContext());
if (protocol)
protocol->RegisterURLLoaderFactories(factories);
if (protocol) {
protocol->RegisterURLLoaderFactories(
URLLoaderFactoryType::kDocumentSubResource, factories);
}
}
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
auto factory = extensions::CreateExtensionURLLoaderFactory(render_process_id,

View File

@@ -825,8 +825,11 @@ void ProxyingURLLoaderFactory::CreateLoaderAndStart(
return;
}
// Intercept file:// protocol to support asar archives.
if (request.url.SchemeIsFile()) {
// The loader of ServiceWorker forbids loading scripts from file:// URLs, and
// Chromium does not provide a way to override this behavior. So in order to
// make ServiceWorker work with file:// URLs, we have to intercept its
// requests here.
if (IsForServiceWorkerScript() && request.url.SchemeIsFile()) {
asar::CreateAsarURLLoader(request, std::move(loader), std::move(client),
new net::HttpResponseHeaders(""));
return;