Commit 59fc783c authored by Fabio Rocha's avatar Fabio Rocha Committed by Chromium LUCI CQ

Refactor ProtocolHandlerRegistry to allow batched protocol registration

Previously, ProtocolHandlerRegistry supported only single-protocol
operations (e.g. add a handler to the registry and register with the OS
in a single function). For the web app handler use case, repeatedly
calling single-protocol functions for multiple app handlers is a
problem because multiple OS registrations will result in multiple UACs
being presented to the user.

This CL lays the groundwork for upcoming changes to introduce batching
to the ProtocolHandlerRegistry which allows for a single OS
registration operation and single UAC.

SetDefaults() is added to support registering multiple default web app
handlers at a time. A single-protocol SetDefault() is also left in
place for use in existing call sites.

RemoveHandlers() is added to support removing multiple default web
handlers and registering their replacement default handlers in batch
operations. A single-protocol RemoveHandler() is left in place for use
in existing call sites.

Since this is just a refactor there should be no observable difference
in behavior with this code. CL 2573383 will build on this code and add
more test cases for the case of multiple registration.

Bug: 1019239
Change-Id: I4488815d39fcce164a9c7054cbcc34d473d806ae
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2573319Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Commit-Queue: Fabio Rocha <fabio.rocha@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#837641}
parent c35a6463
......@@ -15,6 +15,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/notreached.h"
#include "base/optional.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/profiles/profile_io_data.h"
......@@ -442,39 +443,67 @@ bool ProtocolHandlerRegistry::IsHandledProtocol(
return enabled_ && !GetHandlerFor(scheme).IsEmpty();
}
void ProtocolHandlerRegistry::RemoveHandler(
const ProtocolHandler& handler) {
if (IsIgnored(handler)) {
RemoveIgnoredHandler(handler);
return;
}
void ProtocolHandlerRegistry::RemoveHandler(const ProtocolHandler& handler) {
RemoveHandlers({handler});
}
void ProtocolHandlerRegistry::RemoveHandlers(
const std::vector<ProtocolHandler>& handlers) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
ProtocolHandlerList& handlers = protocol_handlers_[handler.protocol()];
bool erase_success = false;
if (HandlerExists(handler, handlers) &&
HandlerExists(handler, &user_protocol_handlers_)) {
EraseHandler(handler, &user_protocol_handlers_);
erase_success = true;
if (!HandlerExists(handler, &policy_protocol_handlers_))
EraseHandler(handler, &protocol_handlers_);
}
auto q = default_handlers_.find(handler.protocol());
if (erase_success && q != default_handlers_.end() && q->second == handler) {
// Make the new top handler in the list the default.
if (!handlers.empty()) {
// NOTE We pass a copy because SetDefault() modifies handlers.
SetDefault(ProtocolHandler(handlers[0]));
} else {
default_handlers_.erase(q);
std::vector<ProtocolHandler> erased_handlers;
for (const auto& handler : handlers) {
if (IsIgnored(handler)) {
RemoveIgnoredHandler(handler);
continue;
}
ProtocolHandlerList& existing_handlers =
protocol_handlers_[handler.protocol()];
bool erase_success = false;
if (HandlerExists(handler, existing_handlers) &&
HandlerExists(handler, &user_protocol_handlers_)) {
EraseHandler(handler, &user_protocol_handlers_);
erase_success = true;
if (!HandlerExists(handler, &policy_protocol_handlers_))
EraseHandler(handler, &protocol_handlers_);
}
if (!erase_success)
continue;
else
erased_handlers.push_back(handler);
}
std::vector<ProtocolHandler> updated_default_handlers;
// Choose new defaults for erased handlers that were default handlers.
for (const auto& erased_handler : erased_handlers) {
ProtocolHandlerList& existing_handlers =
protocol_handlers_[erased_handler.protocol()];
ProtocolHandler default_handler = GetHandlerFor(erased_handler.protocol());
if (default_handler == erased_handler) {
// Removing the default handler for a protocol requires updating the
// default registration. If the default handler is a web app handler, the
// removal of any handler for the protocol may require updating the
// the default registration as the protocol may no longer require
// disambiguation.
if (!existing_handlers.empty()) {
updated_default_handlers.push_back(existing_handlers[0]);
} else {
default_handlers_.erase(erased_handler.protocol());
}
}
}
if (erase_success && !IsHandledProtocol(handler.protocol())) {
delegate_->DeregisterExternalHandler(handler.protocol());
if (!IsHandledProtocol(erased_handler.protocol())) {
delegate_->DeregisterExternalHandler(erased_handler.protocol());
}
}
SetDefaults(updated_default_handlers);
Save();
if (erase_success)
if (!erased_handlers.empty())
NotifyChanged();
}
......@@ -593,18 +622,32 @@ ProtocolHandlerRegistry::GetHandlerList(
}
void ProtocolHandlerRegistry::SetDefault(const ProtocolHandler& handler) {
SetDefaults({handler});
}
void ProtocolHandlerRegistry::SetDefaults(
const std::vector<ProtocolHandler>& handlers) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const std::string& protocol = handler.protocol();
ProtocolHandlerMap::const_iterator p = default_handlers_.find(protocol);
// If we're not loading, and we are setting a default for a new protocol,
// register with the OS.
if (!is_loading_ && p == default_handlers_.end())
for (const auto& handler : handlers) {
SetDefaultImpl(handler);
}
if (is_loading_)
return;
// If we're not loading register with the OS.
for (const auto& handler : handlers) {
delegate_->RegisterWithOSAsDefaultClient(
protocol, GetDefaultWebClientCallback(protocol));
handler.protocol(), GetDefaultWebClientCallback(handler.protocol()));
}
}
void ProtocolHandlerRegistry::SetDefaultImpl(const ProtocolHandler& handler) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const std::string& protocol = handler.protocol();
default_handlers_.erase(protocol);
default_handlers_.insert(std::make_pair(protocol, handler));
PromoteHandler(handler);
}
......
......@@ -163,6 +163,9 @@ class ProtocolHandlerRegistry : public KeyedService {
// Removes the given protocol handler from the registry.
void RemoveHandler(const ProtocolHandler& handler);
// Removes multiple protocol handlers from the registry.
void RemoveHandlers(const std::vector<ProtocolHandler>& handlers);
// Remove the default handler for the given protocol.
void RemoveDefaultHandler(const std::string& scheme);
......@@ -224,6 +227,13 @@ class ProtocolHandlerRegistry : public KeyedService {
// Makes this ProtocolHandler the default handler for its protocol.
void SetDefault(const ProtocolHandler& handler);
// Makes these ProtocolHandler the default handlers for their protocols and
// registers the handlers with the OS.
void SetDefaults(const std::vector<ProtocolHandler>& handlers);
// Makes a handler the default for its protocol inside the registry.
void SetDefaultImpl(const ProtocolHandler& handler);
// Insert the given ProtocolHandler into the registry.
void InsertHandler(const ProtocolHandler& handler);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment