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

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" 17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCString.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFileSystem.h" 18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFileSystem.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" 19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
kinuko 2011/03/14 11:03:57 line 17,19 not needed
ericu 2011/03/15 02:43:11 Done.
20 #include "webkit/fileapi/file_system_util.h"
21 #include "webkit/fileapi/sandbox_mount_point_provider.h"
20 #include "webkit/glue/webkit_glue.h" 22 #include "webkit/glue/webkit_glue.h"
21 23
22 // We use some of WebKit types for conversions between origin identifiers 24 // We use some of WebKit types for conversions between origin identifiers
23 // and origin URLs. 25 // and origin URLs.
24 using WebKit::WebFileSystem; 26 using WebKit::WebFileSystem;
25 using WebKit::WebSecurityOrigin; 27 using WebKit::WebSecurityOrigin;
26 using WebKit::WebString; 28 using WebKit::WebString;
kinuko 2011/03/14 11:03:57 line 27,28 not needed
ericu 2011/03/15 02:43:11 Done.
27 29
28 using base::PlatformFileError; 30 using base::PlatformFileError;
29 31
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"; 32 static const char kExtensionScheme[] = "chrome-extension";
79 33
80 } // anonymous namespace 34 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 35
173 FileSystemPathManager::FileSystemPathManager( 36 FileSystemPathManager::FileSystemPathManager(
174 scoped_refptr<base::MessageLoopProxy> file_message_loop, 37 scoped_refptr<base::MessageLoopProxy> file_message_loop,
175 const FilePath& profile_path, 38 const FilePath& profile_path,
176 bool is_incognito, 39 bool is_incognito,
177 bool allow_file_access_from_files) 40 bool allow_file_access_from_files)
178 : file_message_loop_(file_message_loop), 41 : is_incognito_(is_incognito),
179 base_path_(profile_path.Append(kFileSystemDirectory)), 42 allow_file_access_from_files_(allow_file_access_from_files),
180 is_incognito_(is_incognito), 43 sandbox_provider_(
181 allow_file_access_from_files_(allow_file_access_from_files) { 44 new SandboxMountPointProvider(
45 ALLOW_THIS_IN_INITIALIZER_LIST(this),
46 file_message_loop,
47 profile_path)) {
182 } 48 }
183 49
184 FileSystemPathManager::~FileSystemPathManager() {} 50 FileSystemPathManager::~FileSystemPathManager() {}
185 51
186 void FileSystemPathManager::GetFileSystemRootPath( 52 void FileSystemPathManager::GetFileSystemRootPath(
187 const GURL& origin_url, fileapi::FileSystemType type, 53 const GURL& origin_url, fileapi::FileSystemType type,
188 bool create, GetRootPathCallback* callback_ptr) { 54 bool create, GetRootPathCallback* callback_ptr) {
189 scoped_ptr<GetRootPathCallback> callback(callback_ptr); 55
190 if (is_incognito_) { 56 switch (type) {
191 // TODO(kinuko): return an isolated temporary directory. 57 case kFileSystemTypeTemporary:
192 callback->Run(false, FilePath(), std::string()); 58 case kFileSystemTypePersistent:
193 return; 59 sandbox_provider_->GetFileSystemRootPath(
60 origin_url, type, create, callback_ptr);
61 break;
62 case kFileSystemTypeUnknown:
63 default:
64 NOTREACHED();
65 callback_ptr->Run(false, FilePath(), std::string());
194 } 66 }
67 }
195 68
196 if (!IsAllowedScheme(origin_url)) { 69 FilePath FileSystemPathManager::GetFileSystemRootPathOnFileThread(
197 callback->Run(false, FilePath(), std::string()); 70 const GURL& origin_url, FileSystemType type, bool create) {
198 return; 71 switch (type) {
72 case kFileSystemTypeTemporary:
73 case kFileSystemTypePersistent:
74 return sandbox_provider_->GetFileSystemRootPathOnFileThread(
75 origin_url, type, create);
76 break;
77 case kFileSystemTypeUnknown:
78 default:
79 NOTREACHED();
80 return FilePath();
199 } 81 }
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 } 82 }
218 83
219 bool FileSystemPathManager::CrackFileSystemPath( 84 bool FileSystemPathManager::CrackFileSystemPath(
220 const FilePath& path, GURL* origin_url, FileSystemType* type, 85 const FilePath& path, GURL* origin_url, FileSystemType* type,
221 FilePath* virtual_path) const { 86 FilePath* virtual_path) const {
222 // Any paths that includes parent references are considered invalid. 87 // TODO(ericu):
223 if (path.ReferencesParent()) 88 // Paths come in here [for now] as a URL, followed by a virtual path in
89 // platform format. For example, on Windows, this will look like
90 // filesystem:http://www.example.com/temporary/\path\to\file.txt.
91 // A potentially dangerous malicious path on Windows might look like:
92 // filesystem:http://www.example.com/temporary/foo/../../\path\to\file.txt.
93 // This code is ugly, but will get cleaned up as we fix the calling side.
94 // We should be passing these to WebKit as string, not FilePath, for ease of
95 // manipulation, or possibly as GURL/KURL.
96
97 std::string path_as_string;
98 #ifdef OS_WIN
99 path_as_string = WideToUTF8(path.value());
100 #else
101 path_as_string = path.value();
102 #endif
103 GURL path_as_url(path_as_string);
104
105 FilePath local_path;
106 GURL local_url;
107 FileSystemType local_type;
108 if (!CrackFileSystemURL(path_as_url, &local_url, &local_type, &local_path))
224 return false; 109 return false;
225 110
226 // The path should be a child of the profile FileSystem path. 111 #if defined(FILE_PATH_USES_WIN_SEPARATORS)
227 FilePath relative; 112 // TODO(ericu): This puts the separators back to windows-standard; they come
228 if (!base_path_.AppendRelativePath(path, &relative)) 113 // out of the above code as '/' no matter the platform. Long-term, we'll
229 return false; 114 // want to let the underlying FileSystemFileUtil implementation do this part,
115 // since they won't all need it.
116 local_path = local_path.NormalizeWindowsPathSeparators();
117 #endif
230 118
231 // The relative path from the profile FileSystem path should contain 119 // Any paths that include parent references are considered invalid.
232 // at least three components, one for storage identifier, one for type 120 // These should have been taken care of in CrackFileSystemURL.
233 // and one for the 'unique' part. 121 DCHECK(!local_path.ReferencesParent());
kinuko 2011/03/14 11:03:57 Can't we get rid of these checks (line 111 to 121)
ericu 2011/03/15 02:43:11 111->117 fixes up separators that are the wrong wa
kinuko 2011/03/16 19:33:38 Ok... can we add some comments about that? (A sho
ericu 2011/03/16 23:47:31 Added a small addendum to the upper comment in thi
234 std::vector<FilePath::StringType> components;
235 relative.GetComponents(&components);
236 if (components.size() < 3)
237 return false;
238 122
239 // The second component of the relative path to the root directory 123 // 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. 124 // and |virtual_path| if they are given.
257 125
258 if (origin_url) { 126 if (origin_url) {
259 WebSecurityOrigin web_security_origin = 127 *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 } 128 }
270 129
271 if (type) 130 if (type)
272 *type = cracked_type; 131 *type = local_type;
273 132
274 if (virtual_path) { 133 if (virtual_path) {
275 virtual_path->clear(); 134 *virtual_path = local_path;
276 for (size_t i = 3; i < components.size(); ++i)
277 *virtual_path = virtual_path->Append(components[i]);
278 } 135 }
279 136
280 return true; 137 return true;
281 } 138 }
282 139
283 bool FileSystemPathManager::IsAllowedScheme(const GURL& url) const { 140 bool FileSystemPathManager::IsAllowedScheme(const GURL& url) const {
284 // Basically we only accept http or https. We allow file:// URLs 141 // Basically we only accept http or https. We allow file:// URLs
285 // only if --allow-file-access-from-files flag is given. 142 // only if --allow-file-access-from-files flag is given.
286 return url.SchemeIs("http") || url.SchemeIs("https") || 143 return url.SchemeIs("http") || url.SchemeIs("https") ||
287 url.SchemeIs(kExtensionScheme) || 144 url.SchemeIs(kExtensionScheme) ||
288 (url.SchemeIsFile() && allow_file_access_from_files_); 145 (url.SchemeIsFile() && allow_file_access_from_files_);
289 } 146 }
290 147
291 // static 148 // 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( 149 std::string FileSystemPathManager::GetFileSystemTypeString(
323 fileapi::FileSystemType type) { 150 fileapi::FileSystemType type) {
324 if (type == fileapi::kFileSystemTypeTemporary) 151 if (type == fileapi::kFileSystemTypeTemporary)
325 return fileapi::FileSystemPathManager::kTemporaryName; 152 return fileapi::SandboxMountPointProvider::kTemporaryName;
326 else if (type == fileapi::kFileSystemTypePersistent) 153 else if (type == fileapi::kFileSystemTypePersistent)
327 return fileapi::FileSystemPathManager::kPersistentName; 154 return fileapi::SandboxMountPointProvider::kPersistentName;
328 return std::string(); 155 return std::string();
329 } 156 }
330 157
331 // static 158 // Checks if a given |name| contains any restricted names/chars in it.
332 std::string FileSystemPathManager::GetOriginIdentifierFromURL( 159 bool FileSystemPathManager::IsRestrictedFileName(
333 const GURL& url) { 160 FileSystemType type, const FilePath& filename) {
334 WebKit::WebSecurityOrigin web_security_origin = 161 switch (type) {
335 WebKit::WebSecurityOrigin::createFromString(UTF8ToUTF16(url.spec())); 162 case kFileSystemTypeTemporary:
336 return web_security_origin.databaseIdentifier().utf8(); 163 case kFileSystemTypePersistent:
337 } 164 return sandbox_provider_->IsRestrictedFileName(filename);
338 165 case kFileSystemTypeUnknown:
339 // static 166 default:
340 FilePath FileSystemPathManager::GetFileSystemBaseDirectoryForOriginAndType( 167 NOTREACHED();
341 const FilePath& base_path, const std::string& origin_identifier, 168 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 } 169 }
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 } 170 }
374 171
375 } // namespace fileapi 172 } // namespace fileapi
376 173
377 COMPILE_ASSERT(int(WebFileSystem::TypeTemporary) == \ 174 COMPILE_ASSERT(int(WebFileSystem::TypeTemporary) == \
378 int(fileapi::kFileSystemTypeTemporary), mismatching_enums); 175 int(fileapi::kFileSystemTypeTemporary), mismatching_enums);
379 COMPILE_ASSERT(int(WebFileSystem::TypePersistent) == \ 176 COMPILE_ASSERT(int(WebFileSystem::TypePersistent) == \
380 int(fileapi::kFileSystemTypePersistent), mismatching_enums); 177 int(fileapi::kFileSystemTypePersistent), mismatching_enums);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698