|  | // Copyright (c) 2012 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 "webkit/fileapi/isolated_context.h" | 
|  |  | 
|  | #include <string> | 
|  |  | 
|  | #include "base/basictypes.h" | 
|  | #include "base/logging.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "webkit/fileapi/isolated_context.h" | 
|  |  | 
|  | #define FPL(x) FILE_PATH_LITERAL(x) | 
|  |  | 
|  | #if defined(FILE_PATH_USES_DRIVE_LETTERS) | 
|  | #define DRIVE FPL("C:") | 
|  | #else | 
|  | #define DRIVE | 
|  | #endif | 
|  |  | 
|  | namespace fileapi { | 
|  |  | 
|  | typedef IsolatedContext::FileInfo FileInfo; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | const FilePath kTestPaths[] = { | 
|  | FilePath(DRIVE FPL("/a/b.txt")), | 
|  | FilePath(DRIVE FPL("/c/d/e")), | 
|  | FilePath(DRIVE FPL("/h/")), | 
|  | FilePath(DRIVE FPL("/")), | 
|  | #if defined(FILE_PATH_USES_WIN_SEPARATORS) | 
|  | FilePath(DRIVE FPL("\\foo\\bar")), | 
|  | FilePath(DRIVE FPL("\\")), | 
|  | #endif | 
|  | // For duplicated base name test. | 
|  | FilePath(DRIVE FPL("/")), | 
|  | FilePath(DRIVE FPL("/f/e")), | 
|  | FilePath(DRIVE FPL("/f/b.txt")), | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | class IsolatedContextTest : public testing::Test { | 
|  | public: | 
|  | IsolatedContextTest() { | 
|  | for (size_t i = 0; i < arraysize(kTestPaths); ++i) | 
|  | fileset_.insert(kTestPaths[i].NormalizePathSeparators()); | 
|  | } | 
|  |  | 
|  | void SetUp() { | 
|  | IsolatedContext::FileInfoSet files; | 
|  | for (size_t i = 0; i < arraysize(kTestPaths); ++i) { | 
|  | std::string name; | 
|  | ASSERT_TRUE( | 
|  | files.AddPath(kTestPaths[i].NormalizePathSeparators(), &name)); | 
|  | names_.push_back(name); | 
|  | } | 
|  | id_ = IsolatedContext::GetInstance()->RegisterDraggedFileSystem(files); | 
|  | IsolatedContext::GetInstance()->AddReference(id_); | 
|  | ASSERT_FALSE(id_.empty()); | 
|  | } | 
|  |  | 
|  | void TearDown() { | 
|  | IsolatedContext::GetInstance()->RemoveReference(id_); | 
|  | } | 
|  |  | 
|  | IsolatedContext* isolated_context() const { | 
|  | return IsolatedContext::GetInstance(); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | std::string id_; | 
|  | std::multiset<FilePath> fileset_; | 
|  | std::vector<std::string> names_; | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(IsolatedContextTest); | 
|  | }; | 
|  |  | 
|  | TEST_F(IsolatedContextTest, RegisterAndRevokeTest) { | 
|  | // See if the returned top-level entries match with what we registered. | 
|  | std::vector<FileInfo> toplevels; | 
|  | ASSERT_TRUE(isolated_context()->GetDraggedFileInfo(id_, &toplevels)); | 
|  | ASSERT_EQ(fileset_.size(), toplevels.size()); | 
|  | for (size_t i = 0; i < toplevels.size(); ++i) { | 
|  | ASSERT_TRUE(fileset_.find(toplevels[i].path) != fileset_.end()); | 
|  | } | 
|  |  | 
|  | // See if the name of each registered kTestPaths (that is what we | 
|  | // register in SetUp() by RegisterDraggedFileSystem) is properly cracked as | 
|  | // a valid virtual path in the isolated filesystem. | 
|  | for (size_t i = 0; i < arraysize(kTestPaths); ++i) { | 
|  | FilePath virtual_path = isolated_context()->CreateVirtualRootPath(id_) | 
|  | .AppendASCII(names_[i]); | 
|  | std::string cracked_id; | 
|  | FilePath cracked_path; | 
|  | FileSystemType cracked_type; | 
|  | ASSERT_TRUE(isolated_context()->CrackIsolatedPath( | 
|  | virtual_path, &cracked_id, &cracked_type, &cracked_path)); | 
|  | ASSERT_EQ(kTestPaths[i].NormalizePathSeparators().value(), | 
|  | cracked_path.value()); | 
|  | ASSERT_EQ(id_, cracked_id); | 
|  | ASSERT_EQ(kFileSystemTypeDragged, cracked_type); | 
|  | } | 
|  |  | 
|  | // Make sure GetRegisteredPath returns false for id_ since it is | 
|  | // registered for dragged files. | 
|  | FilePath path; | 
|  | ASSERT_FALSE(isolated_context()->GetRegisteredPath(id_, &path)); | 
|  |  | 
|  | // Deref the current one and registering a new one. | 
|  | isolated_context()->RemoveReference(id_); | 
|  |  | 
|  | std::string id2 = isolated_context()->RegisterFileSystemForPath( | 
|  | kFileSystemTypeNativeLocal, FilePath(DRIVE FPL("/foo")), NULL); | 
|  |  | 
|  | // Make sure the GetDraggedFileInfo returns false for both ones. | 
|  | ASSERT_FALSE(isolated_context()->GetDraggedFileInfo(id2, &toplevels)); | 
|  | ASSERT_FALSE(isolated_context()->GetDraggedFileInfo(id_, &toplevels)); | 
|  |  | 
|  | // Make sure the GetRegisteredPath returns true only for the new one. | 
|  | ASSERT_FALSE(isolated_context()->GetRegisteredPath(id_, &path)); | 
|  | ASSERT_TRUE(isolated_context()->GetRegisteredPath(id2, &path)); | 
|  |  | 
|  | // Try registering three more file systems for the same path as id2. | 
|  | std::string id3 = isolated_context()->RegisterFileSystemForPath( | 
|  | kFileSystemTypeNativeLocal, path, NULL); | 
|  | std::string id4 = isolated_context()->RegisterFileSystemForPath( | 
|  | kFileSystemTypeNativeLocal, path, NULL); | 
|  | std::string id5 = isolated_context()->RegisterFileSystemForPath( | 
|  | kFileSystemTypeNativeLocal, path, NULL); | 
|  |  | 
|  | // Remove file system for id4. | 
|  | isolated_context()->AddReference(id4); | 
|  | isolated_context()->RemoveReference(id4); | 
|  |  | 
|  | // Only id4 should become invalid now. | 
|  | ASSERT_TRUE(isolated_context()->GetRegisteredPath(id2, &path)); | 
|  | ASSERT_TRUE(isolated_context()->GetRegisteredPath(id3, &path)); | 
|  | ASSERT_FALSE(isolated_context()->GetRegisteredPath(id4, &path)); | 
|  | ASSERT_TRUE(isolated_context()->GetRegisteredPath(id5, &path)); | 
|  |  | 
|  | // Revoke file system id5, after adding multiple references. | 
|  | isolated_context()->AddReference(id5); | 
|  | isolated_context()->AddReference(id5); | 
|  | isolated_context()->AddReference(id5); | 
|  | isolated_context()->RevokeFileSystem(id5); | 
|  |  | 
|  | // No matter how many references we add id5 must be invalid now. | 
|  | ASSERT_TRUE(isolated_context()->GetRegisteredPath(id2, &path)); | 
|  | ASSERT_TRUE(isolated_context()->GetRegisteredPath(id3, &path)); | 
|  | ASSERT_FALSE(isolated_context()->GetRegisteredPath(id4, &path)); | 
|  | ASSERT_FALSE(isolated_context()->GetRegisteredPath(id5, &path)); | 
|  |  | 
|  | // Revoke the file systems by path. | 
|  | isolated_context()->RevokeFileSystemByPath(path); | 
|  |  | 
|  | // Now all the file systems associated to the path must be invalid. | 
|  | ASSERT_FALSE(isolated_context()->GetRegisteredPath(id2, &path)); | 
|  | ASSERT_FALSE(isolated_context()->GetRegisteredPath(id3, &path)); | 
|  | ASSERT_FALSE(isolated_context()->GetRegisteredPath(id4, &path)); | 
|  | ASSERT_FALSE(isolated_context()->GetRegisteredPath(id5, &path)); | 
|  | } | 
|  |  | 
|  | TEST_F(IsolatedContextTest, CrackWithRelativePaths) { | 
|  | const struct { | 
|  | FilePath::StringType path; | 
|  | bool valid; | 
|  | } relatives[] = { | 
|  | { FPL("foo"), true }, | 
|  | { FPL("foo/bar"), true }, | 
|  | { FPL(".."), false }, | 
|  | { FPL("foo/.."), false }, | 
|  | { FPL("foo/../bar"), false }, | 
|  | #if defined(FILE_PATH_USES_WIN_SEPARATORS) | 
|  | # define SHOULD_FAIL_WITH_WIN_SEPARATORS false | 
|  | #else | 
|  | # define SHOULD_FAIL_WITH_WIN_SEPARATORS true | 
|  | #endif | 
|  | { FPL("foo\\..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS }, | 
|  | { FPL("foo/..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS }, | 
|  | }; | 
|  |  | 
|  | for (size_t i = 0; i < arraysize(kTestPaths); ++i) { | 
|  | for (size_t j = 0; j < ARRAYSIZE_UNSAFE(relatives); ++j) { | 
|  | SCOPED_TRACE(testing::Message() << "Testing " | 
|  | << kTestPaths[i].value() << " " << relatives[j].path); | 
|  | FilePath virtual_path = isolated_context()->CreateVirtualRootPath(id_) | 
|  | .AppendASCII(names_[i]).Append(relatives[j].path); | 
|  | std::string cracked_id; | 
|  | FilePath cracked_path; | 
|  | FileSystemType cracked_type; | 
|  | if (!relatives[j].valid) { | 
|  | ASSERT_FALSE(isolated_context()->CrackIsolatedPath( | 
|  | virtual_path, &cracked_id, &cracked_type, &cracked_path)); | 
|  | continue; | 
|  | } | 
|  | ASSERT_TRUE(isolated_context()->CrackIsolatedPath( | 
|  | virtual_path, &cracked_id, &cracked_type, &cracked_path)); | 
|  | ASSERT_EQ(kTestPaths[i].Append(relatives[j].path) | 
|  | .NormalizePathSeparators().value(), | 
|  | cracked_path.value()); | 
|  | ASSERT_EQ(id_, cracked_id); | 
|  | ASSERT_EQ(kFileSystemTypeDragged, cracked_type); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(IsolatedContextTest, TestWithVirtualRoot) { | 
|  | std::string cracked_id; | 
|  | FilePath cracked_path; | 
|  |  | 
|  | // Trying to crack virtual root "/" returns true but with empty cracked path | 
|  | // as "/" of the isolated filesystem is a pure virtual directory | 
|  | // that has no corresponding platform directory. | 
|  | FilePath virtual_path = isolated_context()->CreateVirtualRootPath(id_); | 
|  | ASSERT_TRUE(isolated_context()->CrackIsolatedPath( | 
|  | virtual_path, &cracked_id, NULL, &cracked_path)); | 
|  | ASSERT_EQ(FPL(""), cracked_path.value()); | 
|  | ASSERT_EQ(id_, cracked_id); | 
|  |  | 
|  | // Trying to crack "/foo" should fail (because "foo" is not the one | 
|  | // included in the kTestPaths). | 
|  | virtual_path = isolated_context()->CreateVirtualRootPath( | 
|  | id_).AppendASCII("foo"); | 
|  | ASSERT_FALSE(isolated_context()->CrackIsolatedPath( | 
|  | virtual_path, &cracked_id, NULL, &cracked_path)); | 
|  | } | 
|  |  | 
|  | }  // namespace fileapi |