• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <string>
6 
7 #include "base/basictypes.h"
8 #include "base/logging.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "webkit/browser/fileapi/file_system_url.h"
11 #include "webkit/browser/fileapi/isolated_context.h"
12 
13 #define FPL(x) FILE_PATH_LITERAL(x)
14 
15 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
16 #define DRIVE FPL("C:")
17 #else
18 #define DRIVE
19 #endif
20 
21 using fileapi::FileSystemMountOption;
22 using fileapi::FileSystemURL;
23 using fileapi::IsolatedContext;
24 using fileapi::kFileSystemTypeDragged;
25 using fileapi::kFileSystemTypeIsolated;
26 using fileapi::kFileSystemTypeNativeLocal;
27 
28 namespace content {
29 
30 typedef IsolatedContext::MountPointInfo FileInfo;
31 
32 namespace {
33 
34 const base::FilePath kTestPaths[] = {
35   base::FilePath(DRIVE FPL("/a/b.txt")),
36   base::FilePath(DRIVE FPL("/c/d/e")),
37   base::FilePath(DRIVE FPL("/h/")),
38   base::FilePath(DRIVE FPL("/")),
39 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
40   base::FilePath(DRIVE FPL("\\foo\\bar")),
41   base::FilePath(DRIVE FPL("\\")),
42 #endif
43   // For duplicated base name test.
44   base::FilePath(DRIVE FPL("/")),
45   base::FilePath(DRIVE FPL("/f/e")),
46   base::FilePath(DRIVE FPL("/f/b.txt")),
47 };
48 
49 }  // namespace
50 
51 class IsolatedContextTest : public testing::Test {
52  public:
IsolatedContextTest()53   IsolatedContextTest() {
54     for (size_t i = 0; i < arraysize(kTestPaths); ++i)
55       fileset_.insert(kTestPaths[i].NormalizePathSeparators());
56   }
57 
SetUp()58   virtual void SetUp() {
59     IsolatedContext::FileInfoSet files;
60     for (size_t i = 0; i < arraysize(kTestPaths); ++i) {
61       std::string name;
62       ASSERT_TRUE(
63           files.AddPath(kTestPaths[i].NormalizePathSeparators(), &name));
64       names_.push_back(name);
65     }
66     id_ = IsolatedContext::GetInstance()->RegisterDraggedFileSystem(files);
67     IsolatedContext::GetInstance()->AddReference(id_);
68     ASSERT_FALSE(id_.empty());
69   }
70 
TearDown()71   virtual void TearDown() {
72     IsolatedContext::GetInstance()->RemoveReference(id_);
73   }
74 
isolated_context() const75   IsolatedContext* isolated_context() const {
76     return IsolatedContext::GetInstance();
77   }
78 
79  protected:
80   std::string id_;
81   std::multiset<base::FilePath> fileset_;
82   std::vector<std::string> names_;
83 
84  private:
85   DISALLOW_COPY_AND_ASSIGN(IsolatedContextTest);
86 };
87 
TEST_F(IsolatedContextTest,RegisterAndRevokeTest)88 TEST_F(IsolatedContextTest, RegisterAndRevokeTest) {
89   // See if the returned top-level entries match with what we registered.
90   std::vector<FileInfo> toplevels;
91   ASSERT_TRUE(isolated_context()->GetDraggedFileInfo(id_, &toplevels));
92   ASSERT_EQ(fileset_.size(), toplevels.size());
93   for (size_t i = 0; i < toplevels.size(); ++i) {
94     ASSERT_TRUE(fileset_.find(toplevels[i].path) != fileset_.end());
95   }
96 
97   // See if the name of each registered kTestPaths (that is what we
98   // register in SetUp() by RegisterDraggedFileSystem) is properly cracked as
99   // a valid virtual path in the isolated filesystem.
100   for (size_t i = 0; i < arraysize(kTestPaths); ++i) {
101     base::FilePath virtual_path = isolated_context()->CreateVirtualRootPath(id_)
102         .AppendASCII(names_[i]);
103     std::string cracked_id;
104     base::FilePath cracked_path;
105     std::string cracked_inner_id;
106     fileapi::FileSystemType cracked_type;
107     FileSystemMountOption cracked_option;
108     ASSERT_TRUE(isolated_context()->CrackVirtualPath(
109         virtual_path, &cracked_id, &cracked_type, &cracked_inner_id,
110         &cracked_path, &cracked_option));
111     ASSERT_EQ(kTestPaths[i].NormalizePathSeparators().value(),
112               cracked_path.value());
113     ASSERT_EQ(id_, cracked_id);
114     ASSERT_EQ(kFileSystemTypeDragged, cracked_type);
115     EXPECT_TRUE(cracked_inner_id.empty());
116   }
117 
118   // Make sure GetRegisteredPath returns false for id_ since it is
119   // registered for dragged files.
120   base::FilePath path;
121   ASSERT_FALSE(isolated_context()->GetRegisteredPath(id_, &path));
122 
123   // Deref the current one and registering a new one.
124   isolated_context()->RemoveReference(id_);
125 
126   std::string id2 = isolated_context()->RegisterFileSystemForPath(
127       kFileSystemTypeNativeLocal, std::string(),
128       base::FilePath(DRIVE FPL("/foo")), NULL);
129 
130   // Make sure the GetDraggedFileInfo returns false for both ones.
131   ASSERT_FALSE(isolated_context()->GetDraggedFileInfo(id2, &toplevels));
132   ASSERT_FALSE(isolated_context()->GetDraggedFileInfo(id_, &toplevels));
133 
134   // Make sure the GetRegisteredPath returns true only for the new one.
135   ASSERT_FALSE(isolated_context()->GetRegisteredPath(id_, &path));
136   ASSERT_TRUE(isolated_context()->GetRegisteredPath(id2, &path));
137 
138   // Try registering three more file systems for the same path as id2.
139   std::string id3 = isolated_context()->RegisterFileSystemForPath(
140       kFileSystemTypeNativeLocal, std::string(), path, NULL);
141   std::string id4 = isolated_context()->RegisterFileSystemForPath(
142       kFileSystemTypeNativeLocal, std::string(), path, NULL);
143   std::string id5 = isolated_context()->RegisterFileSystemForPath(
144       kFileSystemTypeNativeLocal, std::string(), path, NULL);
145 
146   // Remove file system for id4.
147   isolated_context()->AddReference(id4);
148   isolated_context()->RemoveReference(id4);
149 
150   // Only id4 should become invalid now.
151   ASSERT_TRUE(isolated_context()->GetRegisteredPath(id2, &path));
152   ASSERT_TRUE(isolated_context()->GetRegisteredPath(id3, &path));
153   ASSERT_FALSE(isolated_context()->GetRegisteredPath(id4, &path));
154   ASSERT_TRUE(isolated_context()->GetRegisteredPath(id5, &path));
155 
156   // Revoke file system id5, after adding multiple references.
157   isolated_context()->AddReference(id5);
158   isolated_context()->AddReference(id5);
159   isolated_context()->AddReference(id5);
160   isolated_context()->RevokeFileSystem(id5);
161 
162   // No matter how many references we add id5 must be invalid now.
163   ASSERT_TRUE(isolated_context()->GetRegisteredPath(id2, &path));
164   ASSERT_TRUE(isolated_context()->GetRegisteredPath(id3, &path));
165   ASSERT_FALSE(isolated_context()->GetRegisteredPath(id4, &path));
166   ASSERT_FALSE(isolated_context()->GetRegisteredPath(id5, &path));
167 
168   // Revoke the file systems by path.
169   isolated_context()->RevokeFileSystemByPath(path);
170 
171   // Now all the file systems associated to the path must be invalid.
172   ASSERT_FALSE(isolated_context()->GetRegisteredPath(id2, &path));
173   ASSERT_FALSE(isolated_context()->GetRegisteredPath(id3, &path));
174   ASSERT_FALSE(isolated_context()->GetRegisteredPath(id4, &path));
175   ASSERT_FALSE(isolated_context()->GetRegisteredPath(id5, &path));
176 }
177 
TEST_F(IsolatedContextTest,CrackWithRelativePaths)178 TEST_F(IsolatedContextTest, CrackWithRelativePaths) {
179   const struct {
180     base::FilePath::StringType path;
181     bool valid;
182   } relatives[] = {
183     { FPL("foo"), true },
184     { FPL("foo/bar"), true },
185     { FPL(".."), false },
186     { FPL("foo/.."), false },
187     { FPL("foo/../bar"), false },
188 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
189 # define SHOULD_FAIL_WITH_WIN_SEPARATORS false
190 #else
191 # define SHOULD_FAIL_WITH_WIN_SEPARATORS true
192 #endif
193     { FPL("foo\\..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS },
194     { FPL("foo/..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS },
195   };
196 
197   for (size_t i = 0; i < arraysize(kTestPaths); ++i) {
198     for (size_t j = 0; j < ARRAYSIZE_UNSAFE(relatives); ++j) {
199       SCOPED_TRACE(testing::Message() << "Testing "
200                    << kTestPaths[i].value() << " " << relatives[j].path);
201       base::FilePath virtual_path =
202           isolated_context()->CreateVirtualRootPath(id_).AppendASCII(
203               names_[i]).Append(relatives[j].path);
204       std::string cracked_id;
205       base::FilePath cracked_path;
206       fileapi::FileSystemType cracked_type;
207       std::string cracked_inner_id;
208       FileSystemMountOption cracked_option;
209       if (!relatives[j].valid) {
210         ASSERT_FALSE(isolated_context()->CrackVirtualPath(
211             virtual_path, &cracked_id, &cracked_type, &cracked_inner_id,
212             &cracked_path, &cracked_option));
213         continue;
214       }
215       ASSERT_TRUE(isolated_context()->CrackVirtualPath(
216           virtual_path, &cracked_id, &cracked_type, &cracked_inner_id,
217           &cracked_path, &cracked_option));
218       ASSERT_EQ(kTestPaths[i].Append(relatives[j].path)
219                     .NormalizePathSeparators().value(),
220                 cracked_path.value());
221       ASSERT_EQ(id_, cracked_id);
222       ASSERT_EQ(kFileSystemTypeDragged, cracked_type);
223       EXPECT_TRUE(cracked_inner_id.empty());
224     }
225   }
226 }
227 
TEST_F(IsolatedContextTest,CrackURLWithRelativePaths)228 TEST_F(IsolatedContextTest, CrackURLWithRelativePaths) {
229   const struct {
230     base::FilePath::StringType path;
231     bool valid;
232   } relatives[] = {
233     { FPL("foo"), true },
234     { FPL("foo/bar"), true },
235     { FPL(".."), false },
236     { FPL("foo/.."), false },
237     { FPL("foo/../bar"), false },
238 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
239 # define SHOULD_FAIL_WITH_WIN_SEPARATORS false
240 #else
241 # define SHOULD_FAIL_WITH_WIN_SEPARATORS true
242 #endif
243     { FPL("foo\\..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS },
244     { FPL("foo/..\\baz"), SHOULD_FAIL_WITH_WIN_SEPARATORS },
245   };
246 
247   for (size_t i = 0; i < arraysize(kTestPaths); ++i) {
248     for (size_t j = 0; j < ARRAYSIZE_UNSAFE(relatives); ++j) {
249       SCOPED_TRACE(testing::Message() << "Testing "
250                    << kTestPaths[i].value() << " " << relatives[j].path);
251       base::FilePath virtual_path =
252           isolated_context()->CreateVirtualRootPath(id_).AppendASCII(
253               names_[i]).Append(relatives[j].path);
254 
255       FileSystemURL cracked = isolated_context()->CreateCrackedFileSystemURL(
256           GURL("http://chromium.org"), kFileSystemTypeIsolated, virtual_path);
257 
258       ASSERT_EQ(relatives[j].valid, cracked.is_valid());
259 
260       if (!relatives[j].valid)
261         continue;
262       ASSERT_EQ(GURL("http://chromium.org"), cracked.origin());
263       ASSERT_EQ(kTestPaths[i].Append(relatives[j].path)
264                     .NormalizePathSeparators().value(),
265                 cracked.path().value());
266       ASSERT_EQ(virtual_path.NormalizePathSeparators(), cracked.virtual_path());
267       ASSERT_EQ(id_, cracked.filesystem_id());
268       ASSERT_EQ(kFileSystemTypeDragged, cracked.type());
269       ASSERT_EQ(kFileSystemTypeIsolated, cracked.mount_type());
270     }
271   }
272 }
273 
TEST_F(IsolatedContextTest,TestWithVirtualRoot)274 TEST_F(IsolatedContextTest, TestWithVirtualRoot) {
275   std::string cracked_id;
276   base::FilePath cracked_path;
277   FileSystemMountOption cracked_option;
278 
279   // Trying to crack virtual root "/" returns true but with empty cracked path
280   // as "/" of the isolated filesystem is a pure virtual directory
281   // that has no corresponding platform directory.
282   base::FilePath virtual_path = isolated_context()->CreateVirtualRootPath(id_);
283   ASSERT_TRUE(isolated_context()->CrackVirtualPath(
284       virtual_path, &cracked_id, NULL, NULL, &cracked_path, &cracked_option));
285   ASSERT_EQ(FPL(""), cracked_path.value());
286   ASSERT_EQ(id_, cracked_id);
287 
288   // Trying to crack "/foo" should fail (because "foo" is not the one
289   // included in the kTestPaths).
290   virtual_path = isolated_context()->CreateVirtualRootPath(
291       id_).AppendASCII("foo");
292   ASSERT_FALSE(isolated_context()->CrackVirtualPath(
293       virtual_path, &cracked_id, NULL, NULL, &cracked_path, &cracked_option));
294 }
295 
TEST_F(IsolatedContextTest,CanHandleURL)296 TEST_F(IsolatedContextTest, CanHandleURL) {
297   const GURL test_origin("http://chromium.org");
298   const base::FilePath test_path(FPL("/mount"));
299 
300   // Should handle isolated file system.
301   EXPECT_TRUE(isolated_context()->HandlesFileSystemMountType(
302       fileapi::kFileSystemTypeIsolated));
303 
304   // Shouldn't handle the rest.
305   EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
306       fileapi::kFileSystemTypeExternal));
307   EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
308       fileapi::kFileSystemTypeTemporary));
309   EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
310       fileapi::kFileSystemTypePersistent));
311   EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
312       fileapi::kFileSystemTypeTest));
313   // Not even if it's isolated subtype.
314   EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
315       fileapi::kFileSystemTypeNativeLocal));
316   EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
317       fileapi::kFileSystemTypeDragged));
318   EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
319       fileapi::kFileSystemTypeNativeMedia));
320   EXPECT_FALSE(isolated_context()->HandlesFileSystemMountType(
321       fileapi::kFileSystemTypeDeviceMedia));
322 }
323 
TEST_F(IsolatedContextTest,VirtualFileSystemTests)324 TEST_F(IsolatedContextTest, VirtualFileSystemTests) {
325   // Should be able to register empty and non-absolute paths
326   std::string empty_fsid = isolated_context()->RegisterFileSystemForVirtualPath(
327       fileapi::kFileSystemTypeIsolated, "_", base::FilePath());
328   std::string relative_fsid =
329       isolated_context()->RegisterFileSystemForVirtualPath(
330           fileapi::kFileSystemTypeIsolated, "_",
331           base::FilePath(FPL("relpath")));
332   ASSERT_FALSE(empty_fsid.empty());
333   ASSERT_FALSE(relative_fsid.empty());
334 
335   // Make sure that filesystem root is not prepended to cracked virtual paths.
336   base::FilePath database_root = base::FilePath(DRIVE FPL("/database_path"));
337   std::string database_fsid =
338       isolated_context()->RegisterFileSystemForVirtualPath(
339           fileapi::kFileSystemTypeIsolated, "_", database_root);
340 
341   base::FilePath test_virtual_path =
342       base::FilePath().AppendASCII("virtualdir").AppendASCII("virtualfile.txt");
343 
344   base::FilePath whole_virtual_path =
345       isolated_context()->CreateVirtualRootPath(database_fsid)
346           .AppendASCII("_").Append(test_virtual_path);
347 
348   std::string cracked_id;
349   base::FilePath cracked_path;
350   std::string cracked_inner_id;
351   FileSystemMountOption cracked_option;
352   ASSERT_TRUE(isolated_context()->CrackVirtualPath(
353       whole_virtual_path, &cracked_id, NULL, &cracked_inner_id,
354       &cracked_path, &cracked_option));
355   ASSERT_EQ(database_fsid, cracked_id);
356   ASSERT_EQ(test_virtual_path, cracked_path);
357   EXPECT_TRUE(cracked_inner_id.empty());
358 }
359 
360 }  // namespace content
361