Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(467)

Side by Side Diff: webkit/fileapi/file_system_path_manager.cc

Issue 6603034: Stop returning the true root path of each filesystem from openFileSystem.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "webkit/fileapi/file_system_path_manager.h" 5 #include "webkit/fileapi/file_system_path_manager.h"
6 6
7 #include "base/rand_util.h" 7 #include "base/rand_util.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/message_loop_proxy.h" 10 #include "base/message_loop_proxy.h"
11 #include "base/scoped_callback_factory.h" 11 #include "base/scoped_callback_factory.h"
12 #include "base/scoped_ptr.h" 12 #include "base/scoped_ptr.h"
13 #include "base/stringprintf.h" 13 #include "base/stringprintf.h"
14 #include "base/string_util.h" 14 #include "base/string_util.h"
15 #include "base/utf_string_conversions.h" 15 #include "base/utf_string_conversions.h"
16 #include "googleurl/src/gurl.h" 16 #include "googleurl/src/gurl.h"
17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCString.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFileSystem.h" 17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFileSystem.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" 18 #include "webkit/fileapi/file_system_util.h"
19 #include "webkit/fileapi/sandbox_mount_point_provider.h"
20 #include "webkit/glue/webkit_glue.h" 20 #include "webkit/glue/webkit_glue.h"
21 21
22 // We use some of WebKit types for conversions between origin identifiers 22 // We use some of WebKit types for conversions between origin identifiers
23 // and origin URLs. 23 // and origin URLs.
24 using WebKit::WebFileSystem; 24 using WebKit::WebFileSystem;
25 using WebKit::WebSecurityOrigin;
26 using WebKit::WebString;
27 25
28 using base::PlatformFileError; 26 using base::PlatformFileError;
29 27
30 namespace fileapi {
31
32 const FilePath::CharType FileSystemPathManager::kFileSystemDirectory[] =
33 FILE_PATH_LITERAL("FileSystem");
34
35 const char FileSystemPathManager::kPersistentName[] = "Persistent";
36 const char FileSystemPathManager::kTemporaryName[] = "Temporary";
37
38 static const FilePath::CharType kFileSystemUniqueNamePrefix[] =
39 FILE_PATH_LITERAL("chrome-");
40 static const int kFileSystemUniqueLength = 16;
41 static const unsigned kFileSystemUniqueDirectoryNameLength =
42 kFileSystemUniqueLength + arraysize(kFileSystemUniqueNamePrefix) - 1;
43
44 namespace {
45
46 // Restricted names.
47 // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions
48 static const char* const kRestrictedNames[] = {
49 "con", "prn", "aux", "nul",
50 "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
51 "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9",
52 };
53
54 // Restricted chars.
55 static const FilePath::CharType kRestrictedChars[] = {
56 '/', '\\', '<', '>', ':', '?', '*', '"', '|',
57 };
58
59 inline std::string FilePathStringToASCII(
60 const FilePath::StringType& path_string) {
61 #if defined(OS_WIN)
62 return WideToASCII(path_string);
63 #elif defined(OS_POSIX)
64 return path_string;
65 #endif
66 }
67
68 FilePath::StringType CreateUniqueDirectoryName(const GURL& origin_url) {
69 // This can be anything but need to be unpredictable.
70 static const FilePath::CharType letters[] = FILE_PATH_LITERAL(
71 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
72 FilePath::StringType unique(kFileSystemUniqueNamePrefix);
73 for (int i = 0; i < kFileSystemUniqueLength; ++i)
74 unique += letters[base::RandInt(0, arraysize(letters) - 2)];
75 return unique;
76 }
77
78 static const char kExtensionScheme[] = "chrome-extension"; 28 static const char kExtensionScheme[] = "chrome-extension";
79 29
80 } // anonymous namespace 30 namespace fileapi {
81
82 class FileSystemPathManager::GetFileSystemRootPathTask
83 : public base::RefCountedThreadSafe<
84 FileSystemPathManager::GetFileSystemRootPathTask> {
85 public:
86 GetFileSystemRootPathTask(
87 scoped_refptr<base::MessageLoopProxy> file_message_loop,
88 const std::string& name,
89 FileSystemPathManager::GetRootPathCallback* callback)
90 : file_message_loop_(file_message_loop),
91 origin_message_loop_proxy_(
92 base::MessageLoopProxy::CreateForCurrentThread()),
93 name_(name),
94 callback_(callback) {
95 }
96
97 void Start(const GURL& origin_url,
98 const FilePath& origin_base_path,
99 bool create) {
100 file_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
101 &GetFileSystemRootPathTask::GetFileSystemRootPathOnFileThread,
102 origin_url, origin_base_path, create));
103 }
104
105 private:
106 void GetFileSystemRootPathOnFileThread(
107 const GURL& origin_url,
108 const FilePath& base_path,
109 bool create) {
110 FilePath root;
111 if (ReadOriginDirectory(base_path, origin_url, &root)) {
112 DispatchCallbackOnCallerThread(root);
113 return;
114 }
115
116 if (!create) {
117 DispatchCallbackOnCallerThread(FilePath());
118 return;
119 }
120
121 // Creates the root directory.
122 root = base_path.Append(CreateUniqueDirectoryName(origin_url));
123 if (!file_util::CreateDirectory(root)) {
124 DispatchCallbackOnCallerThread(FilePath());
125 return;
126 }
127 DispatchCallbackOnCallerThread(root);
128 }
129
130 bool ReadOriginDirectory(const FilePath& base_path,
131 const GURL& origin_url,
132 FilePath* unique) {
133 file_util::FileEnumerator file_enum(
134 base_path, false /* recursive */,
135 file_util::FileEnumerator::DIRECTORIES,
136 FilePath::StringType(kFileSystemUniqueNamePrefix) +
137 FILE_PATH_LITERAL("*"));
138 FilePath current;
139 bool found = false;
140 while (!(current = file_enum.Next()).empty()) {
141 if (current.BaseName().value().length() !=
142 kFileSystemUniqueDirectoryNameLength)
143 continue;
144 if (found) {
145 // TODO(kinuko): Should notify the user to ask for some action.
146 LOG(WARNING) << "Unexpectedly found more than one FileSystem "
147 << "directories for " << origin_url;
148 return false;
149 }
150 found = true;
151 *unique = current;
152 }
153 return !unique->empty();
154 }
155
156 void DispatchCallbackOnCallerThread(const FilePath& root_path) {
157 origin_message_loop_proxy_->PostTask(FROM_HERE,
158 NewRunnableMethod(this, &GetFileSystemRootPathTask::DispatchCallback,
159 root_path));
160 }
161
162 void DispatchCallback(const FilePath& root_path) {
163 callback_->Run(!root_path.empty(), root_path, name_);
164 callback_.reset();
165 }
166
167 scoped_refptr<base::MessageLoopProxy> file_message_loop_;
168 scoped_refptr<base::MessageLoopProxy> origin_message_loop_proxy_;
169 std::string name_;
170 scoped_ptr<FileSystemPathManager::GetRootPathCallback> callback_;
171 };
172 31
173 FileSystemPathManager::FileSystemPathManager( 32 FileSystemPathManager::FileSystemPathManager(
174 scoped_refptr<base::MessageLoopProxy> file_message_loop, 33 scoped_refptr<base::MessageLoopProxy> file_message_loop,
175 const FilePath& profile_path, 34 const FilePath& profile_path,
176 bool is_incognito, 35 bool is_incognito,
177 bool allow_file_access_from_files) 36 bool allow_file_access_from_files)
178 : file_message_loop_(file_message_loop), 37 : is_incognito_(is_incognito),
179 base_path_(profile_path.Append(kFileSystemDirectory)), 38 allow_file_access_from_files_(allow_file_access_from_files),
180 is_incognito_(is_incognito), 39 sandbox_provider_(
181 allow_file_access_from_files_(allow_file_access_from_files) { 40 new SandboxMountPointProvider(
41 ALLOW_THIS_IN_INITIALIZER_LIST(this),
42 file_message_loop,
43 profile_path)) {
182 } 44 }
183 45
184 FileSystemPathManager::~FileSystemPathManager() {} 46 FileSystemPathManager::~FileSystemPathManager() {}
185 47
186 void FileSystemPathManager::GetFileSystemRootPath( 48 void FileSystemPathManager::GetFileSystemRootPath(
187 const GURL& origin_url, fileapi::FileSystemType type, 49 const GURL& origin_url, fileapi::FileSystemType type,
188 bool create, GetRootPathCallback* callback_ptr) { 50 bool create, GetRootPathCallback* callback_ptr) {
189 scoped_ptr<GetRootPathCallback> callback(callback_ptr); 51
190 if (is_incognito_) { 52 switch (type) {
191 // TODO(kinuko): return an isolated temporary directory. 53 case kFileSystemTypeTemporary:
192 callback->Run(false, FilePath(), std::string()); 54 case kFileSystemTypePersistent:
193 return; 55 sandbox_provider_->GetFileSystemRootPath(
56 origin_url, type, create, callback_ptr);
57 break;
58 case kFileSystemTypeUnknown:
59 default:
60 NOTREACHED();
61 callback_ptr->Run(false, FilePath(), std::string());
194 } 62 }
63 }
195 64
196 if (!IsAllowedScheme(origin_url)) { 65 FilePath FileSystemPathManager::GetFileSystemRootPathOnFileThread(
197 callback->Run(false, FilePath(), std::string()); 66 const GURL& origin_url, FileSystemType type, bool create) {
198 return; 67 switch (type) {
68 case kFileSystemTypeTemporary:
69 case kFileSystemTypePersistent:
70 return sandbox_provider_->GetFileSystemRootPathOnFileThread(
71 origin_url, type, create);
72 break;
73 case kFileSystemTypeUnknown:
74 default:
75 NOTREACHED();
76 return FilePath();
199 } 77 }
200
201 std::string origin_identifier = GetOriginIdentifierFromURL(origin_url);
202 FilePath origin_base_path = GetFileSystemBaseDirectoryForOriginAndType(
203 base_path(), origin_identifier, type);
204 if (origin_base_path.empty()) {
205 callback->Run(false, FilePath(), std::string());
206 return;
207 }
208
209 std::string type_string = GetFileSystemTypeString(type);
210 DCHECK(!type_string.empty());
211
212 scoped_refptr<GetFileSystemRootPathTask> task(
213 new GetFileSystemRootPathTask(file_message_loop_,
214 origin_identifier + ":" + type_string,
215 callback.release()));
216 task->Start(origin_url, origin_base_path, create);
217 } 78 }
218 79
219 bool FileSystemPathManager::CrackFileSystemPath( 80 bool FileSystemPathManager::CrackFileSystemPath(
220 const FilePath& path, GURL* origin_url, FileSystemType* type, 81 const FilePath& path, GURL* origin_url, FileSystemType* type,
221 FilePath* virtual_path) const { 82 FilePath* virtual_path) const {
222 // Any paths that includes parent references are considered invalid. 83 // TODO(ericu):
223 if (path.ReferencesParent()) 84 // Paths come in here [for now] as a URL, followed by a virtual path in
85 // platform format. For example, on Windows, this will look like
86 // filesystem:http://www.example.com/temporary/\path\to\file.txt.
87 // A potentially dangerous malicious path on Windows might look like:
88 // filesystem:http://www.example.com/temporary/foo/../../\path\to\file.txt.
89 // This code is ugly, but will get cleaned up as we fix the calling side.
90 // Eventually there won't be a distinction between a filesystem path and a
91 // filesystem URL--they'll all be URLs.
92 // We should be passing these to WebKit as string, not FilePath, for ease of
93 // manipulation, or possibly as GURL/KURL.
94
95 std::string path_as_string;
96 #ifdef OS_WIN
97 path_as_string = WideToUTF8(path.value());
98 #else
99 path_as_string = path.value();
100 #endif
101 GURL path_as_url(path_as_string);
102
103 FilePath local_path;
104 GURL local_url;
105 FileSystemType local_type;
106 if (!CrackFileSystemURL(path_as_url, &local_url, &local_type, &local_path))
224 return false; 107 return false;
225 108
226 // The path should be a child of the profile FileSystem path. 109 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
227 FilePath relative; 110 // TODO(ericu): This puts the separators back to windows-standard; they come
228 if (!base_path_.AppendRelativePath(path, &relative)) 111 // out of the above code as '/' no matter the platform. Long-term, we'll
229 return false; 112 // want to let the underlying FileSystemFileUtil implementation do this part,
113 // since they won't all need it.
114 local_path = local_path.NormalizeWindowsPathSeparators();
115 #endif
230 116
231 // The relative path from the profile FileSystem path should contain 117 // Any paths that include parent references are considered invalid.
232 // at least three components, one for storage identifier, one for type 118 // These should have been taken care of in CrackFileSystemURL.
233 // and one for the 'unique' part. 119 DCHECK(!local_path.ReferencesParent());
234 std::vector<FilePath::StringType> components;
235 relative.GetComponents(&components);
236 if (components.size() < 3)
237 return false;
238 120
239 // The second component of the relative path to the root directory 121 // The given |local_path| seems valid. Populates the |origin_url|, |type|
240 // must be kPersistent or kTemporary.
241 if (!IsStringASCII(components[1]))
242 return false;
243
244 std::string ascii_type_component = FilePathStringToASCII(components[1]);
245 FileSystemType cracked_type = kFileSystemTypeUnknown;
246 if (ascii_type_component == kPersistentName)
247 cracked_type = kFileSystemTypePersistent;
248 else if (ascii_type_component == kTemporaryName)
249 cracked_type = kFileSystemTypeTemporary;
250 else
251 return false;
252
253 DCHECK(cracked_type != kFileSystemTypeUnknown);
254
255 // The given |path| seems valid. Populates the |origin_url|, |type|
256 // and |virtual_path| if they are given. 122 // and |virtual_path| if they are given.
257 123
258 if (origin_url) { 124 if (origin_url) {
259 WebSecurityOrigin web_security_origin = 125 *origin_url = local_url;
260 WebSecurityOrigin::createFromDatabaseIdentifier(
261 webkit_glue::FilePathStringToWebString(components[0]));
262 *origin_url = GURL(web_security_origin.toString());
263
264 // We need this work-around for file:/// URIs as
265 // createFromDatabaseIdentifier returns empty origin_url for them.
266 if (allow_file_access_from_files_ && origin_url->spec().empty() &&
267 components[0].find(FILE_PATH_LITERAL("file")) == 0)
268 *origin_url = GURL("file:///");
269 } 126 }
270 127
271 if (type) 128 if (type)
272 *type = cracked_type; 129 *type = local_type;
273 130
274 if (virtual_path) { 131 if (virtual_path) {
275 virtual_path->clear(); 132 *virtual_path = local_path;
276 for (size_t i = 3; i < components.size(); ++i)
277 *virtual_path = virtual_path->Append(components[i]);
278 } 133 }
279 134
280 return true; 135 return true;
281 } 136 }
282 137
283 bool FileSystemPathManager::IsAllowedScheme(const GURL& url) const { 138 bool FileSystemPathManager::IsAllowedScheme(const GURL& url) const {
284 // Basically we only accept http or https. We allow file:// URLs 139 // Basically we only accept http or https. We allow file:// URLs
285 // only if --allow-file-access-from-files flag is given. 140 // only if --allow-file-access-from-files flag is given.
286 return url.SchemeIs("http") || url.SchemeIs("https") || 141 return url.SchemeIs("http") || url.SchemeIs("https") ||
287 url.SchemeIs(kExtensionScheme) || 142 url.SchemeIs(kExtensionScheme) ||
288 (url.SchemeIsFile() && allow_file_access_from_files_); 143 (url.SchemeIsFile() && allow_file_access_from_files_);
289 } 144 }
290 145
291 // static 146 // static
292 bool FileSystemPathManager::IsRestrictedFileName(const FilePath& filename) {
293 if (filename.value().empty())
294 return false;
295
296 if (IsWhitespace(filename.value()[filename.value().size() - 1]) ||
297 filename.value()[filename.value().size() - 1] == '.')
298 return true;
299
300 std::string filename_lower = StringToLowerASCII(
301 FilePathStringToASCII(filename.value()));
302
303 for (size_t i = 0; i < arraysize(kRestrictedNames); ++i) {
304 // Exact match.
305 if (filename_lower == kRestrictedNames[i])
306 return true;
307 // Starts with "RESTRICTED_NAME.".
308 if (filename_lower.find(std::string(kRestrictedNames[i]) + ".") == 0)
309 return true;
310 }
311
312 for (size_t i = 0; i < arraysize(kRestrictedChars); ++i) {
313 if (filename.value().find(kRestrictedChars[i]) !=
314 FilePath::StringType::npos)
315 return true;
316 }
317
318 return false;
319 }
320
321 // static
322 std::string FileSystemPathManager::GetFileSystemTypeString( 147 std::string FileSystemPathManager::GetFileSystemTypeString(
323 fileapi::FileSystemType type) { 148 fileapi::FileSystemType type) {
324 if (type == fileapi::kFileSystemTypeTemporary) 149 if (type == fileapi::kFileSystemTypeTemporary)
325 return fileapi::FileSystemPathManager::kTemporaryName; 150 return fileapi::SandboxMountPointProvider::kTemporaryName;
326 else if (type == fileapi::kFileSystemTypePersistent) 151 else if (type == fileapi::kFileSystemTypePersistent)
327 return fileapi::FileSystemPathManager::kPersistentName; 152 return fileapi::SandboxMountPointProvider::kPersistentName;
328 return std::string(); 153 return std::string();
329 } 154 }
330 155
331 // static 156 // Checks if a given |name| contains any restricted names/chars in it.
332 std::string FileSystemPathManager::GetOriginIdentifierFromURL( 157 bool FileSystemPathManager::IsRestrictedFileName(
333 const GURL& url) { 158 FileSystemType type, const FilePath& filename) {
334 WebKit::WebSecurityOrigin web_security_origin = 159 switch (type) {
335 WebKit::WebSecurityOrigin::createFromString(UTF8ToUTF16(url.spec())); 160 case kFileSystemTypeTemporary:
336 return web_security_origin.databaseIdentifier().utf8(); 161 case kFileSystemTypePersistent:
337 } 162 return sandbox_provider_->IsRestrictedFileName(filename);
338 163 case kFileSystemTypeUnknown:
339 // static 164 default:
340 FilePath FileSystemPathManager::GetFileSystemBaseDirectoryForOriginAndType( 165 NOTREACHED();
341 const FilePath& base_path, const std::string& origin_identifier, 166 return true;
342 fileapi::FileSystemType type) {
343 if (origin_identifier.empty())
344 return FilePath();
345 std::string type_string = GetFileSystemTypeString(type);
346 if (type_string.empty()) {
347 LOG(WARNING) << "Unknown filesystem type is requested:" << type;
348 return FilePath();
349 } 167 }
350 return base_path.AppendASCII(origin_identifier)
351 .AppendASCII(type_string);
352 }
353
354 FileSystemPathManager::OriginEnumerator::OriginEnumerator(
355 const FilePath& base_path)
356 : enumerator_(base_path, false /* recursive */,
357 file_util::FileEnumerator::DIRECTORIES) {
358 }
359
360 std::string FileSystemPathManager::OriginEnumerator::Next() {
361 current_ = enumerator_.Next();
362 return FilePathStringToASCII(current_.BaseName().value());
363 }
364
365 bool FileSystemPathManager::OriginEnumerator::HasTemporary() {
366 return !current_.empty() && file_util::DirectoryExists(current_.AppendASCII(
367 FileSystemPathManager::kTemporaryName));
368 }
369
370 bool FileSystemPathManager::OriginEnumerator::HasPersistent() {
371 return !current_.empty() && file_util::DirectoryExists(current_.AppendASCII(
372 FileSystemPathManager::kPersistentName));
373 } 168 }
374 169
375 } // namespace fileapi 170 } // namespace fileapi
376 171
377 COMPILE_ASSERT(int(WebFileSystem::TypeTemporary) == \ 172 COMPILE_ASSERT(int(WebFileSystem::TypeTemporary) == \
378 int(fileapi::kFileSystemTypeTemporary), mismatching_enums); 173 int(fileapi::kFileSystemTypeTemporary), mismatching_enums);
379 COMPILE_ASSERT(int(WebFileSystem::TypePersistent) == \ 174 COMPILE_ASSERT(int(WebFileSystem::TypePersistent) == \
380 int(fileapi::kFileSystemTypePersistent), mismatching_enums); 175 int(fileapi::kFileSystemTypePersistent), mismatching_enums);
OLDNEW
« no previous file with comments | « webkit/fileapi/file_system_path_manager.h ('k') | webkit/fileapi/file_system_path_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698