[Media Router] Add integration tests and e2e tests for media router and presentation...
[chromium-blink-merge.git] / chrome / browser / media_galleries / fileapi / media_file_system_backend.cc
blobdef7bdf761f4cd82287d63496460863ee2494d7c
1 // Copyright (c) 2013 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.
5 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
7 #include <string>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/files/file_path.h"
12 #include "base/logging.h"
13 #include "base/sequenced_task_runner.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/thread_task_runner_handle.h"
18 #include "base/threading/sequenced_worker_pool.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/media_galleries/fileapi/device_media_async_file_util.h"
22 #include "chrome/browser/media_galleries/fileapi/media_file_validator_factory.h"
23 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
24 #include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
25 #include "chrome/browser/media_galleries/media_file_system_registry.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/render_process_host.h"
29 #include "content/public/browser/render_view_host.h"
30 #include "content/public/browser/resource_request_info.h"
31 #include "content/public/browser/web_contents.h"
32 #include "extensions/browser/extension_system.h"
33 #include "net/url_request/url_request.h"
34 #include "storage/browser/fileapi/copy_or_move_file_validator.h"
35 #include "storage/browser/fileapi/file_stream_reader.h"
36 #include "storage/browser/fileapi/file_stream_writer.h"
37 #include "storage/browser/fileapi/file_system_context.h"
38 #include "storage/browser/fileapi/file_system_operation.h"
39 #include "storage/browser/fileapi/file_system_operation_context.h"
40 #include "storage/browser/fileapi/file_system_url.h"
41 #include "storage/browser/fileapi/native_file_util.h"
42 #include "storage/common/fileapi/file_system_types.h"
43 #include "storage/common/fileapi/file_system_util.h"
45 #if defined(OS_WIN) || defined(OS_MACOSX)
46 #include "chrome/browser/media_galleries/fileapi/itunes_file_util.h"
47 #include "chrome/browser/media_galleries/fileapi/picasa_file_util.h"
48 #endif // defined(OS_WIN) || defined(OS_MACOSX)
50 #if defined(OS_MACOSX)
51 #include "chrome/browser/media_galleries/fileapi/iphoto_file_util.h"
52 #endif // defined(OS_MACOSX)
54 using storage::FileSystemContext;
55 using storage::FileSystemURL;
57 namespace {
59 const char kMediaGalleryMountPrefix[] = "media_galleries-";
61 void OnPreferencesInit(
62 const content::RenderViewHost* rvh,
63 const extensions::Extension* extension,
64 MediaGalleryPrefId pref_id,
65 const base::Callback<void(base::File::Error result)>& callback) {
66 MediaFileSystemRegistry* registry =
67 g_browser_process->media_file_system_registry();
68 registry->RegisterMediaFileSystemForExtension(
69 content::WebContents::FromRenderViewHost(rvh), extension, pref_id,
70 callback);
73 void AttemptAutoMountOnUIThread(
74 int32 process_id,
75 int32 routing_id,
76 const std::string& storage_domain,
77 const std::string& mount_point,
78 const base::Callback<void(base::File::Error result)>& callback) {
79 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
81 content::RenderViewHost* rvh =
82 content::RenderViewHost::FromID(process_id, routing_id);
83 if (rvh) {
84 Profile* profile =
85 Profile::FromBrowserContext(rvh->GetProcess()->GetBrowserContext());
87 ExtensionService* extension_service =
88 extensions::ExtensionSystem::Get(profile)->extension_service();
89 const extensions::Extension* extension =
90 extension_service->GetExtensionById(storage_domain,
91 false /*include disabled*/);
92 std::string expected_mount_prefix =
93 MediaFileSystemBackend::ConstructMountName(
94 profile->GetPath(), storage_domain, kInvalidMediaGalleryPrefId);
95 MediaGalleryPrefId pref_id = kInvalidMediaGalleryPrefId;
96 if (extension && extension->id() == storage_domain &&
97 base::StartsWithASCII(mount_point, expected_mount_prefix, true) &&
98 base::StringToUint64(mount_point.substr(expected_mount_prefix.size()),
99 &pref_id) &&
100 pref_id != kInvalidMediaGalleryPrefId) {
101 MediaGalleriesPreferences* preferences =
102 g_browser_process->media_file_system_registry()->GetPreferences(
103 profile);
104 preferences->EnsureInitialized(
105 base::Bind(&OnPreferencesInit, rvh, extension, pref_id, callback));
106 return;
110 content::BrowserThread::PostTask(
111 content::BrowserThread::IO,
112 FROM_HERE,
113 base::Bind(callback, base::File::FILE_ERROR_NOT_FOUND));
116 } // namespace
118 const char MediaFileSystemBackend::kMediaTaskRunnerName[] =
119 "media-task-runner";
121 MediaFileSystemBackend::MediaFileSystemBackend(
122 const base::FilePath& profile_path,
123 base::SequencedTaskRunner* media_task_runner)
124 : profile_path_(profile_path),
125 media_task_runner_(media_task_runner),
126 media_path_filter_(new MediaPathFilter),
127 media_copy_or_move_file_validator_factory_(new MediaFileValidatorFactory),
128 native_media_file_util_(
129 new NativeMediaFileUtil(media_path_filter_.get())),
130 device_media_async_file_util_(
131 DeviceMediaAsyncFileUtil::Create(profile_path_,
132 APPLY_MEDIA_FILE_VALIDATION))
133 #if defined(OS_WIN) || defined(OS_MACOSX)
135 picasa_file_util_(new picasa::PicasaFileUtil(media_path_filter_.get())),
136 itunes_file_util_(new itunes::ITunesFileUtil(media_path_filter_.get()))
137 #endif // defined(OS_WIN) || defined(OS_MACOSX)
138 #if defined(OS_MACOSX)
140 iphoto_file_util_(new iphoto::IPhotoFileUtil(media_path_filter_.get()))
141 #endif // defined(OS_MACOSX)
145 MediaFileSystemBackend::~MediaFileSystemBackend() {
148 // static
149 bool MediaFileSystemBackend::CurrentlyOnMediaTaskRunnerThread() {
150 base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
151 base::SequencedWorkerPool::SequenceToken media_sequence_token =
152 pool->GetNamedSequenceToken(kMediaTaskRunnerName);
153 return pool->IsRunningSequenceOnCurrentThread(media_sequence_token);
156 // static
157 scoped_refptr<base::SequencedTaskRunner>
158 MediaFileSystemBackend::MediaTaskRunner() {
159 base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
160 base::SequencedWorkerPool::SequenceToken media_sequence_token =
161 pool->GetNamedSequenceToken(kMediaTaskRunnerName);
162 return pool->GetSequencedTaskRunner(media_sequence_token);
165 // static
166 std::string MediaFileSystemBackend::ConstructMountName(
167 const base::FilePath& profile_path,
168 const std::string& extension_id,
169 MediaGalleryPrefId pref_id) {
170 std::string name(kMediaGalleryMountPrefix);
171 name.append(profile_path.BaseName().MaybeAsASCII());
172 name.append("-");
173 name.append(extension_id);
174 name.append("-");
175 if (pref_id != kInvalidMediaGalleryPrefId)
176 name.append(base::Uint64ToString(pref_id));
177 base::ReplaceChars(name, " /", "_", &name);
178 return name;
181 // static
182 bool MediaFileSystemBackend::AttemptAutoMountForURLRequest(
183 const net::URLRequest* url_request,
184 const storage::FileSystemURL& filesystem_url,
185 const std::string& storage_domain,
186 const base::Callback<void(base::File::Error result)>& callback) {
187 if (storage_domain.empty() ||
188 filesystem_url.type() != storage::kFileSystemTypeExternal ||
189 storage_domain != filesystem_url.origin().host()) {
190 return false;
193 const base::FilePath& virtual_path = filesystem_url.path();
194 if (virtual_path.ReferencesParent())
195 return false;
196 std::vector<base::FilePath::StringType> components;
197 virtual_path.GetComponents(&components);
198 if (components.empty())
199 return false;
200 std::string mount_point = base::FilePath(components[0]).AsUTF8Unsafe();
201 if (!base::StartsWithASCII(mount_point, kMediaGalleryMountPrefix, true))
202 return false;
204 const content::ResourceRequestInfo* request_info =
205 content::ResourceRequestInfo::ForRequest(url_request);
206 if (!request_info)
207 return false;
209 content::BrowserThread::PostTask(
210 content::BrowserThread::UI,
211 FROM_HERE,
212 base::Bind(&AttemptAutoMountOnUIThread, request_info->GetChildID(),
213 request_info->GetRouteID(), storage_domain, mount_point,
214 callback));
215 return true;
218 bool MediaFileSystemBackend::CanHandleType(storage::FileSystemType type) const {
219 switch (type) {
220 case storage::kFileSystemTypeNativeMedia:
221 case storage::kFileSystemTypeDeviceMedia:
222 #if defined(OS_WIN) || defined(OS_MACOSX)
223 case storage::kFileSystemTypePicasa:
224 case storage::kFileSystemTypeItunes:
225 #endif // defined(OS_WIN) || defined(OS_MACOSX)
226 #if defined(OS_MACOSX)
227 case storage::kFileSystemTypeIphoto:
228 #endif // defined(OS_MACOSX)
229 return true;
230 default:
231 return false;
235 void MediaFileSystemBackend::Initialize(storage::FileSystemContext* context) {
238 void MediaFileSystemBackend::ResolveURL(
239 const FileSystemURL& url,
240 storage::OpenFileSystemMode mode,
241 const OpenFileSystemCallback& callback) {
242 // We never allow opening a new FileSystem via usual ResolveURL.
243 base::ThreadTaskRunnerHandle::Get()->PostTask(
244 FROM_HERE,
245 base::Bind(callback,
246 GURL(),
247 std::string(),
248 base::File::FILE_ERROR_SECURITY));
251 storage::AsyncFileUtil* MediaFileSystemBackend::GetAsyncFileUtil(
252 storage::FileSystemType type) {
253 switch (type) {
254 case storage::kFileSystemTypeNativeMedia:
255 return native_media_file_util_.get();
256 case storage::kFileSystemTypeDeviceMedia:
257 return device_media_async_file_util_.get();
258 #if defined(OS_WIN) || defined(OS_MACOSX)
259 case storage::kFileSystemTypeItunes:
260 return itunes_file_util_.get();
261 case storage::kFileSystemTypePicasa:
262 return picasa_file_util_.get();
263 #endif // defined(OS_WIN) || defined(OS_MACOSX)
264 #if defined(OS_MACOSX)
265 case storage::kFileSystemTypeIphoto:
266 return iphoto_file_util_.get();
267 #endif // defined(OS_MACOSX)
268 default:
269 NOTREACHED();
271 return NULL;
274 storage::WatcherManager* MediaFileSystemBackend::GetWatcherManager(
275 storage::FileSystemType type) {
276 return NULL;
279 storage::CopyOrMoveFileValidatorFactory*
280 MediaFileSystemBackend::GetCopyOrMoveFileValidatorFactory(
281 storage::FileSystemType type,
282 base::File::Error* error_code) {
283 DCHECK(error_code);
284 *error_code = base::File::FILE_OK;
285 switch (type) {
286 case storage::kFileSystemTypeNativeMedia:
287 case storage::kFileSystemTypeDeviceMedia:
288 case storage::kFileSystemTypeIphoto:
289 case storage::kFileSystemTypeItunes:
290 if (!media_copy_or_move_file_validator_factory_) {
291 *error_code = base::File::FILE_ERROR_SECURITY;
292 return NULL;
294 return media_copy_or_move_file_validator_factory_.get();
295 default:
296 NOTREACHED();
298 return NULL;
301 storage::FileSystemOperation* MediaFileSystemBackend::CreateFileSystemOperation(
302 const FileSystemURL& url,
303 FileSystemContext* context,
304 base::File::Error* error_code) const {
305 scoped_ptr<storage::FileSystemOperationContext> operation_context(
306 new storage::FileSystemOperationContext(context,
307 media_task_runner_.get()));
308 return storage::FileSystemOperation::Create(
309 url, context, operation_context.Pass());
312 bool MediaFileSystemBackend::SupportsStreaming(
313 const storage::FileSystemURL& url) const {
314 if (url.type() == storage::kFileSystemTypeDeviceMedia) {
315 DCHECK(device_media_async_file_util_);
316 return device_media_async_file_util_->SupportsStreaming(url);
319 return false;
322 bool MediaFileSystemBackend::HasInplaceCopyImplementation(
323 storage::FileSystemType type) const {
324 DCHECK(type == storage::kFileSystemTypeNativeMedia ||
325 type == storage::kFileSystemTypeDeviceMedia ||
326 type == storage::kFileSystemTypeItunes ||
327 type == storage::kFileSystemTypePicasa ||
328 type == storage::kFileSystemTypeIphoto);
329 return true;
332 scoped_ptr<storage::FileStreamReader>
333 MediaFileSystemBackend::CreateFileStreamReader(
334 const FileSystemURL& url,
335 int64 offset,
336 int64 max_bytes_to_read,
337 const base::Time& expected_modification_time,
338 FileSystemContext* context) const {
339 if (url.type() == storage::kFileSystemTypeDeviceMedia) {
340 DCHECK(device_media_async_file_util_);
341 scoped_ptr<storage::FileStreamReader> reader =
342 device_media_async_file_util_->GetFileStreamReader(
343 url, offset, expected_modification_time, context);
344 DCHECK(reader);
345 return reader.Pass();
348 return scoped_ptr<storage::FileStreamReader>(
349 storage::FileStreamReader::CreateForLocalFile(
350 context->default_file_task_runner(),
351 url.path(),
352 offset,
353 expected_modification_time));
356 scoped_ptr<storage::FileStreamWriter>
357 MediaFileSystemBackend::CreateFileStreamWriter(
358 const FileSystemURL& url,
359 int64 offset,
360 FileSystemContext* context) const {
361 return scoped_ptr<storage::FileStreamWriter>(
362 storage::FileStreamWriter::CreateForLocalFile(
363 context->default_file_task_runner(),
364 url.path(),
365 offset,
366 storage::FileStreamWriter::OPEN_EXISTING_FILE));
369 storage::FileSystemQuotaUtil* MediaFileSystemBackend::GetQuotaUtil() {
370 // No quota support.
371 return NULL;
374 const storage::UpdateObserverList* MediaFileSystemBackend::GetUpdateObservers(
375 storage::FileSystemType type) const {
376 return NULL;
379 const storage::ChangeObserverList* MediaFileSystemBackend::GetChangeObservers(
380 storage::FileSystemType type) const {
381 return NULL;
384 const storage::AccessObserverList* MediaFileSystemBackend::GetAccessObservers(
385 storage::FileSystemType type) const {
386 return NULL;