diff options
author | ben <ben@chromium.org> | 2015-07-28 16:50:12 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-07-28 23:50:53 +0000 |
commit | 79b0408c7e702c6b5c035ea3cb669cb4c97036b5 (patch) | |
tree | 9f5c1a7bd92ce3c6a10eafd191f726e390d3bbc6 /mojo/shell | |
parent | 67d3786d1147e9e684b870ff47e92749ceb3095c (diff) | |
download | chromium_src-79b0408c7e702c6b5c035ea3cb669cb4c97036b5.zip chromium_src-79b0408c7e702c6b5c035ea3cb669cb4c97036b5.tar.gz chromium_src-79b0408c7e702c6b5c035ea3cb669cb4c97036b5.tar.bz2 |
Get CapabilityFilters to work with ContentHandlers.
Mostly just a small amount of wiring and code cleanup in production code.
For testing, I wanted to run identical tests. So I ended up restructuring how the tests work. The test itself is run in a common function shared between an instantiation for each URL as a unique application (with its own loader) and an instantiation for each URL as content handled by a single content handler. I also changed the validator to be a Mojo service which simplified things a little.
I also made ServiceProviderImpl use StrongBinding.
R=sky@chromium.org
http://crbug.com/510210
Review URL: https://codereview.chromium.org/1260193002
Cr-Commit-Position: refs/heads/master@{#340810}
Diffstat (limited to 'mojo/shell')
-rw-r--r-- | mojo/shell/BUILD.gn | 2 | ||||
-rw-r--r-- | mojo/shell/application_instance.cc | 19 | ||||
-rw-r--r-- | mojo/shell/application_instance.h | 36 | ||||
-rw-r--r-- | mojo/shell/application_manager.cc | 70 | ||||
-rw-r--r-- | mojo/shell/application_manager.h | 30 | ||||
-rw-r--r-- | mojo/shell/application_manager_unittest.cc | 6 | ||||
-rw-r--r-- | mojo/shell/capability_filter.cc | 19 | ||||
-rw-r--r-- | mojo/shell/capability_filter.h | 57 | ||||
-rw-r--r-- | mojo/shell/capability_filter_unittest.cc | 563 | ||||
-rw-r--r-- | mojo/shell/capability_filter_unittest.mojom | 7 | ||||
-rw-r--r-- | mojo/shell/content_handler_connection.cc | 10 | ||||
-rw-r--r-- | mojo/shell/content_handler_connection.h | 10 |
12 files changed, 532 insertions, 297 deletions
diff --git a/mojo/shell/BUILD.gn b/mojo/shell/BUILD.gn index d19134a..f70d37c 100644 --- a/mojo/shell/BUILD.gn +++ b/mojo/shell/BUILD.gn @@ -13,6 +13,8 @@ source_set("shell") { "application_loader.h", "application_manager.cc", "application_manager.h", + "capability_filter.cc", + "capability_filter.h", "content_handler_connection.cc", "content_handler_connection.h", "data_pipe_peek.cc", diff --git a/mojo/shell/application_instance.cc b/mojo/shell/application_instance.cc index 2bdf585..45d3e4b 100644 --- a/mojo/shell/application_instance.cc +++ b/mojo/shell/application_instance.cc @@ -55,7 +55,7 @@ void ApplicationInstance::ConnectToClient( const GURL& requestor_url, InterfaceRequest<ServiceProvider> services, ServiceProviderPtr exposed_services, - CapabilityFilterPtr filter) { + const CapabilityFilter& filter) { if (queue_requests_) { QueuedClientRequest* queued_request = new QueuedClientRequest(); queued_request->originator = originator; @@ -63,7 +63,7 @@ void ApplicationInstance::ConnectToClient( queued_request->requestor_url = requestor_url; queued_request->services = services.Pass(); queued_request->exposed_services = exposed_services.Pass(); - queued_request->filter = filter.Pass(); + queued_request->filter = filter; queued_client_requests_.push_back(queued_request); return; } @@ -72,9 +72,8 @@ void ApplicationInstance::ConnectToClient( exposed_services.Pass(), requested_url); } -ApplicationInstance::AllowedInterfaces - ApplicationInstance::GetAllowedInterfaces( - const Identity& identity) const { +AllowedInterfaces ApplicationInstance::GetAllowedInterfaces( + const Identity& identity) const { // Start by looking for interfaces specific to the supplied identity. auto it = filter_.find(identity.url.spec()); if (it != filter_.end()) @@ -101,12 +100,16 @@ void ApplicationInstance::ConnectToApplication( return; } if (allow_any_application_ || filter_.find(url_string) != filter_.end()) { + CapabilityFilter capability_filter = GetPermissiveCapabilityFilter(); + if (!filter.is_null()) + capability_filter = filter->filter.To<CapabilityFilter>(); manager_->ConnectToApplication(this, app_request.Pass(), std::string(), identity_.url, services.Pass(), - exposed_services.Pass(), filter.Pass(), + exposed_services.Pass(), capability_filter, base::Closure()); } else { - DVLOG(2) << "CapabilityFilter prevented connection to: " << url_string; + DVLOG(1) << "CapabilityFilter prevented connection from: " << + identity_.url << " to: " << url_string; } } @@ -152,7 +155,7 @@ void ApplicationInstance::OnConnectionError() { request->requestor_url, request->services.Pass(), request->exposed_services.Pass(), - request->filter.Pass(), + request->filter, base::Closure()); } STLDeleteElements(&queued_client_requests); diff --git a/mojo/shell/application_instance.h b/mojo/shell/application_instance.h index 8e9b6de..f50ab82 100644 --- a/mojo/shell/application_instance.h +++ b/mojo/shell/application_instance.h @@ -11,38 +11,11 @@ #include "mojo/application/public/interfaces/application.mojom.h" #include "mojo/application/public/interfaces/shell.mojom.h" #include "mojo/public/cpp/bindings/binding.h" +#include "mojo/shell/capability_filter.h" #include "mojo/shell/identity.h" #include "url/gurl.h" namespace mojo { - -// TODO(beng): upstream this into mojo repo, array.h so it can be shared with -// application_impl.cc. -// A |TypeConverter| that will create an |std::set<E>| containing a copy of -// the contents of an |Array<T>|, using |TypeConverter<E, T>| to copy each -// element. If the input array is null, the output set will be empty. -template <typename E, typename T> -struct TypeConverter <std::set<E>, Array<T>> { - static std::set<E> Convert(const Array<T>& input) { - std::set<E> result; - if (!input.is_null()) { - for (size_t i = 0; i < input.size(); ++i) - result.insert(TypeConverter<E, T>::Convert(input[i])); - } - return result; - } -}; - -template <typename T, typename E> -struct TypeConverter <Array<T>, std::set<E>> { - static Array<T> Convert(const std::set<E>& input) { - Array<T> result(0u); - for (auto i : input) - result.push_back(TypeConverter<T, E>::Convert(i)); - return result.Pass(); - } -}; - namespace shell { class ApplicationManager; @@ -51,9 +24,6 @@ class ApplicationManager; // shell's ApplicationManager. class ApplicationInstance : public Shell { public: - using AllowedInterfaces = std::set<std::string>; - using CapabilityFilter = std::map<std::string, AllowedInterfaces>; - ApplicationInstance(ApplicationPtr application, ApplicationManager* manager, const Identity& originator_identity, @@ -70,7 +40,7 @@ class ApplicationInstance : public Shell { const GURL& requestor_url, InterfaceRequest<ServiceProvider> services, ServiceProviderPtr exposed_services, - CapabilityFilterPtr filter); + const CapabilityFilter& filter); // Returns the set of interfaces this application instance is allowed to see // from an instance with |identity|. @@ -106,7 +76,7 @@ class ApplicationInstance : public Shell { GURL requestor_url; InterfaceRequest<ServiceProvider> services; ServiceProviderPtr exposed_services; - CapabilityFilterPtr filter; + CapabilityFilter filter; }; ApplicationManager* const manager_; diff --git a/mojo/shell/application_manager.cc b/mojo/shell/application_manager.cc index 9538f5a..1abe49c 100644 --- a/mojo/shell/application_manager.cc +++ b/mojo/shell/application_manager.cc @@ -75,7 +75,7 @@ void ApplicationManager::ConnectToApplication( const GURL& requestor_url, InterfaceRequest<ServiceProvider> services, ServiceProviderPtr exposed_services, - CapabilityFilterPtr filter, + const CapabilityFilter& filter, const base::Closure& on_application_end) { GURL requested_gurl(requested_url->url.To<std::string>()); TRACE_EVENT_INSTANT1( @@ -89,35 +89,35 @@ void ApplicationManager::ConnectToApplication( GURL mapped_url = delegate_->ResolveMappings(requested_gurl); if (ConnectToRunningApplication(originator, mapped_url, qualifier, requestor_url, &services, - &exposed_services, &filter)) { + &exposed_services, filter)) { return; } GURL resolved_url = delegate_->ResolveMojoURL(mapped_url); if (ConnectToRunningApplication(originator, resolved_url, qualifier, requestor_url, &services, - &exposed_services, &filter)) { + &exposed_services, filter)) { return; } // The application is not running, let's compute the parameters. if (ConnectToApplicationWithLoader( originator, requested_gurl, qualifier, mapped_url, requestor_url, - &services, &exposed_services, &filter, on_application_end, + &services, &exposed_services, filter, on_application_end, GetLoaderForURL(mapped_url))) { return; } if (ConnectToApplicationWithLoader( originator, requested_gurl, qualifier, resolved_url, requestor_url, - &services, &exposed_services, &filter, on_application_end, + &services, &exposed_services, filter, on_application_end, GetLoaderForURL(resolved_url))) { return; } if (ConnectToApplicationWithLoader( originator, requested_gurl, qualifier, resolved_url, requestor_url, - &services, &exposed_services, &filter, on_application_end, + &services, &exposed_services, filter, on_application_end, default_loader_.get())) { return; } @@ -126,8 +126,7 @@ void ApplicationManager::ConnectToApplication( &ApplicationManager::HandleFetchCallback, weak_ptr_factory_.GetWeakPtr(), originator, requested_gurl, qualifier, requestor_url, base::Passed(services.Pass()), base::Passed(exposed_services.Pass()), - base::Passed(filter.Pass()), - on_application_end); + filter, on_application_end); if (delegate_->CreateFetcher( resolved_url, @@ -182,7 +181,7 @@ bool ApplicationManager::ConnectToRunningApplication( const GURL& requestor_url, InterfaceRequest<ServiceProvider>* services, ServiceProviderPtr* exposed_services, - CapabilityFilterPtr* filter) { + const CapabilityFilter& filter) { GURL application_url = GetBaseURLAndQuery(resolved_url, nullptr); ApplicationInstance* instance = GetApplicationInstance(Identity(application_url, qualifier)); @@ -191,7 +190,7 @@ bool ApplicationManager::ConnectToRunningApplication( instance->ConnectToClient(originator, resolved_url, requestor_url, services->Pass(), exposed_services->Pass(), - filter->Pass()); + filter); return true; } @@ -203,7 +202,7 @@ bool ApplicationManager::ConnectToApplicationWithLoader( const GURL& requestor_url, InterfaceRequest<ServiceProvider>* services, ServiceProviderPtr* exposed_services, - CapabilityFilterPtr* filter, + const CapabilityFilter& filter, const base::Closure& on_application_end, ApplicationLoader* loader) { if (!loader) @@ -216,7 +215,7 @@ bool ApplicationManager::ConnectToApplicationWithLoader( resolved_url, RegisterInstance(originator, app_url, qualifier, requestor_url, services->Pass(), exposed_services->Pass(), - filter->Pass(), on_application_end)); + filter, on_application_end)); return true; } @@ -227,28 +226,20 @@ InterfaceRequest<Application> ApplicationManager::RegisterInstance( const GURL& requestor_url, InterfaceRequest<ServiceProvider> services, ServiceProviderPtr exposed_services, - CapabilityFilterPtr filter, + const CapabilityFilter& filter, const base::Closure& on_application_end) { Identity app_identity(app_url, qualifier); ApplicationPtr application; InterfaceRequest<Application> application_request = GetProxy(&application); - ApplicationInstance::CapabilityFilter capability_filter; - std::set<std::string> interfaces; - interfaces.insert("*"); - capability_filter["*"] = interfaces; - if (!filter.is_null()) { - capability_filter = - filter->filter.To<ApplicationInstance::CapabilityFilter>(); - } ApplicationInstance* instance = new ApplicationInstance( application.Pass(), this, originator ? originator->identity() : Identity(GURL()), app_identity, - capability_filter, on_application_end); + filter, on_application_end); identity_to_instance_[app_identity] = instance; instance->InitializeApplication(); instance->ConnectToClient(originator, app_url, requestor_url, services.Pass(), - exposed_services.Pass(), filter.Pass()); + exposed_services.Pass(), filter); return application_request.Pass(); } @@ -267,7 +258,7 @@ void ApplicationManager::HandleFetchCallback( const GURL& requestor_url, InterfaceRequest<ServiceProvider> services, ServiceProviderPtr exposed_services, - CapabilityFilterPtr filter, + const CapabilityFilter& filter, const base::Closure& on_application_end, NativeApplicationCleanup cleanup, scoped_ptr<Fetcher> fetcher) { @@ -287,7 +278,7 @@ void ApplicationManager::HandleFetchCallback( header->value = fetcher->GetRedirectReferer().spec(); request->headers.push_back(header.Pass()); ConnectToApplication(originator, request.Pass(), qualifier, requestor_url, - services.Pass(), exposed_services.Pass(), nullptr, + services.Pass(), exposed_services.Pass(), filter, on_application_end); return; } @@ -300,7 +291,7 @@ void ApplicationManager::HandleFetchCallback( // already running. if (ConnectToRunningApplication(originator, requested_url, qualifier, requestor_url, &services, - &exposed_services, &filter)) { + &exposed_services, filter)) { return; } @@ -309,7 +300,7 @@ void ApplicationManager::HandleFetchCallback( InterfaceRequest<Application> request( RegisterInstance(originator, app_url, qualifier, requestor_url, - services.Pass(), exposed_services.Pass(), filter.Pass(), + services.Pass(), exposed_services.Pass(), filter, on_application_end)); // For resources that are loaded with content handlers, we group app instances @@ -326,8 +317,8 @@ void ApplicationManager::HandleFetchCallback( blocking_pool_, static_cast<int>(shebang.size()))); std::string site = enable_multi_process ? response->site.To<std::string>() : std::string(); - LoadWithContentHandler(content_handler_url, requestor_url, site, - request.Pass(), response.Pass()); + LoadWithContentHandler(originator, content_handler_url, requestor_url, site, + filter, request.Pass(), response.Pass()); return; } @@ -336,8 +327,8 @@ void ApplicationManager::HandleFetchCallback( URLResponsePtr response(fetcher->AsURLResponse(blocking_pool_, 0)); std::string site = enable_multi_process ? response->site.To<std::string>() : std::string(); - LoadWithContentHandler(iter->second, requestor_url, site, request.Pass(), - response.Pass()); + LoadWithContentHandler(originator, iter->second, requestor_url, site, + filter, request.Pass(), response.Pass()); return; } @@ -362,8 +353,9 @@ void ApplicationManager::HandleFetchCallback( qualifier = alias_iter->second.second; } - LoadWithContentHandler(alias_iter->second.first, requestor_url, qualifier, - request.Pass(), response.Pass()); + LoadWithContentHandler(originator, alias_iter->second.first, requestor_url, + qualifier, filter, request.Pass(), + response.Pass()); return; } @@ -440,19 +432,24 @@ void ApplicationManager::RegisterApplicationPackageAlias( } void ApplicationManager::LoadWithContentHandler( + ApplicationInstance* originator, const GURL& content_handler_url, const GURL& requestor_url, const std::string& qualifier, + const CapabilityFilter& filter, InterfaceRequest<Application> application_request, URLResponsePtr url_response) { ContentHandlerConnection* connection = nullptr; std::pair<GURL, std::string> key(content_handler_url, qualifier); + // TODO(beng): Figure out the extent to which capability filter should be + // factored into handler identity. URLToContentHandlerMap::iterator iter = url_to_content_handler_.find(key); if (iter != url_to_content_handler_.end()) { connection = iter->second; } else { - connection = new ContentHandlerConnection(this, content_handler_url, - requestor_url, qualifier); + connection = new ContentHandlerConnection( + originator, this, content_handler_url, requestor_url, qualifier, + filter); url_to_content_handler_[key] = connection; } @@ -538,7 +535,8 @@ ScopedMessagePipeHandle ApplicationManager::ConnectToServiceByName( mojo::URLRequestPtr request(mojo::URLRequest::New()); request->url = mojo::String::From(application_url.spec()); ConnectToApplication(nullptr, request.Pass(), std::string(), GURL(), - GetProxy(&services), nullptr, nullptr, base::Closure()); + GetProxy(&services), nullptr, + GetPermissiveCapabilityFilter(), base::Closure()); MessagePipe pipe; services->ConnectToService(interface_name, pipe.handle1.Pass()); return pipe.handle0.Pass(); diff --git a/mojo/shell/application_manager.h b/mojo/shell/application_manager.h index b1613f7..324761f 100644 --- a/mojo/shell/application_manager.h +++ b/mojo/shell/application_manager.h @@ -18,6 +18,7 @@ #include "mojo/services/network/public/interfaces/url_loader_factory.mojom.h" #include "mojo/services/updater/updater.mojom.h" #include "mojo/shell/application_loader.h" +#include "mojo/shell/capability_filter.h" #include "mojo/shell/fetcher.h" #include "mojo/shell/identity.h" #include "mojo/shell/native_runner.h" @@ -80,15 +81,14 @@ class ApplicationManager { // |originator| can be NULL (e.g. for the first application or in tests), but // typically is non-NULL and identifies the instance initiating the // connection. - void ConnectToApplication( - ApplicationInstance* originator, - URLRequestPtr requested_url, - const std::string& qualifier, - const GURL& requestor_url, - InterfaceRequest<ServiceProvider> services, - ServiceProviderPtr exposed_services, - CapabilityFilterPtr filter, - const base::Closure& on_application_end); + void ConnectToApplication(ApplicationInstance* originator, + URLRequestPtr requested_url, + const std::string& qualifier, + const GURL& requestor_url, + InterfaceRequest<ServiceProvider> services, + ServiceProviderPtr exposed_services, + const CapabilityFilter& capability_filter, + const base::Closure& on_application_end); // Must only be used by shell internals and test code as it does not forward // capability filters. @@ -172,7 +172,7 @@ class ApplicationManager { const GURL& requestor_url, InterfaceRequest<ServiceProvider>* services, ServiceProviderPtr* exposed_services, - CapabilityFilterPtr* filter); + const CapabilityFilter& filter); bool ConnectToApplicationWithLoader( ApplicationInstance* originator, @@ -182,7 +182,7 @@ class ApplicationManager { const GURL& requestor_url, InterfaceRequest<ServiceProvider>* services, ServiceProviderPtr* exposed_services, - CapabilityFilterPtr* filter, + const CapabilityFilter& filter, const base::Closure& on_application_end, ApplicationLoader* loader); @@ -193,7 +193,7 @@ class ApplicationManager { const GURL& requestor_url, InterfaceRequest<ServiceProvider> services, ServiceProviderPtr exposed_services, - CapabilityFilterPtr filter, + const CapabilityFilter& filter, const base::Closure& on_application_end); // Called once |fetcher| has found app. |requested_url| is the url of the @@ -204,7 +204,7 @@ class ApplicationManager { const GURL& requestor_url, InterfaceRequest<ServiceProvider> services, ServiceProviderPtr exposed_services, - CapabilityFilterPtr filter, + const CapabilityFilter& filter, const base::Closure& on_application_end, NativeApplicationCleanup cleanup, scoped_ptr<Fetcher> fetcher); @@ -217,9 +217,11 @@ class ApplicationManager { const base::FilePath& file_path, bool path_exists); - void LoadWithContentHandler(const GURL& content_handler_url, + void LoadWithContentHandler(ApplicationInstance* originator, + const GURL& content_handler_url, const GURL& requestor_url, const std::string& qualifier, + const CapabilityFilter& filter, InterfaceRequest<Application> application_request, URLResponsePtr url_response); diff --git a/mojo/shell/application_manager_unittest.cc b/mojo/shell/application_manager_unittest.cc index 980ad18..01c285c 100644 --- a/mojo/shell/application_manager_unittest.cc +++ b/mojo/shell/application_manager_unittest.cc @@ -759,7 +759,8 @@ TEST_F(ApplicationManagerTest, TestEndApplicationClosure) { mojo::URLRequestPtr request(mojo::URLRequest::New()); request->url = mojo::String::From("test:test"); application_manager_->ConnectToApplication( - nullptr, request.Pass(), std::string(), GURL(), nullptr, nullptr, nullptr, + nullptr, request.Pass(), std::string(), GURL(), nullptr, nullptr, + GetPermissiveCapabilityFilter(), base::Bind(&QuitClosure, base::Unretained(&called))); loop_.Run(); EXPECT_TRUE(called); @@ -787,7 +788,8 @@ TEST(ApplicationManagerTest2, ContentHandlerConnectionGetsRequestorURL) { request->url = mojo::String::From("test:test"); application_manager.ConnectToApplication( nullptr, request.Pass(), std::string(), requestor_url, nullptr, nullptr, - nullptr, base::Bind(&QuitClosure, base::Unretained(&called))); + GetPermissiveCapabilityFilter(), + base::Bind(&QuitClosure, base::Unretained(&called))); loop.Run(); EXPECT_TRUE(called); diff --git a/mojo/shell/capability_filter.cc b/mojo/shell/capability_filter.cc new file mode 100644 index 0000000..fa39449 --- /dev/null +++ b/mojo/shell/capability_filter.cc @@ -0,0 +1,19 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/shell/capability_filter.h" + +namespace mojo { +namespace shell { + +CapabilityFilter GetPermissiveCapabilityFilter() { + CapabilityFilter filter; + AllowedInterfaces interfaces; + interfaces.insert("*"); + filter["*"] = interfaces; + return filter; +} + +} // namespace shell +} // namespace mojo diff --git a/mojo/shell/capability_filter.h b/mojo/shell/capability_filter.h new file mode 100644 index 0000000..6d17cc3 --- /dev/null +++ b/mojo/shell/capability_filter.h @@ -0,0 +1,57 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_SHELL_CAPABILITY_FILTER_H_ +#define MOJO_SHELL_CAPABILITY_FILTER_H_ + +#include <map> +#include <set> + +#include "mojo/public/cpp/bindings/array.h" + +namespace mojo { +// TODO(beng): upstream this into mojo repo, array.h so it can be shared with +// application_impl.cc. +// A |TypeConverter| that will create an |std::set<E>| containing a copy of +// the contents of an |Array<T>|, using |TypeConverter<E, T>| to copy each +// element. If the input array is null, the output set will be empty. +template <typename E, typename T> +struct TypeConverter <std::set<E>, Array<T>> { + static std::set<E> Convert(const Array<T>& input) { + std::set<E> result; + if (!input.is_null()) { + for (size_t i = 0; i < input.size(); ++i) + result.insert(TypeConverter<E, T>::Convert(input[i])); + } + return result; + } +}; + +template <typename T, typename E> +struct TypeConverter <Array<T>, std::set<E>> { + static Array<T> Convert(const std::set<E>& input) { + Array<T> result(0u); + for (auto i : input) + result.push_back(TypeConverter<T, E>::Convert(i)); + return result.Pass(); + } +}; + +namespace shell { + +// A set of names of interfaces that may be exposed to an application. +using AllowedInterfaces = std::set<std::string>; +// A map of allowed applications to allowed interface sets. See shell.mojom for +// more details. +using CapabilityFilter = std::map<std::string, AllowedInterfaces>; + +// Returns a capability filter that allows an application to connect to any +// other application and any service exposed by other applications. +CapabilityFilter GetPermissiveCapabilityFilter(); + +} // namespace shell +} // namespace mojo + + +#endif // MOJO_SHELL_CAPABILITY_FILTER_H_ diff --git a/mojo/shell/capability_filter_unittest.cc b/mojo/shell/capability_filter_unittest.cc index 612a487..688815f 100644 --- a/mojo/shell/capability_filter_unittest.cc +++ b/mojo/shell/capability_filter_unittest.cc @@ -5,13 +5,17 @@ #include "base/at_exit.h" #include "base/bind.h" #include "base/macros.h" +#include "base/memory/scoped_vector.h" #include "base/message_loop/message_loop.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "mojo/application/public/cpp/application_connection.h" #include "mojo/application/public/cpp/application_delegate.h" #include "mojo/application/public/cpp/application_impl.h" #include "mojo/application/public/cpp/connect.h" #include "mojo/application/public/cpp/interface_factory.h" +#include "mojo/application/public/cpp/service_provider_impl.h" +#include "mojo/application/public/interfaces/content_handler.mojom.h" #include "mojo/common/weak_binding_set.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/shell/application_loader.h" @@ -23,34 +27,65 @@ namespace mojo { namespace shell { namespace { +const char kTestMimeType[] = "test/mime-type"; + +// Lives on the main thread of the test. // Listens for services exposed/blocked and for application connections being // closed. Quits |loop| when all expectations are met. -class ConnectionValidator { +class ConnectionValidator : public ApplicationLoader, + public ApplicationDelegate, + public InterfaceFactory<Validator>, + public Validator { public: ConnectionValidator(const std::set<std::string>& expectations, base::MessageLoop* loop) - : expectations_(expectations), + : app_(nullptr), + expectations_(expectations), loop_(loop) {} - ~ConnectionValidator() {} + ~ConnectionValidator() override {} - void AddServiceCalled(const std::string& app_url, - const std::string& service_url, - const std::string& name, - bool blocked) { - Validate(base::StringPrintf("%s %s %s %s", - blocked ? "B" : "E", app_url.c_str(), service_url.c_str(), - name.c_str())); + bool expectations_met() { + return unexpected_.empty() && expectations_.empty(); } - void ConnectionClosed(const std::string& app_url, - const std::string& service_url) { - Validate(base::StringPrintf("C %s %s", app_url.c_str(), - service_url.c_str())); + void PrintUnmetExpectations() { + for (auto expectation : expectations_) + ADD_FAILURE() << "Unmet: " << expectation; + for (auto unexpected : unexpected_) + ADD_FAILURE() << "Unexpected: " << unexpected; } - bool expectations_met() { return expectations_.empty(); } - private: + // Overridden from ApplicationLoader: + void Load(const GURL& url, InterfaceRequest<Application> request) override { + app_.reset(new ApplicationImpl(this, request.Pass())); + } + + // Overridden from ApplicationDelegate: + bool ConfigureIncomingConnection(ApplicationConnection* connection) override { + connection->AddService<Validator>(this); + return true; + } + + // Overridden from InterfaceFactory<Validator>: + void Create(ApplicationConnection* connection, + InterfaceRequest<Validator> request) override { + validator_bindings_.AddBinding(this, request.Pass()); + } + + // Overridden from Validator: + void AddServiceCalled(const String& app_url, + const String& service_url, + const String& name, + bool blocked) override { + Validate(base::StringPrintf("%s %s %s %s", + blocked ? "B" : "E", app_url.data(), service_url.data(), name.data())); + } + void ConnectionClosed(const String& app_url, + const String& service_url) override { + Validate(base::StringPrintf("C %s %s", app_url.data(), service_url.data())); + } + void Validate(const std::string& result) { DVLOG(1) << "Validate: " << result; auto i = expectations_.find(result); @@ -59,13 +94,18 @@ class ConnectionValidator { if (expectations_.empty()) loop_->Quit(); } else { - DVLOG(1) << "Unexpected result."; + // This is a test failure, and will result in PrintUnexpectedExpecations() + // being called. + unexpected_.insert(result); loop_->Quit(); } } + scoped_ptr<ApplicationImpl> app_; std::set<std::string> expectations_; + std::set<std::string> unexpected_; base::MessageLoop* loop_; + WeakBindingSet<Validator> validator_bindings_; DISALLOW_COPY_AND_ASSIGN(ConnectionValidator); }; @@ -73,106 +113,112 @@ class ConnectionValidator { // This class models an application who will use the shell to interact with a // system service. The shell may limit this application's visibility of the full // set of interfaces exposed by that service. -class TestApplication : public ApplicationDelegate, - public ApplicationLoader, - public InterfaceFactory<Client>, - public Client { +class TestApplication : public ApplicationDelegate { public: - TestApplication(ConnectionValidator* validator, - bool connect_to_test_service_2) - : validator_(validator), - connect_to_test_service_2_(connect_to_test_service_2) {} - ~TestApplication() override {} + TestApplication() : app_(nullptr) {} + ~TestApplication() override {} private: // Overridden from ApplicationDelegate: - bool ConfigureIncomingConnection(ApplicationConnection*) override { + void Initialize(ApplicationImpl* app) override { + app_ = app; + } + bool ConfigureIncomingConnection(ApplicationConnection* connection) override { + // TestApplications receive their Validator via the inbound connection. + connection->ConnectToService(&validator_); + URLRequestPtr request(URLRequest::New()); request->url = String::From("test:service"); - ApplicationConnection* connection = + ApplicationConnection* connection1 = app_->ConnectToApplication(request.Pass()); - connection->SetRemoteServiceProviderConnectionErrorHandler( - base::Bind(&TestApplication::Connection1Closed, - base::Unretained(this))); - - if (connect_to_test_service_2_) { - URLRequestPtr request2(URLRequest::New()); - request2->url = String::From("test:service2"); - ApplicationConnection* connection2 = - app_->ConnectToApplication(request2.Pass()); - connection2->SetRemoteServiceProviderConnectionErrorHandler( - base::Bind(&TestApplication::Connection2Closed, - base::Unretained(this))); - } - return true; - } - bool ConfigureOutgoingConnection(ApplicationConnection* connection) override { - connection->AddService<Client>(this); + connection1->SetRemoteServiceProviderConnectionErrorHandler( + base::Bind(&TestApplication::ConnectionClosed, + base::Unretained(this), "test:service")); + + URLRequestPtr request2(URLRequest::New()); + request2->url = String::From("test:service2"); + ApplicationConnection* connection2 = + app_->ConnectToApplication(request2.Pass()); + connection2->SetRemoteServiceProviderConnectionErrorHandler( + base::Bind(&TestApplication::ConnectionClosed, + base::Unretained(this), "test:service2")); return true; } - // Overridden from ApplicationLoader: - void Load(const GURL& url, InterfaceRequest<Application> request) override { - app_.reset(new ApplicationImpl(this, request.Pass())); + void ConnectionClosed(const std::string& service_url) { + validator_->ConnectionClosed(app_->url(), service_url); } - // Overridden from InterfaceFactory<Client>: - void Create(ApplicationConnection* connection, - InterfaceRequest<Client> request) override { - client_bindings_.AddBinding(this, request.Pass()); - } + ApplicationImpl* app_; + ValidatorPtr validator_; - // Overridden from Client: - void AddServiceCalled(const String& app_url, - const String& service_url, - const String& name, - bool blocked) override { - validator_->AddServiceCalled(app_url, service_url, name, blocked); + DISALLOW_COPY_AND_ASSIGN(TestApplication); +}; + +class TestContentHandler : public ApplicationDelegate, + public InterfaceFactory<ContentHandler>, + public ContentHandler { + public: + TestContentHandler() : app_(nullptr) {} + ~TestContentHandler() override {} + + private: + // Overridden from ApplicationDelegate: + void Initialize(ApplicationImpl* app) override { + app_ = app; + } + bool ConfigureIncomingConnection(ApplicationConnection* connection) override { + connection->AddService<ContentHandler>(this); + return true; } - void Connection1Closed() { - validator_->ConnectionClosed(app_->url(), "test:service"); + // Overridden from InterfaceFactory<ContentHandler>: + void Create(ApplicationConnection* connection, + InterfaceRequest<ContentHandler> request) override { + bindings_.AddBinding(this, request.Pass()); } - void Connection2Closed() { - validator_->ConnectionClosed(app_->url(), "test:service2"); + // Overridden from ContentHandler: + void StartApplication(InterfaceRequest<Application> application, + URLResponsePtr response) override { + embedded_apps_.push_back( + new ApplicationImpl(new TestApplication, application.Pass())); } - ConnectionValidator* validator_; - bool connect_to_test_service_2_; - scoped_ptr<ApplicationImpl> app_; - WeakBindingSet<Client> client_bindings_; + ApplicationImpl* app_; + WeakBindingSet<ContentHandler> bindings_; + ScopedVector<ApplicationImpl> embedded_apps_; - DISALLOW_COPY_AND_ASSIGN(TestApplication); + DISALLOW_COPY_AND_ASSIGN(TestContentHandler); }; // This class models a system service that exposes two interfaces, Safe and // Unsafe. The interface Unsafe is not to be exposed to untrusted applications. class ServiceApplication : public ApplicationDelegate, - public ApplicationLoader, public InterfaceFactory<Safe>, public InterfaceFactory<Unsafe>, public Safe, public Unsafe { public: - ServiceApplication() {} + ServiceApplication() : app_(nullptr) {} ~ServiceApplication() override {} private: // Overridden from ApplicationDelegate: + void Initialize(ApplicationImpl* app) override { + app_ = app; + // ServiceApplications have no capability filter and can thus connect + // directly to the validator application. + URLRequestPtr request(URLRequest::New()); + request->url = String::From("test:validator"); + app_->ConnectToService(request.Pass(), &validator_); + } bool ConfigureIncomingConnection(ApplicationConnection* connection) override { - connection->ConnectToService(&client_); AddService<Safe>(connection); AddService<Unsafe>(connection); return true; } - // Overridden from ApplicationLoader: - void Load(const GURL& url, - InterfaceRequest<Application> application_request) override { - app_.reset(new ApplicationImpl(this, application_request.Pass())); - } - // Overridden from InterfaceFactory<Safe>: void Create(ApplicationConnection* connection, InterfaceRequest<Safe> request) override { @@ -187,25 +233,63 @@ class ServiceApplication : public ApplicationDelegate, template <typename Interface> void AddService(ApplicationConnection* connection) { - client_->AddServiceCalled(connection->GetRemoteApplicationURL(), - connection->GetConnectionURL(), - Interface::Name_, - !connection->AddService<Interface>(this)); + validator_->AddServiceCalled(connection->GetRemoteApplicationURL(), + connection->GetConnectionURL(), + Interface::Name_, + !connection->AddService<Interface>(this)); } - scoped_ptr<ApplicationImpl> app_; - ClientPtr client_; + ApplicationImpl* app_; + ValidatorPtr validator_; WeakBindingSet<Safe> safe_bindings_; WeakBindingSet<Unsafe> unsafe_bindings_; DISALLOW_COPY_AND_ASSIGN(ServiceApplication); }; +// A custom Fetcher used to trigger a content handler for kTestMimeType for a +// specific test. +class TestFetcher : public Fetcher { + public: + TestFetcher(const GURL& url, const FetchCallback& callback) + : Fetcher(callback), + url_(url) { + loader_callback_.Run(make_scoped_ptr(this)); + } + ~TestFetcher() override {} + + private: + // Overridden from Fetcher: + const GURL& GetURL() const override { return url_; } + GURL GetRedirectURL() const override { return GURL(); } + GURL GetRedirectReferer() const override { return GURL(); } + URLResponsePtr AsURLResponse(base::TaskRunner* task_runner, + uint32_t skip) override { + URLResponsePtr response(URLResponse::New()); + response->url = url_.spec(); + return response.Pass(); + } + void AsPath( + base::TaskRunner* task_runner, + base::Callback<void(const base::FilePath&, bool)> callback) override {} + std::string MimeType() override { return kTestMimeType; } + bool HasMojoMagic() override { return false; } + bool PeekFirstLine(std::string* line) override { return false; } + + const GURL url_; + + DISALLOW_COPY_AND_ASSIGN(TestFetcher); +}; + class TestApplicationManagerDelegate : public ApplicationManager::Delegate { public: TestApplicationManagerDelegate() {} ~TestApplicationManagerDelegate() override {} + void set_use_test_fetcher(bool use_test_fetcher) { + use_test_fetcher_ = use_test_fetcher; + } + private: // Overridden from ApplicationManager::Delegate: GURL ResolveMappings(const GURL& url) override { @@ -216,157 +300,250 @@ class TestApplicationManagerDelegate : public ApplicationManager::Delegate { } bool CreateFetcher(const GURL& url, const Fetcher::FetchCallback& loader_callback) override { + if (use_test_fetcher_) { + new TestFetcher(url, loader_callback); + return true; + } return false; } + bool use_test_fetcher_; + DISALLOW_COPY_AND_ASSIGN(TestApplicationManagerDelegate); }; +class TestLoader : public ApplicationLoader { + public: + explicit TestLoader(ApplicationDelegate* delegate) : delegate_(delegate) {} + ~TestLoader() override {} + + private: + // Overridden from ApplicationLoader: + void Load(const GURL& url, InterfaceRequest<Application> request) override { + app_.reset(new ApplicationImpl(delegate_.get(), request.Pass())); + } + + scoped_ptr<ApplicationDelegate> delegate_; + scoped_ptr<ApplicationImpl> app_; + + DISALLOW_COPY_AND_ASSIGN(TestLoader); +}; + class CapabilityFilterTest : public testing::Test { public: - CapabilityFilterTest() {} + CapabilityFilterTest() : validator_(nullptr) {} ~CapabilityFilterTest() override {} protected: - void RunApplication(const std::string& url, CapabilityFilterPtr filter) { + void RunApplication(const std::string& url, const CapabilityFilter& filter) { ServiceProviderPtr services; + + // We expose Validator to the test application via ConnectToApplication + // because we don't allow the test application to connect to test:validator. + // Adding it to the CapabilityFilter would interfere with the test. + ServiceProviderPtr exposed_services; + (new ServiceProviderImpl(GetProxy(&exposed_services)))-> + AddService<Validator>(validator_); URLRequestPtr request(URLRequest::New()); request->url = String::From(url); application_manager_->ConnectToApplication( nullptr, request.Pass(), std::string(), GURL(), GetProxy(&services), - nullptr, filter.Pass(), base::MessageLoop::QuitWhenIdleClosure()); + exposed_services.Pass(), filter, + base::MessageLoop::QuitWhenIdleClosure()); + } + + void InitValidator(const std::set<std::string>& expectations) { + validator_ = new ConnectionValidator(expectations, &loop_); + application_manager()->SetLoaderForURL(make_scoped_ptr(validator_), + GURL("test:validator")); + } + + template <class T> + void CreateLoader(const std::string& url) { + application_manager_->SetLoaderForURL( + make_scoped_ptr(new TestLoader(new T)), GURL(url)); + } + + virtual void RunTest() { + loop()->Run(); + EXPECT_TRUE(validator_->expectations_met()); + if (!validator_->expectations_met()) + validator_->PrintUnmetExpectations(); + } + + void RunContentHandlerTest() { + set_use_test_fetcher(); + + GURL content_handler_url("test:content_handler"); + application_manager()->RegisterContentHandler(kTestMimeType, + content_handler_url); + + CreateLoader<TestContentHandler>(content_handler_url.spec()); + RunTest(); } base::MessageLoop* loop() { return &loop_; } ApplicationManager* application_manager() { return application_manager_.get(); } + ConnectionValidator* validator() { return validator_; } + void set_use_test_fetcher() { + test_delegate_.set_use_test_fetcher(true); + } - private: // Overridden from testing::Test: void SetUp() override { application_manager_.reset(new ApplicationManager(&test_delegate_)); + CreateLoader<ServiceApplication>("test:service"); + CreateLoader<ServiceApplication>("test:service2"); } void TearDown() override { application_manager_.reset(); + test_delegate_.set_use_test_fetcher(false); + } + + private: + template<class T> + scoped_ptr<ApplicationDelegate> CreateApplicationDelegate() { + return scoped_ptr<ApplicationDelegate>(new T); } base::ShadowingAtExitManager at_exit_; TestApplicationManagerDelegate test_delegate_; base::MessageLoop loop_; scoped_ptr<ApplicationManager> application_manager_; + ConnectionValidator* validator_; DISALLOW_COPY_AND_ASSIGN(CapabilityFilterTest); }; -TEST_F(CapabilityFilterTest, Blocking) { - std::set<std::string> expectations; - expectations.insert("E test:trusted test:service mojo::shell::Safe"); - expectations.insert("E test:trusted test:service mojo::shell::Unsafe"); - expectations.insert("E test:trusted test:service2 mojo::shell::Safe"); - expectations.insert("E test:trusted test:service2 mojo::shell::Unsafe"); - expectations.insert("E test:untrusted test:service mojo::shell::Safe"); - expectations.insert("B test:untrusted test:service mojo::shell::Unsafe"); - expectations.insert("C test:untrusted test:service2"); - - ConnectionValidator validator(expectations, loop()); - application_manager()->SetLoaderForURL( - make_scoped_ptr(new TestApplication(&validator, true)), - GURL("test:trusted")); - application_manager()->SetLoaderForURL( - make_scoped_ptr(new TestApplication(&validator, true)), - GURL("test:untrusted")); - application_manager()->SetLoaderForURL( - make_scoped_ptr(new ServiceApplication), GURL("test:service")); - application_manager()->SetLoaderForURL( - make_scoped_ptr(new ServiceApplication), GURL("test:service2")); - - Array<String> interfaces(Array<String>::New(1)); - interfaces[0] = String::From(std::string(Safe::Name_)); - CapabilityFilterPtr filter(CapabilityFilter::New()); - filter->filter.insert("test:service", interfaces.Pass()); - - // This first application can only connect to test:service. Connections to - // test:service2 will be blocked. It also will only be able to see the "Safe" - // interface exposed by test:service. It will be blocked from seeing "Unsafe". - RunApplication("test:untrusted", filter.Pass()); - - // This second application can connect to both test:service and test:service2. - // It can connect to both "Safe" and "Unsafe" interfaces. - RunApplication("test:trusted", nullptr); - - loop()->Run(); - - EXPECT_TRUE(validator.expectations_met()); +class CapabilityFilter_BlockingTest : public CapabilityFilterTest { + public: + CapabilityFilter_BlockingTest() {} + ~CapabilityFilter_BlockingTest() override {} + + protected: + void RunTest() override { + // This first application can only connect to test:service. Connections to + // test:service2 will be blocked. It also will only be able to see the + // "Safe" interface exposed by test:service. It will be blocked from seeing + // "Unsafe". + AllowedInterfaces interfaces; + interfaces.insert(Safe::Name_); + CapabilityFilter filter; + filter["test:service"] = interfaces; + RunApplication("test:untrusted", filter); + + // This second application can connect to both test:service and + // test:service2. It can connect to both "Safe" and "Unsafe" interfaces. + RunApplication("test:trusted", GetPermissiveCapabilityFilter()); + + CapabilityFilterTest::RunTest(); + } + + private: + // Overridden from CapabilityFilterTest: + void SetUp() override { + CapabilityFilterTest::SetUp(); + + std::set<std::string> expectations; + expectations.insert("E test:trusted test:service mojo::shell::Safe"); + expectations.insert("E test:trusted test:service mojo::shell::Unsafe"); + expectations.insert("E test:trusted test:service2 mojo::shell::Safe"); + expectations.insert("E test:trusted test:service2 mojo::shell::Unsafe"); + expectations.insert("E test:untrusted test:service mojo::shell::Safe"); + expectations.insert("B test:untrusted test:service mojo::shell::Unsafe"); + expectations.insert("C test:untrusted test:service2"); + InitValidator(expectations); + } + + DISALLOW_COPY_AND_ASSIGN(CapabilityFilter_BlockingTest); +}; + +TEST_F(CapabilityFilter_BlockingTest, Application) { + CreateLoader<TestApplication>("test:trusted"); + CreateLoader<TestApplication>("test:untrusted"); + RunTest(); +} + +TEST_F(CapabilityFilter_BlockingTest, ContentHandler) { + RunContentHandlerTest(); +} + +class CapabilityFilter_WildcardsTest : public CapabilityFilterTest { + public: + CapabilityFilter_WildcardsTest() {} + ~CapabilityFilter_WildcardsTest() override {} + + protected: + void RunTest() override { + // This application is allowed to connect to any application because of a + // wildcard rule, and any interface exposed because of a wildcard rule in + // the interface array. + RunApplication("test:wildcard", GetPermissiveCapabilityFilter()); + + // This application is allowed to connect to no other applications because + // of an empty capability filter. + RunApplication("test:blocked", CapabilityFilter()); + + // This application is allowed to connect to any application because of a + // wildcard rule but may not connect to any interfaces because of an empty + // interface array. + CapabilityFilter filter1; + filter1["*"] = AllowedInterfaces(); + RunApplication("test:wildcard2", filter1); + + // This application is allowed to connect to both test:service and + // test:service2, and may see any interface exposed by test:service but only + // the Safe interface exposed by test:service2. + AllowedInterfaces interfaces2; + interfaces2.insert("*"); + CapabilityFilter filter2; + filter2["test:service"] = interfaces2; + AllowedInterfaces interfaces3; + interfaces3.insert(Safe::Name_); + filter2["test:service2"] = interfaces3; + RunApplication("test:wildcard3", filter2); + + CapabilityFilterTest::RunTest(); + } + + private: + // Overridden from CapabilityFilterTest: + void SetUp() override { + CapabilityFilterTest::SetUp(); + + std::set<std::string> expectations; + expectations.insert("E test:wildcard test:service mojo::shell::Safe"); + expectations.insert("E test:wildcard test:service mojo::shell::Unsafe"); + expectations.insert("E test:wildcard test:service2 mojo::shell::Safe"); + expectations.insert("E test:wildcard test:service2 mojo::shell::Unsafe"); + expectations.insert("C test:blocked test:service"); + expectations.insert("C test:blocked test:service2"); + expectations.insert("B test:wildcard2 test:service mojo::shell::Safe"); + expectations.insert("B test:wildcard2 test:service mojo::shell::Unsafe"); + expectations.insert("B test:wildcard2 test:service2 mojo::shell::Safe"); + expectations.insert("B test:wildcard2 test:service2 mojo::shell::Unsafe"); + expectations.insert("E test:wildcard3 test:service mojo::shell::Safe"); + expectations.insert("E test:wildcard3 test:service mojo::shell::Unsafe"); + expectations.insert("E test:wildcard3 test:service2 mojo::shell::Safe"); + expectations.insert("B test:wildcard3 test:service2 mojo::shell::Unsafe"); + InitValidator(expectations); + } + + DISALLOW_COPY_AND_ASSIGN(CapabilityFilter_WildcardsTest); +}; + +TEST_F(CapabilityFilter_WildcardsTest, Application) { + CreateLoader<TestApplication>("test:wildcard"); + CreateLoader<TestApplication>("test:blocked"); + CreateLoader<TestApplication>("test:wildcard2"); + CreateLoader<TestApplication>("test:wildcard3"); + RunTest(); } -TEST_F(CapabilityFilterTest, Wildcards) { - std::set<std::string> expectations; - expectations.insert("E test:wildcard test:service mojo::shell::Safe"); - expectations.insert("E test:wildcard test:service mojo::shell::Unsafe"); - expectations.insert("C test:blocked test:service"); - expectations.insert("B test:wildcard2 test:service mojo::shell::Safe"); - expectations.insert("B test:wildcard2 test:service mojo::shell::Unsafe"); - expectations.insert("B test:wildcard2 test:service2 mojo::shell::Safe"); - expectations.insert("B test:wildcard2 test:service2 mojo::shell::Unsafe"); - expectations.insert("E test:wildcard3 test:service mojo::shell::Safe"); - expectations.insert("E test:wildcard3 test:service mojo::shell::Unsafe"); - expectations.insert("E test:wildcard3 test:service2 mojo::shell::Safe"); - expectations.insert("B test:wildcard3 test:service2 mojo::shell::Unsafe"); - - ConnectionValidator validator(expectations, loop()); - application_manager()->SetLoaderForURL( - make_scoped_ptr(new TestApplication(&validator, false)), - GURL("test:wildcard")); - application_manager()->SetLoaderForURL( - make_scoped_ptr(new TestApplication(&validator, false)), - GURL("test:blocked")); - application_manager()->SetLoaderForURL( - make_scoped_ptr(new TestApplication(&validator, true)), - GURL("test:wildcard2")); - application_manager()->SetLoaderForURL( - make_scoped_ptr(new TestApplication(&validator, true)), - GURL("test:wildcard3")); - application_manager()->SetLoaderForURL( - make_scoped_ptr(new ServiceApplication), GURL("test:service")); - application_manager()->SetLoaderForURL( - make_scoped_ptr(new ServiceApplication), GURL("test:service2")); - - // This application is allowed to connect to any application because of a - // wildcard rule, and any interface exposed because of a wildcard rule in - // the interface array. - CapabilityFilterPtr filter1(CapabilityFilter::New()); - Array<String> interfaces(Array<String>::New(1)); - interfaces[0] = "*"; - filter1->filter.insert("*", interfaces.Pass()); - RunApplication("test:wildcard", filter1.Pass()); - - // This application is allowed to connect to no other applications because of - // an empty capability filter. - RunApplication("test:blocked", CapabilityFilter::New()); - - // This application is allowed to connect to any application because of a - // wildcard rule but may not connect to any interfaces because of an empty - // interface array. - CapabilityFilterPtr filter2(CapabilityFilter::New()); - filter2->filter.insert("*", Array<String>::New(0)); - RunApplication("test:wildcard2", filter2.Pass()); - - // This application is allowed to connect to both test:service and - // test:service2, and may see any interface exposed by test:service but only - // the Safe interface exposed by test:service2. - CapabilityFilterPtr filter3(CapabilityFilter::New()); - Array<String> interfaces1(Array<String>::New(1)); - interfaces1[0] = "*"; - filter3->filter.insert("test:service", interfaces1.Pass()); - Array<String> interfaces2(Array<String>::New(1)); - interfaces2[0] = String::From(std::string(Safe::Name_)); - filter3->filter.insert("test:service2", interfaces2.Pass()); - RunApplication("test:wildcard3", filter3.Pass()); - - loop()->Run(); - - EXPECT_TRUE(validator.expectations_met()); +TEST_F(CapabilityFilter_WildcardsTest, ContentHandler) { + RunContentHandlerTest(); } } // namespace diff --git a/mojo/shell/capability_filter_unittest.mojom b/mojo/shell/capability_filter_unittest.mojom index 64ea598..6b2d3764 100644 --- a/mojo/shell/capability_filter_unittest.mojom +++ b/mojo/shell/capability_filter_unittest.mojom @@ -11,11 +11,12 @@ module mojo.shell; interface Safe { }; interface Unsafe { }; -// Implemented by a test application to allow service applications to inform it -// of services/connections blocked. -interface Client { +// Implemented by a service that records services exposed to an application and +// connection errors to a target application. +interface Validator { AddServiceCalled(string app_url, string service_url, string name, bool blocked); + ConnectionClosed(string from_url, string to_url); }; diff --git a/mojo/shell/content_handler_connection.cc b/mojo/shell/content_handler_connection.cc index c89b639..dd3c5cb 100644 --- a/mojo/shell/content_handler_connection.cc +++ b/mojo/shell/content_handler_connection.cc @@ -10,10 +10,12 @@ namespace mojo { namespace shell { ContentHandlerConnection::ContentHandlerConnection( + ApplicationInstance* originator, ApplicationManager* manager, const GURL& content_handler_url, const GURL& requestor_url, - const std::string& qualifier) + const std::string& qualifier, + const CapabilityFilter& filter) : manager_(manager), content_handler_url_(content_handler_url), content_handler_qualifier_(qualifier), @@ -21,11 +23,9 @@ ContentHandlerConnection::ContentHandlerConnection( ServiceProviderPtr services; mojo::URLRequestPtr request(mojo::URLRequest::New()); request->url = mojo::String::From(content_handler_url.spec()); - // TODO(beng): Need to figure out how to deal with originator and - // CapabilityFilter here. manager->ConnectToApplication( - nullptr, request.Pass(), qualifier, requestor_url, GetProxy(&services), - nullptr, nullptr, base::Closure()); + originator, request.Pass(), qualifier, requestor_url, GetProxy(&services), + nullptr, filter, base::Closure()); MessagePipe pipe; content_handler_.Bind( InterfacePtrInfo<ContentHandler>(pipe.handle0.Pass(), 0u)); diff --git a/mojo/shell/content_handler_connection.h b/mojo/shell/content_handler_connection.h index 749e6b4..1995265 100644 --- a/mojo/shell/content_handler_connection.h +++ b/mojo/shell/content_handler_connection.h @@ -8,11 +8,13 @@ #include <string> #include "mojo/application/public/interfaces/content_handler.mojom.h" +#include "mojo/shell/capability_filter.h" #include "url/gurl.h" namespace mojo { namespace shell { +class ApplicationInstance; class ApplicationManager; // A ContentHandlerConnection is responsible for creating and maintaining a @@ -23,12 +25,14 @@ class ApplicationManager; // destruction. class ContentHandlerConnection { public: - ContentHandlerConnection(ApplicationManager* manager, + ContentHandlerConnection(ApplicationInstance* originator, + ApplicationManager* manager, const GURL& content_handler_url, const GURL& requestor_url, - const std::string& qualifier); + const std::string& qualifier, + const CapabilityFilter& filter); - // Closes the connection and destorys |this| object. + // Closes the connection and destroys |this| object. void CloseConnection(); ContentHandler* content_handler() { return content_handler_.get(); } |