refactor: ginify protocol (#22812)

This commit is contained in:
Jeremy Apthorp 2020-03-26 10:34:32 -07:00 committed by GitHub
parent b3d3ac4e0f
commit e73d5e3db5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 192 additions and 112 deletions

View file

@ -10,8 +10,10 @@
#include "base/stl_util.h"
#include "content/public/browser/child_process_security_policy.h"
#include "gin/object_template_builder.h"
#include "shell/browser/browser.h"
#include "shell/browser/electron_browser_context.h"
#include "shell/browser/protocol_registry.h"
#include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/net_converter.h"
#include "shell/common/gin_helper/dictionary.h"
@ -74,6 +76,8 @@ struct Converter<CustomScheme> {
namespace electron {
namespace api {
gin::WrapperInfo Protocol::kWrapperInfo = {gin::kEmbedderNativeGin};
std::vector<std::string> GetStandardSchemes() {
return g_standard_schemes;
}
@ -160,59 +164,45 @@ std::string ErrorCodeToString(ProtocolError error) {
} // namespace
Protocol::Protocol(v8::Isolate* isolate,
ElectronBrowserContext* browser_context) {
Init(isolate);
AttachAsUserData(browser_context);
}
Protocol::Protocol(v8::Isolate* isolate, ProtocolRegistry* protocol_registry)
: protocol_registry_(protocol_registry) {}
Protocol::~Protocol() = default;
void Protocol::RegisterURLLoaderFactories(
content::ContentBrowserClient::NonNetworkURLLoaderFactoryMap* factories) {
for (const auto& it : handlers_) {
factories->emplace(it.first, std::make_unique<ElectronURLLoaderFactory>(
it.second.first, it.second.second));
}
}
ProtocolError Protocol::RegisterProtocol(ProtocolType type,
const std::string& scheme,
const ProtocolHandler& handler) {
const bool added = base::TryEmplace(handlers_, scheme, type, handler).second;
bool added = protocol_registry_->RegisterProtocol(type, scheme, handler);
return added ? ProtocolError::OK : ProtocolError::REGISTERED;
}
void Protocol::UnregisterProtocol(const std::string& scheme,
gin::Arguments* args) {
const bool removed = handlers_.erase(scheme) != 0;
const auto error =
removed ? ProtocolError::OK : ProtocolError::NOT_REGISTERED;
HandleOptionalCallback(args, error);
bool removed = protocol_registry_->UnregisterProtocol(scheme);
HandleOptionalCallback(
args, removed ? ProtocolError::OK : ProtocolError::NOT_REGISTERED);
}
bool Protocol::IsProtocolRegistered(const std::string& scheme) {
return base::Contains(handlers_, scheme);
return protocol_registry_->IsProtocolRegistered(scheme);
}
ProtocolError Protocol::InterceptProtocol(ProtocolType type,
const std::string& scheme,
const ProtocolHandler& handler) {
const bool added =
base::TryEmplace(intercept_handlers_, scheme, type, handler).second;
bool added = protocol_registry_->InterceptProtocol(type, scheme, handler);
return added ? ProtocolError::OK : ProtocolError::INTERCEPTED;
}
void Protocol::UninterceptProtocol(const std::string& scheme,
gin::Arguments* args) {
const bool removed = intercept_handlers_.erase(scheme) != 0;
const auto error =
removed ? ProtocolError::OK : ProtocolError::NOT_INTERCEPTED;
HandleOptionalCallback(args, error);
bool removed = protocol_registry_->UninterceptProtocol(scheme);
HandleOptionalCallback(
args, removed ? ProtocolError::OK : ProtocolError::NOT_INTERCEPTED);
}
bool Protocol::IsProtocolIntercepted(const std::string& scheme) {
return base::Contains(intercept_handlers_, scheme);
return protocol_registry_->IsProtocolIntercepted(scheme);
}
v8::Local<v8::Promise> Protocol::IsProtocolHandled(const std::string& scheme,
@ -224,21 +214,21 @@ v8::Local<v8::Promise> Protocol::IsProtocolHandled(const std::string& scheme,
"instead.",
"ProtocolDeprecateIsProtocolHandled");
return gin_helper::Promise<bool>::ResolvedPromise(
isolate(), IsProtocolRegistered(scheme) ||
IsProtocolIntercepted(scheme) ||
// The |isProtocolHandled| should return true for builtin
// schemes, however with NetworkService it is impossible to
// know which schemes are registered until a real network
// request is sent.
// So we have to test against a hard-coded builtin schemes
// list make it work with old code. We should deprecate
// this API with the new |isProtocolRegistered| API.
base::Contains(kBuiltinSchemes, scheme));
args->isolate(),
IsProtocolRegistered(scheme) || IsProtocolIntercepted(scheme) ||
// The |isProtocolHandled| should return true for builtin
// schemes, however with NetworkService it is impossible to
// know which schemes are registered until a real network
// request is sent.
// So we have to test against a hard-coded builtin schemes
// list make it work with old code. We should deprecate
// this API with the new |isProtocolRegistered| API.
base::Contains(kBuiltinSchemes, scheme));
}
void Protocol::HandleOptionalCallback(gin::Arguments* args,
ProtocolError error) {
CompletionCallback callback;
base::RepeatingCallback<void(v8::Local<v8::Value>)> callback;
if (args->GetNext(&callback)) {
node::Environment* env = node::Environment::GetCurrent(args->isolate());
EmitWarning(
@ -249,7 +239,7 @@ void Protocol::HandleOptionalCallback(gin::Arguments* args,
callback.Run(v8::Null(args->isolate()));
else
callback.Run(v8::Exception::Error(
gin::StringToV8(isolate(), ErrorCodeToString(error))));
gin::StringToV8(args->isolate(), ErrorCodeToString(error))));
}
}
@ -257,14 +247,13 @@ void Protocol::HandleOptionalCallback(gin::Arguments* args,
gin::Handle<Protocol> Protocol::Create(
v8::Isolate* isolate,
ElectronBrowserContext* browser_context) {
return gin::CreateHandle(isolate, new Protocol(isolate, browser_context));
return gin::CreateHandle(
isolate, new Protocol(isolate, browser_context->protocol_registry()));
}
// static
void Protocol::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype) {
prototype->SetClassName(gin::StringToV8(isolate, "Protocol"));
gin_helper::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
gin::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return gin::Wrappable<Protocol>::GetObjectTemplateBuilder(isolate)
.SetMethod("registerStringProtocol",
&Protocol::RegisterProtocolFor<ProtocolType::kString>)
.SetMethod("registerBufferProtocol",
@ -296,6 +285,10 @@ void Protocol::BuildPrototype(v8::Isolate* isolate,
.SetMethod("isProtocolIntercepted", &Protocol::IsProtocolIntercepted);
}
const char* Protocol::GetTypeName() {
return "Protocol";
}
} // namespace api
} // namespace electron

View file

@ -10,13 +10,13 @@
#include "content/public/browser/content_browser_client.h"
#include "gin/handle.h"
#include "gin/wrappable.h"
#include "shell/browser/net/electron_url_loader_factory.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/trackable_object.h"
namespace electron {
class ElectronBrowserContext;
class ProtocolRegistry;
namespace api {
@ -35,22 +35,19 @@ enum class ProtocolError {
};
// Protocol implementation based on network services.
class Protocol : public gin_helper::TrackableObject<Protocol> {
class Protocol : public gin::Wrappable<Protocol> {
public:
static gin::Handle<Protocol> Create(v8::Isolate* isolate,
ElectronBrowserContext* browser_context);
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype);
// Used by ElectronBrowserClient for creating URLLoaderFactory.
void RegisterURLLoaderFactories(
content::ContentBrowserClient::NonNetworkURLLoaderFactoryMap* factories);
const HandlersMap& intercept_handlers() const { return intercept_handlers_; }
// gin::Wrappable
static gin::WrapperInfo kWrapperInfo;
gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
const char* GetTypeName() override;
private:
Protocol(v8::Isolate* isolate, ElectronBrowserContext* browser_context);
Protocol(v8::Isolate* isolate, ProtocolRegistry* protocol_registry);
~Protocol() override;
// Callback types.
@ -91,8 +88,9 @@ class Protocol : public gin_helper::TrackableObject<Protocol> {
// Be compatible with old interface, which accepts optional callback.
void HandleOptionalCallback(gin::Arguments* args, ProtocolError error);
HandlersMap handlers_;
HandlersMap intercept_handlers_;
// Weak pointer; the lifetime of the ProtocolRegistry is guaranteed to be
// longer than the lifetime of this JS interface.
ProtocolRegistry* protocol_registry_;
};
} // namespace api

View file

@ -209,24 +209,6 @@ void DownloadIdCallback(content::DownloadManager* download_manager,
false, std::vector<download::DownloadItem::ReceivedSlice>());
}
void DestroyGlobalHandle(v8::Isolate* isolate,
const v8::Global<v8::Value>& global_handle) {
v8::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
if (!global_handle.IsEmpty()) {
v8::Local<v8::Value> local_handle = global_handle.Get(isolate);
v8::Local<v8::Object> object;
if (local_handle->IsObject() &&
local_handle->ToObject(isolate->GetCurrentContext()).ToLocal(&object)) {
void* ptr = object->GetAlignedPointerFromInternalField(0);
if (!ptr)
return;
delete static_cast<gin_helper::WrappableBase*>(ptr);
object->SetAlignedPointerInInternalField(0, nullptr);
}
}
}
#if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
class DictionaryObserver final : public SpellcheckCustomDictionary::Observer {
private:
@ -302,10 +284,6 @@ Session::~Session() {
}
#endif
// TODO(zcbenz): Now since URLRequestContextGetter is gone, is this still
// needed?
// Refs https://github.com/electron/electron/pull/12305.
DestroyGlobalHandle(isolate(), protocol_);
g_sessions.erase(weak_map_id());
}
@ -750,11 +728,11 @@ v8::Local<v8::Value> Session::Cookies(v8::Isolate* isolate) {
auto handle = Cookies::Create(isolate, browser_context());
cookies_.Reset(isolate, handle.ToV8());
}
return v8::Local<v8::Value>::New(isolate, cookies_);
return cookies_.Get(isolate);
}
v8::Local<v8::Value> Session::Protocol(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, protocol_);
return protocol_.Get(isolate);
}
v8::Local<v8::Value> Session::ServiceWorkerContext(v8::Isolate* isolate) {
@ -763,7 +741,7 @@ v8::Local<v8::Value> Session::ServiceWorkerContext(v8::Isolate* isolate) {
handle = ServiceWorkerContext::Create(isolate, browser_context()).ToV8();
service_worker_context_.Reset(isolate, handle);
}
return v8::Local<v8::Value>::New(isolate, service_worker_context_);
return service_worker_context_.Get(isolate);
}
v8::Local<v8::Value> Session::WebRequest(v8::Isolate* isolate) {
@ -771,15 +749,15 @@ v8::Local<v8::Value> Session::WebRequest(v8::Isolate* isolate) {
auto handle = WebRequest::Create(isolate, browser_context());
web_request_.Reset(isolate, handle.ToV8());
}
return v8::Local<v8::Value>::New(isolate, web_request_);
return web_request_.Get(isolate);
}
v8::Local<v8::Value> Session::NetLog(v8::Isolate* isolate) {
if (net_log_.IsEmpty()) {
auto handle = electron::api::NetLog::Create(isolate, browser_context());
auto handle = NetLog::Create(isolate, browser_context());
net_log_.Reset(isolate, handle.ToV8());
}
return v8::Local<v8::Value>::New(isolate, net_log_);
return net_log_.Get(isolate);
}
static void StartPreconnectOnUI(
@ -1052,9 +1030,6 @@ void Initialize(v8::Local<v8::Object> exports,
dict.Set(
"Session",
Session::GetConstructor(isolate)->GetFunction(context).ToLocalChecked());
dict.Set(
"Protocol",
Protocol::GetConstructor(isolate)->GetFunction(context).ToLocalChecked());
dict.SetMethod("fromPartition", &FromPartition);
}

View file

@ -140,8 +140,6 @@ class Session : public gin_helper::TrackableObject<Session>,
v8::Global<v8::Value> protocol_;
v8::Global<v8::Value> net_log_;
v8::Global<v8::Value> service_worker_context_;
// Cached object.
v8::Global<v8::Value> web_request_;
// The client id to enable the network throttler.