OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/browser/fileapi/sandbox_context.h" | 5 #include "webkit/browser/fileapi/sandbox_context.h" |
6 | 6 |
7 #include "base/command_line.h" | |
8 #include "base/file_util.h" | |
9 #include "base/stl_util.h" | |
7 #include "base/task_runner_util.h" | 10 #include "base/task_runner_util.h" |
11 #include "net/base/net_util.h" | |
8 #include "webkit/browser/fileapi/async_file_util_adapter.h" | 12 #include "webkit/browser/fileapi/async_file_util_adapter.h" |
13 #include "webkit/browser/fileapi/file_system_context.h" | |
14 #include "webkit/browser/fileapi/file_system_operation_context.h" | |
15 #include "webkit/browser/fileapi/file_system_url.h" | |
9 #include "webkit/browser/fileapi/file_system_usage_cache.h" | 16 #include "webkit/browser/fileapi/file_system_usage_cache.h" |
10 #include "webkit/browser/fileapi/obfuscated_file_util.h" | 17 #include "webkit/browser/fileapi/obfuscated_file_util.h" |
11 #include "webkit/browser/fileapi/sandbox_quota_observer.h" | 18 #include "webkit/browser/fileapi/sandbox_quota_observer.h" |
12 #include "webkit/browser/quota/quota_manager.h" | 19 #include "webkit/browser/quota/quota_manager.h" |
20 #include "webkit/common/fileapi/file_system_util.h" | |
13 | 21 |
14 namespace fileapi { | 22 namespace fileapi { |
15 | 23 |
24 namespace { | |
25 | |
26 // A command line switch to disable usage tracking. | |
27 const char kDisableUsageTracking[] = "disable-file-system-usage-tracking"; | |
kinuko
2013/07/31 07:35:53
Wasn't this deleted?
nhiroki
2013/07/31 07:52:08
Oops, good catch! I deleted this in the previous c
| |
28 | |
29 // Restricted names. | |
30 // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions | |
31 const base::FilePath::CharType* const kRestrictedNames[] = { | |
32 FILE_PATH_LITERAL("."), FILE_PATH_LITERAL(".."), | |
33 }; | |
34 | |
35 // Restricted chars. | |
36 const base::FilePath::CharType kRestrictedChars[] = { | |
37 FILE_PATH_LITERAL('/'), FILE_PATH_LITERAL('\\'), | |
38 }; | |
39 | |
40 class ObfuscatedOriginEnumerator | |
41 : public SandboxContext::OriginEnumerator { | |
42 public: | |
43 explicit ObfuscatedOriginEnumerator(ObfuscatedFileUtil* file_util) { | |
44 enum_.reset(file_util->CreateOriginEnumerator()); | |
45 } | |
46 virtual ~ObfuscatedOriginEnumerator() {} | |
47 | |
48 virtual GURL Next() OVERRIDE { | |
49 return enum_->Next(); | |
50 } | |
51 | |
52 virtual bool HasFileSystemType(fileapi::FileSystemType type) const OVERRIDE { | |
53 return enum_->HasFileSystemType(type); | |
54 } | |
55 | |
56 private: | |
57 scoped_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enum_; | |
58 }; | |
59 | |
60 } // namespace | |
61 | |
16 const base::FilePath::CharType | 62 const base::FilePath::CharType |
17 SandboxContext::kFileSystemDirectory[] = FILE_PATH_LITERAL("File System"); | 63 SandboxContext::kFileSystemDirectory[] = FILE_PATH_LITERAL("File System"); |
18 | 64 |
19 SandboxContext::SandboxContext( | 65 SandboxContext::SandboxContext( |
20 quota::QuotaManagerProxy* quota_manager_proxy, | 66 quota::QuotaManagerProxy* quota_manager_proxy, |
21 base::SequencedTaskRunner* file_task_runner, | 67 base::SequencedTaskRunner* file_task_runner, |
22 const base::FilePath& profile_path, | 68 const base::FilePath& profile_path, |
23 quota::SpecialStoragePolicy* special_storage_policy) | 69 quota::SpecialStoragePolicy* special_storage_policy, |
70 const FileSystemOptions& file_system_options) | |
24 : file_task_runner_(file_task_runner), | 71 : file_task_runner_(file_task_runner), |
25 sandbox_file_util_(new AsyncFileUtilAdapter( | 72 sandbox_file_util_(new AsyncFileUtilAdapter( |
26 new ObfuscatedFileUtil( | 73 new ObfuscatedFileUtil( |
27 special_storage_policy, | 74 special_storage_policy, |
28 profile_path.Append(kFileSystemDirectory), | 75 profile_path.Append(kFileSystemDirectory), |
29 file_task_runner))), | 76 file_task_runner))), |
30 file_system_usage_cache_(new FileSystemUsageCache(file_task_runner)), | 77 file_system_usage_cache_(new FileSystemUsageCache(file_task_runner)), |
31 quota_observer_(new SandboxQuotaObserver( | 78 quota_observer_(new SandboxQuotaObserver( |
32 quota_manager_proxy, | 79 quota_manager_proxy, |
33 file_task_runner, | 80 file_task_runner, |
34 sync_file_util(), | 81 sync_file_util(), |
35 usage_cache())), | 82 usage_cache())), |
36 special_storage_policy_(special_storage_policy) { | 83 special_storage_policy_(special_storage_policy), |
84 file_system_options_(file_system_options) { | |
37 } | 85 } |
38 | 86 |
39 SandboxContext::~SandboxContext() { | 87 SandboxContext::~SandboxContext() { |
40 if (!file_task_runner_->RunsTasksOnCurrentThread()) { | 88 if (!file_task_runner_->RunsTasksOnCurrentThread()) { |
41 AsyncFileUtilAdapter* sandbox_file_util = sandbox_file_util_.release(); | 89 AsyncFileUtilAdapter* sandbox_file_util = sandbox_file_util_.release(); |
42 SandboxQuotaObserver* quota_observer = quota_observer_.release(); | 90 SandboxQuotaObserver* quota_observer = quota_observer_.release(); |
43 FileSystemUsageCache* file_system_usage_cache = | 91 FileSystemUsageCache* file_system_usage_cache = |
44 file_system_usage_cache_.release(); | 92 file_system_usage_cache_.release(); |
45 if (!file_task_runner_->DeleteSoon(FROM_HERE, sandbox_file_util)) | 93 if (!file_task_runner_->DeleteSoon(FROM_HERE, sandbox_file_util)) |
46 delete sandbox_file_util; | 94 delete sandbox_file_util; |
47 if (!file_task_runner_->DeleteSoon(FROM_HERE, quota_observer)) | 95 if (!file_task_runner_->DeleteSoon(FROM_HERE, quota_observer)) |
48 delete quota_observer; | 96 delete quota_observer; |
49 if (!file_task_runner_->DeleteSoon(FROM_HERE, file_system_usage_cache)) | 97 if (!file_task_runner_->DeleteSoon(FROM_HERE, file_system_usage_cache)) |
50 delete file_system_usage_cache; | 98 delete file_system_usage_cache; |
51 } | 99 } |
52 } | 100 } |
53 | 101 |
102 bool SandboxContext::IsAccessValid(const FileSystemURL& url) const { | |
103 if (!IsAllowedScheme(url.origin())) | |
104 return false; | |
105 | |
106 if (url.path().ReferencesParent()) | |
107 return false; | |
108 | |
109 // Return earlier if the path is '/', because VirtualPath::BaseName() | |
110 // returns '/' for '/' and we fail the "basename != '/'" check below. | |
111 // (We exclude '.' because it's disallowed by spec.) | |
112 if (VirtualPath::IsRootPath(url.path()) && | |
113 url.path() != base::FilePath(base::FilePath::kCurrentDirectory)) | |
114 return true; | |
115 | |
116 // Restricted names specified in | |
117 // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restriction s | |
118 base::FilePath filename = VirtualPath::BaseName(url.path()); | |
119 // See if the name is allowed to create. | |
120 for (size_t i = 0; i < arraysize(kRestrictedNames); ++i) { | |
121 if (filename.value() == kRestrictedNames[i]) | |
122 return false; | |
123 } | |
124 for (size_t i = 0; i < arraysize(kRestrictedChars); ++i) { | |
125 if (filename.value().find(kRestrictedChars[i]) != | |
126 base::FilePath::StringType::npos) | |
127 return false; | |
128 } | |
129 | |
130 return true; | |
131 } | |
132 | |
133 bool SandboxContext::IsAllowedScheme(const GURL& url) const { | |
134 // Basically we only accept http or https. We allow file:// URLs | |
135 // only if --allow-file-access-from-files flag is given. | |
136 if (url.SchemeIs("http") || url.SchemeIs("https")) | |
137 return true; | |
138 if (url.SchemeIsFileSystem()) | |
139 return url.inner_url() && IsAllowedScheme(*url.inner_url()); | |
140 | |
141 for (size_t i = 0; | |
142 i < file_system_options_.additional_allowed_schemes().size(); | |
143 ++i) { | |
144 if (url.SchemeIs( | |
145 file_system_options_.additional_allowed_schemes()[i].c_str())) | |
146 return true; | |
147 } | |
148 return false; | |
149 } | |
150 | |
151 SandboxContext::OriginEnumerator* SandboxContext::CreateOriginEnumerator() { | |
152 return new ObfuscatedOriginEnumerator(sync_file_util()); | |
153 } | |
154 | |
155 base::FilePath SandboxContext::GetBaseDirectoryForOriginAndType( | |
156 const GURL& origin_url, fileapi::FileSystemType type, bool create) { | |
157 base::PlatformFileError error = base::PLATFORM_FILE_OK; | |
158 base::FilePath path = sync_file_util()->GetDirectoryForOriginAndType( | |
159 origin_url, type, create, &error); | |
160 if (error != base::PLATFORM_FILE_OK) | |
161 return base::FilePath(); | |
162 return path; | |
163 } | |
164 | |
165 base::PlatformFileError SandboxContext::DeleteOriginDataOnFileThread( | |
166 FileSystemContext* file_system_context, | |
167 quota::QuotaManagerProxy* proxy, | |
168 const GURL& origin_url, | |
169 fileapi::FileSystemType type) { | |
170 int64 usage = GetOriginUsageOnFileThread(file_system_context, | |
171 origin_url, type); | |
kinuko
2013/07/31 07:35:53
nit: indent
nhiroki
2013/07/31 07:52:08
Done.
| |
172 usage_cache()->CloseCacheFiles(); | |
173 bool result = sync_file_util()->DeleteDirectoryForOriginAndType( | |
174 origin_url, type); | |
175 if (result && proxy) { | |
176 proxy->NotifyStorageModified( | |
177 quota::QuotaClient::kFileSystem, | |
178 origin_url, | |
179 FileSystemTypeToQuotaStorageType(type), | |
180 -usage); | |
181 } | |
182 | |
183 if (result) | |
184 return base::PLATFORM_FILE_OK; | |
185 return base::PLATFORM_FILE_ERROR_FAILED; | |
186 } | |
187 | |
188 void SandboxContext::GetOriginsForTypeOnFileThread( | |
189 fileapi::FileSystemType type, std::set<GURL>* origins) { | |
190 DCHECK(origins); | |
191 scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator()); | |
192 GURL origin; | |
193 while (!(origin = enumerator->Next()).is_empty()) { | |
194 if (enumerator->HasFileSystemType(type)) | |
195 origins->insert(origin); | |
196 } | |
197 } | |
198 | |
199 void SandboxContext::GetOriginsForHostOnFileThread( | |
200 fileapi::FileSystemType type, const std::string& host, | |
201 std::set<GURL>* origins) { | |
202 DCHECK(origins); | |
203 scoped_ptr<OriginEnumerator> enumerator(CreateOriginEnumerator()); | |
204 GURL origin; | |
205 while (!(origin = enumerator->Next()).is_empty()) { | |
206 if (host == net::GetHostOrSpecFromURL(origin) && | |
207 enumerator->HasFileSystemType(type)) | |
208 origins->insert(origin); | |
209 } | |
210 } | |
211 | |
212 int64 SandboxContext::GetOriginUsageOnFileThread( | |
213 FileSystemContext* file_system_context, | |
214 const GURL& origin_url, | |
215 fileapi::FileSystemType type) { | |
216 // Don't use usage cache and return recalculated usage for sticky invalidated | |
217 // origins. | |
218 if (ContainsKey(sticky_dirty_origins_, std::make_pair(origin_url, type))) | |
219 return RecalculateUsage(file_system_context, origin_url, type); | |
220 | |
221 base::FilePath base_path = | |
222 GetBaseDirectoryForOriginAndType(origin_url, type, false); | |
223 if (base_path.empty() || !base::DirectoryExists(base_path)) | |
224 return 0; | |
225 base::FilePath usage_file_path = | |
226 base_path.Append(FileSystemUsageCache::kUsageFileName); | |
227 | |
228 bool is_valid = usage_cache()->IsValid(usage_file_path); | |
229 uint32 dirty_status = 0; | |
230 bool dirty_status_available = | |
231 usage_cache()->GetDirty(usage_file_path, &dirty_status); | |
232 bool visited = !visited_origins_.insert(origin_url).second; | |
233 if (is_valid && (dirty_status == 0 || (dirty_status_available && visited))) { | |
234 // The usage cache is clean (dirty == 0) or the origin is already | |
235 // initialized and running. Read the cache file to get the usage. | |
236 int64 usage = 0; | |
237 return usage_cache()->GetUsage(usage_file_path, &usage) ? usage : -1; | |
238 } | |
239 // The usage cache has not been initialized or the cache is dirty. | |
240 // Get the directory size now and update the cache. | |
241 usage_cache()->Delete(usage_file_path); | |
242 | |
243 int64 usage = RecalculateUsage(file_system_context, origin_url, type); | |
244 | |
245 // This clears the dirty flag too. | |
246 usage_cache()->UpdateUsage(usage_file_path, usage); | |
247 return usage; | |
248 } | |
249 | |
250 void SandboxContext::InvalidateUsageCache( | |
251 const GURL& origin, | |
252 fileapi::FileSystemType type) { | |
253 base::PlatformFileError error = base::PLATFORM_FILE_OK; | |
254 base::FilePath usage_file_path = GetUsageCachePathForOriginAndType( | |
255 sync_file_util(), origin, type, &error); | |
256 if (error != base::PLATFORM_FILE_OK) | |
257 return; | |
258 usage_cache()->IncrementDirty(usage_file_path); | |
259 } | |
260 | |
261 void SandboxContext::StickyInvalidateUsageCache( | |
262 const GURL& origin, | |
263 fileapi::FileSystemType type) { | |
264 sticky_dirty_origins_.insert(std::make_pair(origin, type)); | |
265 quota_observer()->SetUsageCacheEnabled(origin, type, false); | |
266 InvalidateUsageCache(origin, type); | |
267 } | |
268 | |
269 base::FilePath SandboxContext::GetUsageCachePathForOriginAndType( | |
270 const GURL& origin_url, | |
271 FileSystemType type) { | |
272 base::PlatformFileError error; | |
273 base::FilePath path = GetUsageCachePathForOriginAndType( | |
274 sync_file_util(), origin_url, type, &error); | |
275 if (error != base::PLATFORM_FILE_OK) | |
276 return base::FilePath(); | |
277 return path; | |
278 } | |
279 | |
280 // static | |
281 base::FilePath SandboxContext::GetUsageCachePathForOriginAndType( | |
282 ObfuscatedFileUtil* sandbox_file_util, | |
283 const GURL& origin_url, | |
284 fileapi::FileSystemType type, | |
285 base::PlatformFileError* error_out) { | |
286 DCHECK(error_out); | |
287 *error_out = base::PLATFORM_FILE_OK; | |
288 base::FilePath base_path = sandbox_file_util->GetDirectoryForOriginAndType( | |
289 origin_url, type, false /* create */, error_out); | |
290 if (*error_out != base::PLATFORM_FILE_OK) | |
291 return base::FilePath(); | |
292 return base_path.Append(FileSystemUsageCache::kUsageFileName); | |
293 } | |
294 | |
295 int64 SandboxContext::RecalculateUsage(FileSystemContext* context, | |
296 const GURL& origin, | |
297 FileSystemType type) { | |
298 FileSystemOperationContext operation_context(context); | |
299 FileSystemURL url = context->CreateCrackedFileSystemURL( | |
300 origin, type, base::FilePath()); | |
301 scoped_ptr<FileSystemFileUtil::AbstractFileEnumerator> enumerator( | |
302 sync_file_util()->CreateFileEnumerator(&operation_context, url, true)); | |
303 | |
304 base::FilePath file_path_each; | |
305 int64 usage = 0; | |
306 | |
307 while (!(file_path_each = enumerator->Next()).empty()) { | |
308 usage += enumerator->Size(); | |
309 usage += ObfuscatedFileUtil::ComputeFilePathCost(file_path_each); | |
310 } | |
311 | |
312 return usage; | |
313 } | |
314 | |
54 ObfuscatedFileUtil* SandboxContext::sync_file_util() { | 315 ObfuscatedFileUtil* SandboxContext::sync_file_util() { |
55 return static_cast<ObfuscatedFileUtil*>(file_util()->sync_file_util()); | 316 return static_cast<ObfuscatedFileUtil*>(file_util()->sync_file_util()); |
56 } | 317 } |
57 | 318 |
58 } // namespace fileapi | 319 } // namespace fileapi |
OLD | NEW |