summaryrefslogtreecommitdiffstats
path: root/mojo/shell
diff options
context:
space:
mode:
authorben <ben@chromium.org>2015-07-28 16:50:12 -0700
committerCommit bot <commit-bot@chromium.org>2015-07-28 23:50:53 +0000
commit79b0408c7e702c6b5c035ea3cb669cb4c97036b5 (patch)
tree9f5c1a7bd92ce3c6a10eafd191f726e390d3bbc6 /mojo/shell
parent67d3786d1147e9e684b870ff47e92749ceb3095c (diff)
downloadchromium_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.gn2
-rw-r--r--mojo/shell/application_instance.cc19
-rw-r--r--mojo/shell/application_instance.h36
-rw-r--r--mojo/shell/application_manager.cc70
-rw-r--r--mojo/shell/application_manager.h30
-rw-r--r--mojo/shell/application_manager_unittest.cc6
-rw-r--r--mojo/shell/capability_filter.cc19
-rw-r--r--mojo/shell/capability_filter.h57
-rw-r--r--mojo/shell/capability_filter_unittest.cc563
-rw-r--r--mojo/shell/capability_filter_unittest.mojom7
-rw-r--r--mojo/shell/content_handler_connection.cc10
-rw-r--r--mojo/shell/content_handler_connection.h10
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(); }