Skip to content

Instantly share code, notes, and snippets.

@tarruda
Created October 17, 2020 00:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tarruda/554962f987f7f3a1a94d2c1c76c880a8 to your computer and use it in GitHub Desktop.
Save tarruda/554962f987f7f3a1a94d2c1c76c880a8 to your computer and use it in GitHub Desktop.
This patch modifies electron's intercept*Protocol APIs to allow passing an array of URL patterns as second argument (same format as webRequest)
commit 6defd383ae86a65a4cdcc8ec47f4aabf7aac69a6
Author: Thiago Padilha <thiagopadilha@cloud.upwork.com>
Date: Fri Oct 16 19:10:26 2020 -0300
OTA-10843: Implement URL patterns for intercept*Protocol
By passing an array of URL patterns (same syntax as webRequest), it is now
possible to filter which URLs are passed to intercept*Protocol handlers.
diff --git a/shell/browser/api/electron_api_protocol_ns.cc b/shell/browser/api/electron_api_protocol_ns.cc
index 6b1c4e016..7413ab252 100644
--- a/shell/browser/api/electron_api_protocol_ns.cc
+++ b/shell/browser/api/electron_api_protocol_ns.cc
@@ -172,14 +172,15 @@ void ProtocolNS::RegisterURLLoaderFactories(
content::ContentBrowserClient::NonNetworkURLLoaderFactoryMap* factories) {
for (const auto& it : handlers_) {
factories->emplace(it.first, std::make_unique<ElectronURLLoaderFactory>(
- it.second.first, it.second.second));
+ it.second.first, it.second.second.first));
}
}
ProtocolError ProtocolNS::RegisterProtocol(ProtocolType type,
const std::string& scheme,
const ProtocolHandler& handler) {
- const bool added = base::TryEmplace(handlers_, scheme, type, handler).second;
+ const bool added = base::TryEmplace(handlers_, scheme, type,
+ std::make_pair(handler, std::set<URLPattern>())).second;
return added ? ProtocolError::OK : ProtocolError::REGISTERED;
}
@@ -197,9 +198,11 @@ bool ProtocolNS::IsProtocolRegistered(const std::string& scheme) {
ProtocolError ProtocolNS::InterceptProtocol(ProtocolType type,
const std::string& scheme,
- const ProtocolHandler& handler) {
+ const ProtocolHandler& handler,
+ std::set<URLPattern> patterns) {
const bool added =
- base::TryEmplace(intercept_handlers_, scheme, type, handler).second;
+ base::TryEmplace(intercept_handlers_, scheme, type,
+ std::make_pair(handler, std::move(patterns))).second;
return added ? ProtocolError::OK : ProtocolError::INTERCEPTED;
}
@@ -254,6 +257,30 @@ void ProtocolNS::HandleOptionalCallback(gin::Arguments* args,
}
}
+std::set<URLPattern> ProtocolNS::ParseURLPatterns(gin::Arguments *args) {
+ std::set<URLPattern> rv;
+ std::set<std::string> filter_patterns;
+
+ if (!args->GetNext(&filter_patterns)) {
+ return rv;
+ }
+
+ for (const std::string& filter_pattern : filter_patterns) {
+ URLPattern pattern(URLPattern::SCHEME_ALL);
+ const URLPattern::ParseResult result = pattern.Parse(std::move(filter_pattern));
+ if (result == URLPattern::ParseResult::kSuccess) {
+ rv.insert(pattern);
+ } else {
+ const char* error_type = URLPattern::GetParseResultString(result);
+ args->ThrowTypeError("Invalid url pattern " + filter_pattern + ": " +
+ error_type);
+ break;
+ }
+ }
+
+ return rv;
+}
+
// static
gin::Handle<ProtocolNS> ProtocolNS::Create(
v8::Isolate* isolate,
diff --git a/shell/browser/api/electron_api_protocol_ns.h b/shell/browser/api/electron_api_protocol_ns.h
index febbd34eb..12d729db1 100644
--- a/shell/browser/api/electron_api_protocol_ns.h
+++ b/shell/browser/api/electron_api_protocol_ns.h
@@ -9,6 +9,7 @@
#include <vector>
#include "content/public/browser/content_browser_client.h"
+#include "extensions/common/url_pattern.h"
#include "gin/handle.h"
#include "shell/browser/api/trackable_object.h"
#include "shell/browser/net/electron_url_loader_factory.h"
@@ -67,7 +68,8 @@ class ProtocolNS : public mate::TrackableObject<ProtocolNS> {
ProtocolError InterceptProtocol(ProtocolType type,
const std::string& scheme,
- const ProtocolHandler& handler);
+ const ProtocolHandler& handler,
+ std::set<URLPattern> url_pattern);
void UninterceptProtocol(const std::string& scheme, gin::Arguments* args);
bool IsProtocolIntercepted(const std::string& scheme);
@@ -86,12 +88,15 @@ class ProtocolNS : public mate::TrackableObject<ProtocolNS> {
void InterceptProtocolFor(const std::string& scheme,
const ProtocolHandler& handler,
gin::Arguments* args) {
- HandleOptionalCallback(args, InterceptProtocol(type, scheme, handler));
+ HandleOptionalCallback(args, InterceptProtocol(type, scheme, handler,
+ ParseURLPatterns(args)));
}
// Be compatible with old interface, which accepts optional callback.
void HandleOptionalCallback(gin::Arguments* args, ProtocolError error);
+ std::set<URLPattern> ParseURLPatterns(gin::Arguments* args);
+
HandlersMap handlers_;
HandlersMap intercept_handlers_;
};
diff --git a/shell/browser/net/electron_url_loader_factory.h b/shell/browser/net/electron_url_loader_factory.h
index a7d7b4916..5582219fe 100644
--- a/shell/browser/net/electron_url_loader_factory.h
+++ b/shell/browser/net/electron_url_loader_factory.h
@@ -9,6 +9,7 @@
#include <string>
#include <utility>
+#include "extensions/common/url_pattern.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
@@ -36,7 +37,8 @@ using ProtocolHandler =
// scheme => (type, handler).
using HandlersMap =
- std::map<std::string, std::pair<ProtocolType, ProtocolHandler>>;
+ std::map<std::string, std::pair<ProtocolType,
+ std::pair<ProtocolHandler, std::set<URLPattern>>>>;
// Implementation of URLLoaderFactory.
class ElectronURLLoaderFactory : public network::mojom::URLLoaderFactory {
diff --git a/shell/browser/net/proxying_url_loader_factory.cc b/shell/browser/net/proxying_url_loader_factory.cc
index 47df711b9..bf619bf6a 100644
--- a/shell/browser/net/proxying_url_loader_factory.cc
+++ b/shell/browser/net/proxying_url_loader_factory.cc
@@ -10,6 +10,7 @@
#include "base/strings/string_util.h"
#include "content/public/browser/browser_context.h"
#include "extensions/browser/extension_navigation_ui_data.h"
+#include "extensions/common/url_pattern.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "net/base/completion_repeating_callback.h"
#include "net/base/load_flags.h"
@@ -18,6 +19,24 @@
#include "shell/browser/net/asar/asar_url_loader.h"
#include "shell/common/options_switches.h"
+
+namespace {
+
+// Test whether the URL of |request| matches |patterns|.
+bool MatchesFilterCondition(const network::ResourceRequest& original_request,
+ const std::set<URLPattern>& patterns) {
+ if (patterns.empty())
+ return true;
+
+ for (const auto& pattern : patterns) {
+ if (pattern.MatchesURL(original_request.url))
+ return true;
+ }
+ return false;
+}
+
+}
+
namespace electron {
ProxyingURLLoaderFactory::InProgressRequest::FollowRedirectParams::
FollowRedirectParams() = default;
@@ -684,6 +703,7 @@ ProxyingURLLoaderFactory::ProxyingURLLoaderFactory(
navigation_ui_data_(std::move(navigation_ui_data)),
navigation_id_(std::move(navigation_id)),
loader_factory_type_(loader_factory_type) {
+
target_factory_.Bind(std::move(target_factory_remote));
target_factory_.set_disconnect_handler(base::BindOnce(
&ProxyingURLLoaderFactory::OnTargetFactoryError, base::Unretained(this)));
@@ -730,13 +750,16 @@ void ProxyingURLLoaderFactory::CreateLoaderAndStart(
// Check if user has intercepted this scheme.
auto it = intercepted_handlers_.find(request.url.scheme());
if (it != intercepted_handlers_.end()) {
- // <scheme, <type, handler>>
- it->second.second.Run(
- request, base::BindOnce(&ElectronURLLoaderFactory::StartLoading,
- std::move(loader), routing_id, request_id,
- options, request, std::move(client),
- traffic_annotation, this, it->second.first));
- return;
+ auto url_patterns = it->second.second.second;
+ if (MatchesFilterCondition(original_request, url_patterns)) {
+ // <scheme, <type, handler>>
+ it->second.second.first.Run(
+ request, base::BindOnce(&ElectronURLLoaderFactory::StartLoading,
+ std::move(loader), routing_id, request_id,
+ options, request, std::move(client),
+ traffic_annotation, this, it->second.first));
+ return;
+ }
}
// Intercept file:// protocol to support asar archives.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment