summaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorsky <sky@chromium.org>2015-05-01 16:21:51 -0700
committerCommit bot <commit-bot@chromium.org>2015-05-01 23:23:15 +0000
commit6de67f80026697580ed4cefa11a72193243bd4a0 (patch)
treea1faddfa0cc1bf907c2b381479a336f9482bbeb5 /components
parente732780029f2d752aed0fe14a788ef4ac3510308 (diff)
downloadchromium_src-6de67f80026697580ed4cefa11a72193243bd4a0.zip
chromium_src-6de67f80026697580ed4cefa11a72193243bd4a0.tar.gz
chromium_src-6de67f80026697580ed4cefa11a72193243bd4a0.tar.bz2
Adds resource_provider::ResourceProvider
It's used to fetch resources for mojo apps. R=ben@chromium.org Review URL: https://codereview.chromium.org/1108403008 Cr-Commit-Position: refs/heads/master@{#328014}
Diffstat (limited to 'components')
-rw-r--r--components/resource_provider/BUILD.gn83
-rw-r--r--components/resource_provider/DEPS7
-rw-r--r--components/resource_provider/OWNERS1
-rw-r--r--components/resource_provider/file_utils.cc66
-rw-r--r--components/resource_provider/file_utils.h29
-rw-r--r--components/resource_provider/file_utils_unittest.cc80
-rw-r--r--components/resource_provider/main.cc13
-rw-r--r--components/resource_provider/public/interfaces/BUILD.gn14
-rw-r--r--components/resource_provider/public/interfaces/resource_provider.mojom18
-rw-r--r--components/resource_provider/resource_provider_app.cc45
-rw-r--r--components/resource_provider/resource_provider_app.h46
-rw-r--r--components/resource_provider/resource_provider_apptest.cc146
-rw-r--r--components/resource_provider/resource_provider_impl.cc60
-rw-r--r--components/resource_provider/resource_provider_impl.h31
-rw-r--r--components/test/data/resource_provider/dir/sample21
-rw-r--r--components/test/data/resource_provider/sample1
16 files changed, 641 insertions, 0 deletions
diff --git a/components/resource_provider/BUILD.gn b/components/resource_provider/BUILD.gn
new file mode 100644
index 0000000..c245d5c
--- /dev/null
+++ b/components/resource_provider/BUILD.gn
@@ -0,0 +1,83 @@
+# 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.
+
+import("//testing/test.gni")
+import("//mojo/mojo_application_package.gni")
+
+mojo_native_application("resource_provider") {
+ sources = [
+ "main.cc",
+ "resource_provider_app.cc",
+ "resource_provider_app.h",
+ ]
+
+ deps = [
+ ":lib",
+ "//base",
+ "//components/resource_provider/public/interfaces",
+ "//mojo/application",
+ "//mojo/environment:chromium",
+ "//url",
+ ]
+}
+
+source_set("lib") {
+ sources = [
+ "file_utils.cc",
+ "file_utils.h",
+ "resource_provider_impl.cc",
+ "resource_provider_impl.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/resource_provider/public/interfaces",
+ "//mojo/common:common_base",
+ "//mojo/platform_handle",
+ "//url",
+ ]
+}
+
+test("tests") {
+ output_name = "resource_provider_unittests"
+ sources = [
+ "file_utils_unittest.cc",
+ ]
+
+ deps = [
+ ":lib",
+ "//base",
+ "//base/test:test_config",
+ "//components/resource_provider/public/interfaces",
+ "//mojo/environment:chromium",
+ "//testing/gtest",
+ "//third_party/mojo/src/mojo/edk/test:run_all_unittests",
+ "//url",
+ ]
+}
+
+mojo_application_package("apptests") {
+ output_name = "resource_provider_apptests"
+ testonly = true
+
+ sources = [
+ "resource_provider_apptest.cc",
+ ]
+
+ resources = [
+ "//components/test/data/resource_provider/sample",
+ "//components/test/data/resource_provider/dir",
+ ]
+
+ deps = [
+ "//base",
+ "//base/test:test_config",
+ "//components/resource_provider/public/interfaces",
+ "//mojo/application",
+ "//mojo/application:test_support",
+ "//mojo/common",
+ "//mojo/platform_handle",
+ "//third_party/mojo/src/mojo/public/cpp/bindings:bindings",
+ ]
+}
diff --git a/components/resource_provider/DEPS b/components/resource_provider/DEPS
new file mode 100644
index 0000000..9498e27
--- /dev/null
+++ b/components/resource_provider/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+ "+mojo/application",
+ "+mojo/common",
+ "+mojo/converters",
+ "+mojo/platform_handle",
+ "+third_party/mojo/src/mojo/public",
+]
diff --git a/components/resource_provider/OWNERS b/components/resource_provider/OWNERS
new file mode 100644
index 0000000..90b3e80
--- /dev/null
+++ b/components/resource_provider/OWNERS
@@ -0,0 +1 @@
+sky@chromium.org
diff --git a/components/resource_provider/file_utils.cc b/components/resource_provider/file_utils.cc
new file mode 100644
index 0000000..468d27e
--- /dev/null
+++ b/components/resource_provider/file_utils.cc
@@ -0,0 +1,66 @@
+// 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 "components/resource_provider/file_utils.h"
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "url/gurl.h"
+
+namespace resource_provider {
+namespace {
+
+bool IsPathNameValid(const std::string& name) {
+ if (name.empty() || name == "." || name == "..")
+ return false;
+
+ for (auto c : name) {
+ if (!IsAsciiAlpha(c) && !IsAsciiDigit(c) && c != '_' && c != '.')
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+base::FilePath GetPathForApplicationUrl(const GURL& application_url) {
+ if (application_url.scheme() != "mojo")
+ return base::FilePath();
+
+ std::string path = application_url.path();
+ base::TrimString(path, "/", &path);
+
+ if (!IsPathNameValid(path))
+ return base::FilePath();
+
+ base::FilePath base_path;
+ PathService::Get(base::DIR_EXE, &base_path);
+ return base_path.AppendASCII(path).AppendASCII("resources");
+}
+
+base::FilePath GetPathForResourceNamed(const base::FilePath& app_path,
+ const std::string& resource_path) {
+ CHECK(!app_path.empty());
+
+ if (resource_path.empty() || resource_path[0] == '/' ||
+ resource_path.back() == '/' ||
+ resource_path.find("//") != std::string::npos)
+ return base::FilePath();
+
+ std::vector<std::string> path_components;
+ Tokenize(resource_path, "/", &path_components);
+ if (path_components.empty())
+ return base::FilePath();
+
+ base::FilePath result(app_path);
+ for (const auto& path_component : path_components) {
+ if (!IsPathNameValid(path_component))
+ return base::FilePath();
+ result = result.AppendASCII(path_component);
+ }
+ return result;
+}
+
+} // namespace resource_provider
diff --git a/components/resource_provider/file_utils.h b/components/resource_provider/file_utils.h
new file mode 100644
index 0000000..7ddf947
--- /dev/null
+++ b/components/resource_provider/file_utils.h
@@ -0,0 +1,29 @@
+// 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 COMPONENTS_RESOURCE_PROVIDER_FILE_UTILS_H_
+#define COMPONENTS_RESOURCE_PROVIDER_FILE_UTILS_H_
+
+#include <string>
+
+class GURL;
+
+namespace base {
+class FilePath;
+}
+
+namespace resource_provider {
+
+// Returns the path to the resources for |application_url|, or an empty
+// path if |application_url| is not valid.
+base::FilePath GetPathForApplicationUrl(const GURL& application_url);
+
+// Returns the path to the specified resource. |app_path| was previously
+// obtained by way of GetPathForApplicationUrl().
+base::FilePath GetPathForResourceNamed(const base::FilePath& app_path,
+ const std::string& resource_path);
+
+} // namespace resource_provider
+
+#endif // COMPONENTS_RESOURCE_PROVIDER_FILE_UTILS_H_
diff --git a/components/resource_provider/file_utils_unittest.cc b/components/resource_provider/file_utils_unittest.cc
new file mode 100644
index 0000000..96de984
--- /dev/null
+++ b/components/resource_provider/file_utils_unittest.cc
@@ -0,0 +1,80 @@
+// 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 "components/resource_provider/file_utils.h"
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace resource_provider {
+
+// Assertions for invalid app paths.
+TEST(FileUtilsTest, InvalidAppPath) {
+ struct TestCase {
+ std::string url;
+ };
+ struct TestCase invalid_cases[]{
+ {"http://foo"}, // Must start with 'mojo:'.
+ {"mojo://."}, // Don't allow '.'.
+ {"mojo://.."}, // Don't allow '..'.
+ {"mojo://foo/."}, // Don't allow '.'.
+ {"mojo://bar/.."}, // Don't allow '..'.
+ };
+
+ for (size_t i = 0; i < arraysize(invalid_cases); ++i) {
+ const GURL url(invalid_cases[i].url);
+ base::FilePath resulting_path(GetPathForApplicationUrl(url));
+ EXPECT_TRUE(resulting_path.empty()) << "i=" << i
+ << " input=" << invalid_cases[i].url
+ << " result=" << resulting_path.value();
+ }
+}
+
+// Assertions for invalid app paths.
+TEST(FileUtilsTest, InvalidResourcePath) {
+ struct TestCase {
+ std::string path;
+ };
+ struct TestCase invalid_cases[]{
+ {"."},
+ {".."},
+ {"foo/."},
+ {"bar/.."},
+ {"foo/./bar"},
+ {"bar/../baz"},
+ {"bar/baz/"},
+ {"bar//baz/"},
+ };
+
+ const base::FilePath app_path(GetPathForApplicationUrl(GURL("mojo:test")));
+ ASSERT_FALSE(app_path.empty());
+
+ for (size_t i = 0; i < arraysize(invalid_cases); ++i) {
+ base::FilePath resulting_path(
+ GetPathForResourceNamed(app_path, invalid_cases[i].path));
+ EXPECT_TRUE(resulting_path.empty()) << i
+ << " input=" << invalid_cases[i].path
+ << " result=" << resulting_path.value();
+ }
+}
+
+TEST(FileUtilsTest, ValidPaths) {
+ const base::FilePath app_path(GetPathForApplicationUrl(GURL("mojo:test")));
+ ASSERT_FALSE(app_path.empty());
+
+ // Trivial single path element.
+ const base::FilePath trivial_path(
+ GetPathForResourceNamed(app_path, "single"));
+ EXPECT_EQ(app_path.AppendASCII("single").value(), trivial_path.value());
+
+ // Two path elements.
+ const base::FilePath two_paths(GetPathForResourceNamed(app_path, "a/b"));
+ EXPECT_EQ(app_path.AppendASCII("a").AppendASCII("b").value(),
+ two_paths.value());
+}
+
+} // namespace resource_provider
diff --git a/components/resource_provider/main.cc b/components/resource_provider/main.cc
new file mode 100644
index 0000000..413a21b
--- /dev/null
+++ b/components/resource_provider/main.cc
@@ -0,0 +1,13 @@
+// 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 "components/resource_provider/resource_provider_app.h"
+#include "mojo/application/application_runner_chromium.h"
+#include "third_party/mojo/src/mojo/public/c/system/main.h"
+
+MojoResult MojoMain(MojoHandle shell_handle) {
+ mojo::ApplicationRunnerChromium runner(
+ new resource_provider::ResourceProviderApp);
+ return runner.Run(shell_handle);
+}
diff --git a/components/resource_provider/public/interfaces/BUILD.gn b/components/resource_provider/public/interfaces/BUILD.gn
new file mode 100644
index 0000000..7bf8e85
--- /dev/null
+++ b/components/resource_provider/public/interfaces/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2014 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.
+
+import("//build/module_args/mojo.gni")
+import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+ sources = [
+ "resource_provider.mojom",
+ ]
+
+ mojo_sdk_deps = [ "mojo/public/interfaces/application" ]
+}
diff --git a/components/resource_provider/public/interfaces/resource_provider.mojom b/components/resource_provider/public/interfaces/resource_provider.mojom
new file mode 100644
index 0000000..15af0d1
--- /dev/null
+++ b/components/resource_provider/public/interfaces/resource_provider.mojom
@@ -0,0 +1,18 @@
+// 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.
+
+module resource_provider;
+
+// An interface through which a mojo application obtains resources.
+interface ResourceProvider {
+ // Fetches the resources at the specified paths. The paths are relative to
+ // the resources directory of the application. Use "/" as the path separator.
+ // For example, the path "foo/bar" returns a platform handle to the file at
+ // the path foo/bar relative to the resources directory of the application
+ // requestion the resource.
+ //
+ // The result is an array of platform handles for each of the requested paths.
+ // TODO(sky): this should really be map<string,handle>, but that doesn't work.
+ GetResources(array<string> paths) => (array<handle> resource_handles);
+};
diff --git a/components/resource_provider/resource_provider_app.cc b/components/resource_provider/resource_provider_app.cc
new file mode 100644
index 0000000..1373d63
--- /dev/null
+++ b/components/resource_provider/resource_provider_app.cc
@@ -0,0 +1,45 @@
+// 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 "components/resource_provider/resource_provider_app.h"
+
+#include "components/resource_provider/file_utils.h"
+#include "components/resource_provider/resource_provider_impl.h"
+#include "third_party/mojo/src/mojo/public/cpp/application/application_connection.h"
+#include "url/gurl.h"
+
+namespace resource_provider {
+
+ResourceProviderApp::ResourceProviderApp() {
+}
+
+ResourceProviderApp::~ResourceProviderApp() {
+}
+
+void ResourceProviderApp::Initialize(mojo::ApplicationImpl* app) {
+}
+
+bool ResourceProviderApp::ConfigureIncomingConnection(
+ mojo::ApplicationConnection* connection) {
+ const base::FilePath app_path(
+ GetPathForApplicationUrl(GURL(connection->GetRemoteApplicationURL())));
+ if (app_path.empty())
+ return false; // The specified app has no resources.
+
+ connection->AddService<ResourceProvider>(this);
+ return true;
+}
+
+void ResourceProviderApp::Create(
+ mojo::ApplicationConnection* connection,
+ mojo::InterfaceRequest<ResourceProvider> request) {
+ const base::FilePath app_path(
+ GetPathForApplicationUrl(GURL(connection->GetRemoteApplicationURL())));
+ // We validated path at ConfigureIncomingConnection() time, so it should still
+ // be valid.
+ CHECK(!app_path.empty());
+ bindings_.AddBinding(new ResourceProviderImpl(app_path), request.Pass());
+}
+
+} // namespace resource_provider
diff --git a/components/resource_provider/resource_provider_app.h b/components/resource_provider/resource_provider_app.h
new file mode 100644
index 0000000..55bb940
--- /dev/null
+++ b/components/resource_provider/resource_provider_app.h
@@ -0,0 +1,46 @@
+// 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 COMPONENTS_RESOURCE_PROVIDER_RESOURCE_PROVIDER_APP_H_
+#define COMPONENTS_RESOURCE_PROVIDER_RESOURCE_PROVIDER_APP_H_
+
+#include <map>
+
+#include "components/resource_provider/public/interfaces/resource_provider.mojom.h"
+#include "mojo/common/weak_binding_set.h"
+#include "third_party/mojo/src/mojo/public/cpp/application/application_delegate.h"
+#include "third_party/mojo/src/mojo/public/cpp/application/interface_factory.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
+
+namespace mojo {
+class ApplicationImpl;
+}
+
+namespace resource_provider {
+
+class ResourceProviderApp : public mojo::ApplicationDelegate,
+ public mojo::InterfaceFactory<ResourceProvider> {
+ public:
+ ResourceProviderApp();
+ ~ResourceProviderApp() override;
+
+ private:
+ // ApplicationDelegate:
+ void Initialize(mojo::ApplicationImpl* app) override;
+ bool ConfigureIncomingConnection(
+ mojo::ApplicationConnection* connection) override;
+
+ // mojo::InterfaceFactory<ResourceProvider>:
+ void Create(mojo::ApplicationConnection* connection,
+ mojo::InterfaceRequest<ResourceProvider> request) override;
+
+ mojo::WeakBindingSet<ResourceProvider> bindings_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceProviderApp);
+};
+
+} // namespace resource_provider
+
+#endif // COMPONENTS_RESOURCE_PROVIDER_RESOURCE_PROVIDER_APP_H_
diff --git a/components/resource_provider/resource_provider_apptest.cc b/components/resource_provider/resource_provider_apptest.cc
new file mode 100644
index 0000000..2d10b6d
--- /dev/null
+++ b/components/resource_provider/resource_provider_apptest.cc
@@ -0,0 +1,146 @@
+// 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 <stdint.h>
+
+#include "base/bind.h"
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/files/file.h"
+#include "base/run_loop.h"
+#include "components/resource_provider/public/interfaces/resource_provider.mojom.h"
+#include "mojo/application/application_test_base_chromium.h"
+#include "mojo/common/common_type_converters.h"
+#include "mojo/platform_handle/platform_handle_functions.h"
+#include "third_party/mojo/src/mojo/public/cpp/application/application_delegate.h"
+#include "third_party/mojo/src/mojo/public/cpp/application/application_impl.h"
+#include "third_party/mojo/src/mojo/public/cpp/application/service_provider_impl.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/array.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/macros.h"
+
+namespace resource_provider {
+namespace {
+
+std::string ReadFile(base::File* file) {
+ const size_t kBufferSize = 1 << 16;
+ scoped_ptr<char[]> buffer(new char[kBufferSize]);
+ const int read = file->ReadAtCurrentPos(buffer.get(), kBufferSize);
+ if (read == -1)
+ return std::string();
+ return std::string(buffer.get(), read);
+}
+
+std::vector<std::string> VectorWithString(const std::string& contents) {
+ std::vector<std::string> result;
+ result.push_back(contents);
+ return result;
+}
+
+std::vector<std::string> VectorWithStrings(const std::string& contents1,
+ const std::string& contents2) {
+ std::vector<std::string> result;
+ result.push_back(contents1);
+ result.push_back(contents2);
+ return result;
+}
+
+// ResourceFetcher fetches resources from a ResourceProvider, storing the
+// results as well as running
+// a message loop until the resource has been obtained.
+class ResourceFetcher {
+ public:
+ using ResourceMap = std::map<std::string, std::string>;
+
+ explicit ResourceFetcher(ResourceProvider* provider)
+ : provider_(provider), waiting_count_(0u) {}
+ ~ResourceFetcher() {}
+
+ ResourceMap* resources() { return &resources_; }
+
+ void WaitForResults() {
+ ASSERT_NE(0u, waiting_count_);
+ run_loop_.Run();
+ }
+
+ void GetResources(const std::vector<std::string>& paths) {
+ waiting_count_++;
+ provider_->GetResources(mojo::Array<mojo::String>::From(paths),
+ base::Bind(&ResourceFetcher::OnGotResources,
+ base::Unretained(this), paths));
+ }
+
+ private:
+ // Callback when a resource has been fetched.
+ void OnGotResources(const std::vector<std::string>& paths,
+ mojo::Array<mojo::ScopedHandle> resources) {
+ ASSERT_FALSE(resources.is_null());
+ ASSERT_EQ(paths.size(), resources.size());
+ for (size_t i = 0; i < paths.size(); ++i) {
+ std::string contents;
+ if (resources[i].is_valid()) {
+ MojoPlatformHandle platform_handle;
+ ASSERT_EQ(MOJO_RESULT_OK,
+ MojoExtractPlatformHandle(resources[i].release().value(),
+ &platform_handle));
+ base::File file(platform_handle);
+ contents = ReadFile(&file);
+ }
+ resources_[paths[i]] = contents;
+ }
+
+ if (waiting_count_ > 0) {
+ waiting_count_--;
+ if (waiting_count_ == 0)
+ run_loop_.Quit();
+ }
+ }
+
+ ResourceProvider* provider_;
+ ResourceMap resources_;
+ // Number of resources we're waiting on.
+ size_t waiting_count_;
+ base::RunLoop run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceFetcher);
+};
+
+class ResourceProviderApplicationTest : public mojo::test::ApplicationTestBase {
+ public:
+ ResourceProviderApplicationTest() {}
+ ~ResourceProviderApplicationTest() override {}
+
+ protected:
+ // ApplicationTestBase:
+ void SetUp() override {
+ ApplicationTestBase::SetUp();
+ application_impl()->ConnectToService("mojo:resource_provider",
+ &resource_provider_);
+ }
+
+ ResourceProviderPtr resource_provider_;
+
+ private:
+ MOJO_DISALLOW_COPY_AND_ASSIGN(ResourceProviderApplicationTest);
+};
+
+TEST_F(ResourceProviderApplicationTest, FetchOneResource) {
+ ResourceFetcher fetcher(resource_provider_.get());
+ fetcher.GetResources(VectorWithString("sample"));
+ fetcher.WaitForResults();
+ ASSERT_TRUE(fetcher.resources()->count("sample") > 0u);
+ EXPECT_EQ("test data\n", (*fetcher.resources())["sample"]);
+}
+
+TEST_F(ResourceProviderApplicationTest, FetchTwoResources) {
+ ResourceFetcher fetcher(resource_provider_.get());
+ fetcher.GetResources(VectorWithStrings("sample", "dir/sample2"));
+ fetcher.WaitForResults();
+ ASSERT_TRUE(fetcher.resources()->count("sample") > 0u);
+ EXPECT_EQ("test data\n", (*fetcher.resources())["sample"]);
+
+ ASSERT_TRUE(fetcher.resources()->count("dir/sample2") > 0u);
+ EXPECT_EQ("xxyy\n", (*fetcher.resources())["dir/sample2"]);
+}
+
+} // namespace
+} // namespace resource_provider
diff --git a/components/resource_provider/resource_provider_impl.cc b/components/resource_provider/resource_provider_impl.cc
new file mode 100644
index 0000000..2c85b6d
--- /dev/null
+++ b/components/resource_provider/resource_provider_impl.cc
@@ -0,0 +1,60 @@
+// 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 "components/resource_provider/resource_provider_impl.h"
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "components/resource_provider/file_utils.h"
+#include "mojo/platform_handle/platform_handle_functions.h"
+
+using mojo::ScopedHandle;
+
+namespace resource_provider {
+namespace {
+
+ScopedHandle GetHandleForPath(const base::FilePath& path) {
+ if (path.empty())
+ return ScopedHandle();
+
+ ScopedHandle to_pass;
+ base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+ if (!file.IsValid())
+ return ScopedHandle();
+
+ MojoHandle mojo_handle;
+ if (MojoCreatePlatformHandleWrapper(file.TakePlatformFile(), &mojo_handle) !=
+ MOJO_RESULT_OK)
+ return ScopedHandle();
+
+ return ScopedHandle(mojo::Handle(mojo_handle)).Pass();
+}
+
+} // namespace
+
+ResourceProviderImpl::ResourceProviderImpl(
+ const base::FilePath& application_path)
+ : application_path_(application_path) {
+ CHECK(!application_path_.empty());
+}
+
+ResourceProviderImpl::~ResourceProviderImpl() {
+}
+
+void ResourceProviderImpl::GetResources(mojo::Array<mojo::String> paths,
+ const GetResourcesCallback& callback) {
+ mojo::Array<mojo::ScopedHandle> handles;
+ if (!paths.is_null()) {
+ handles.resize(paths.size());
+ for (size_t i = 0; i < paths.size(); ++i) {
+ handles[i] = GetHandleForPath(
+ GetPathForResourceNamed(application_path_, paths[i]));
+ }
+ }
+ callback.Run(handles.Pass());
+}
+
+} // namespace resource_provider
diff --git a/components/resource_provider/resource_provider_impl.h b/components/resource_provider/resource_provider_impl.h
new file mode 100644
index 0000000..eb2e22b
--- /dev/null
+++ b/components/resource_provider/resource_provider_impl.h
@@ -0,0 +1,31 @@
+// 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 COMPONENTS_RESOURCE_PROVIDER_RESOURCE_PROVIDER_IMPL_H_
+#define COMPONENTS_RESOURCE_PROVIDER_RESOURCE_PROVIDER_IMPL_H_
+
+#include "base/files/file_path.h"
+#include "components/resource_provider/public/interfaces/resource_provider.mojom.h"
+
+namespace resource_provider {
+
+// ResourceProvider implementation that loads resources in background threads.
+class ResourceProviderImpl : public resource_provider::ResourceProvider {
+ public:
+ explicit ResourceProviderImpl(const base::FilePath& application_path);
+ ~ResourceProviderImpl() override;
+
+ private:
+ // ResourceProvider:
+ void GetResources(mojo::Array<mojo::String> paths,
+ const GetResourcesCallback& callback) override;
+
+ const base::FilePath application_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceProviderImpl);
+};
+
+} // namespace resource_provider
+
+#endif // COMPONENTS_RESOURCE_PROVIDER_RESOURCE_PROVIDER_IMPL_H_
diff --git a/components/test/data/resource_provider/dir/sample2 b/components/test/data/resource_provider/dir/sample2
new file mode 100644
index 0000000..a6256e5
--- /dev/null
+++ b/components/test/data/resource_provider/dir/sample2
@@ -0,0 +1 @@
+xxyy
diff --git a/components/test/data/resource_provider/sample b/components/test/data/resource_provider/sample
new file mode 100644
index 0000000..082b346
--- /dev/null
+++ b/components/test/data/resource_provider/sample
@@ -0,0 +1 @@
+test data