1 // Copyright (c) 2012 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 "content/browser/fileapi/fileapi_message_filter.h" 6 7 #include <string> 8 #include <vector> 9 10 #include "base/bind.h" 11 #include "base/files/file_path.h" 12 #include "base/logging.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/platform_file.h" 15 #include "base/sequenced_task_runner.h" 16 #include "base/strings/string_util.h" 17 #include "base/threading/thread.h" 18 #include "base/time/time.h" 19 #include "content/browser/child_process_security_policy_impl.h" 20 #include "content/browser/fileapi/browser_file_system_helper.h" 21 #include "content/browser/fileapi/chrome_blob_storage_context.h" 22 #include "content/browser/streams/stream_registry.h" 23 #include "content/common/fileapi/file_system_messages.h" 24 #include "content/common/fileapi/webblob_messages.h" 25 #include "content/public/browser/user_metrics.h" 26 #include "ipc/ipc_platform_file.h" 27 #include "net/base/mime_util.h" 28 #include "net/url_request/url_request_context.h" 29 #include "net/url_request/url_request_context_getter.h" 30 #include "url/gurl.h" 31 #include "webkit/browser/blob/blob_storage_controller.h" 32 #include "webkit/browser/fileapi/file_observers.h" 33 #include "webkit/browser/fileapi/file_permission_policy.h" 34 #include "webkit/browser/fileapi/file_system_context.h" 35 #include "webkit/browser/fileapi/isolated_context.h" 36 #include "webkit/browser/quota/quota_manager.h" 37 #include "webkit/common/blob/blob_data.h" 38 #include "webkit/common/blob/shareable_file_reference.h" 39 #include "webkit/common/fileapi/directory_entry.h" 40 #include "webkit/common/fileapi/file_system_types.h" 41 #include "webkit/common/fileapi/file_system_util.h" 42 43 using fileapi::FileSystemFileUtil; 44 using fileapi::FileSystemBackend; 45 using fileapi::FileSystemOperation; 46 using fileapi::FileSystemURL; 47 using fileapi::FileUpdateObserver; 48 using fileapi::UpdateObserverList; 49 using webkit_blob::BlobData; 50 using webkit_blob::BlobStorageController; 51 52 namespace content { 53 54 namespace { 55 56 void RevokeFilePermission(int child_id, const base::FilePath& path) { 57 ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile( 58 child_id, path); 59 } 60 61 } // namespace 62 63 FileAPIMessageFilter::FileAPIMessageFilter( 64 int process_id, 65 net::URLRequestContextGetter* request_context_getter, 66 fileapi::FileSystemContext* file_system_context, 67 ChromeBlobStorageContext* blob_storage_context, 68 StreamContext* stream_context) 69 : process_id_(process_id), 70 context_(file_system_context), 71 request_context_getter_(request_context_getter), 72 request_context_(NULL), 73 blob_storage_context_(blob_storage_context), 74 stream_context_(stream_context) { 75 DCHECK(context_); 76 DCHECK(request_context_getter_.get()); 77 DCHECK(blob_storage_context); 78 DCHECK(stream_context); 79 } 80 81 FileAPIMessageFilter::FileAPIMessageFilter( 82 int process_id, 83 net::URLRequestContext* request_context, 84 fileapi::FileSystemContext* file_system_context, 85 ChromeBlobStorageContext* blob_storage_context, 86 StreamContext* stream_context) 87 : process_id_(process_id), 88 context_(file_system_context), 89 request_context_(request_context), 90 blob_storage_context_(blob_storage_context), 91 stream_context_(stream_context) { 92 DCHECK(context_); 93 DCHECK(request_context_); 94 DCHECK(blob_storage_context); 95 DCHECK(stream_context); 96 } 97 98 void FileAPIMessageFilter::OnChannelConnected(int32 peer_pid) { 99 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 100 BrowserMessageFilter::OnChannelConnected(peer_pid); 101 102 if (request_context_getter_.get()) { 103 DCHECK(!request_context_); 104 request_context_ = request_context_getter_->GetURLRequestContext(); 105 request_context_getter_ = NULL; 106 DCHECK(request_context_); 107 } 108 109 operation_runner_ = context_->CreateFileSystemOperationRunner(); 110 } 111 112 void FileAPIMessageFilter::OnChannelClosing() { 113 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 114 BrowserMessageFilter::OnChannelClosing(); 115 116 // Unregister all the blob and stream URLs that are previously registered in 117 // this process. 118 for (base::hash_set<std::string>::const_iterator iter = blob_urls_.begin(); 119 iter != blob_urls_.end(); ++iter) { 120 blob_storage_context_->controller()->RemoveBlob(GURL(*iter)); 121 } 122 for (base::hash_set<std::string>::const_iterator iter = stream_urls_.begin(); 123 iter != stream_urls_.end(); ++iter) { 124 stream_context_->registry()->UnregisterStream(GURL(*iter)); 125 } 126 127 in_transit_snapshot_files_.clear(); 128 129 // Close all files that are previously OpenFile()'ed in this process. 130 if (!on_close_callbacks_.IsEmpty()) { 131 DLOG(INFO) 132 << "File API: Renderer process shut down before NotifyCloseFile" 133 << " for " << on_close_callbacks_.size() << " files opened in PPAPI"; 134 } 135 136 for (OnCloseCallbackMap::iterator itr(&on_close_callbacks_); 137 !itr.IsAtEnd(); itr.Advance()) { 138 const base::Closure* callback = itr.GetCurrentValue(); 139 DCHECK(callback); 140 if (!callback->is_null()) 141 callback->Run(); 142 } 143 144 on_close_callbacks_.Clear(); 145 operation_runner_.reset(); 146 operations_.clear(); 147 } 148 149 base::TaskRunner* FileAPIMessageFilter::OverrideTaskRunnerForMessage( 150 const IPC::Message& message) { 151 if (message.type() == FileSystemHostMsg_SyncGetPlatformPath::ID) 152 return context_->default_file_task_runner(); 153 return NULL; 154 } 155 156 bool FileAPIMessageFilter::OnMessageReceived( 157 const IPC::Message& message, bool* message_was_ok) { 158 *message_was_ok = true; 159 bool handled = true; 160 IPC_BEGIN_MESSAGE_MAP_EX(FileAPIMessageFilter, message, *message_was_ok) 161 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Open, OnOpen) 162 IPC_MESSAGE_HANDLER(FileSystemHostMsg_DeleteFileSystem, OnDeleteFileSystem) 163 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Move, OnMove) 164 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Copy, OnCopy) 165 IPC_MESSAGE_HANDLER(FileSystemMsg_Remove, OnRemove) 166 IPC_MESSAGE_HANDLER(FileSystemHostMsg_ReadMetadata, OnReadMetadata) 167 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Create, OnCreate) 168 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Exists, OnExists) 169 IPC_MESSAGE_HANDLER(FileSystemHostMsg_ReadDirectory, OnReadDirectory) 170 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Write, OnWrite) 171 IPC_MESSAGE_HANDLER(FileSystemHostMsg_Truncate, OnTruncate) 172 IPC_MESSAGE_HANDLER(FileSystemHostMsg_TouchFile, OnTouchFile) 173 IPC_MESSAGE_HANDLER(FileSystemHostMsg_CancelWrite, OnCancel) 174 IPC_MESSAGE_HANDLER(FileSystemHostMsg_OpenFile, OnOpenFile) 175 IPC_MESSAGE_HANDLER(FileSystemHostMsg_NotifyCloseFile, OnNotifyCloseFile) 176 IPC_MESSAGE_HANDLER(FileSystemHostMsg_CreateSnapshotFile, 177 OnCreateSnapshotFile) 178 IPC_MESSAGE_HANDLER(FileSystemHostMsg_DidReceiveSnapshotFile, 179 OnDidReceiveSnapshotFile) 180 IPC_MESSAGE_HANDLER(FileSystemHostMsg_WillUpdate, OnWillUpdate) 181 IPC_MESSAGE_HANDLER(FileSystemHostMsg_DidUpdate, OnDidUpdate) 182 IPC_MESSAGE_HANDLER(FileSystemHostMsg_SyncGetPlatformPath, 183 OnSyncGetPlatformPath) 184 IPC_MESSAGE_HANDLER(BlobHostMsg_StartBuilding, OnStartBuildingBlob) 185 IPC_MESSAGE_HANDLER(BlobHostMsg_AppendBlobDataItem, 186 OnAppendBlobDataItemToBlob) 187 IPC_MESSAGE_HANDLER(BlobHostMsg_SyncAppendSharedMemory, 188 OnAppendSharedMemoryToBlob) 189 IPC_MESSAGE_HANDLER(BlobHostMsg_FinishBuilding, OnFinishBuildingBlob) 190 IPC_MESSAGE_HANDLER(BlobHostMsg_Clone, OnCloneBlob) 191 IPC_MESSAGE_HANDLER(BlobHostMsg_Remove, OnRemoveBlob) 192 IPC_MESSAGE_HANDLER(StreamHostMsg_StartBuilding, OnStartBuildingStream) 193 IPC_MESSAGE_HANDLER(StreamHostMsg_AppendBlobDataItem, 194 OnAppendBlobDataItemToStream) 195 IPC_MESSAGE_HANDLER(StreamHostMsg_SyncAppendSharedMemory, 196 OnAppendSharedMemoryToStream) 197 IPC_MESSAGE_HANDLER(StreamHostMsg_FinishBuilding, OnFinishBuildingStream) 198 IPC_MESSAGE_HANDLER(StreamHostMsg_Clone, OnCloneStream) 199 IPC_MESSAGE_HANDLER(StreamHostMsg_Remove, OnRemoveStream) 200 IPC_MESSAGE_UNHANDLED(handled = false) 201 IPC_END_MESSAGE_MAP_EX() 202 return handled; 203 } 204 205 FileAPIMessageFilter::~FileAPIMessageFilter() {} 206 207 void FileAPIMessageFilter::BadMessageReceived() { 208 RecordAction(UserMetricsAction("BadMessageTerminate_FAMF")); 209 BrowserMessageFilter::BadMessageReceived(); 210 } 211 212 void FileAPIMessageFilter::OnOpen( 213 int request_id, const GURL& origin_url, fileapi::FileSystemType type, 214 int64 requested_size, bool create) { 215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 216 if (type == fileapi::kFileSystemTypeTemporary) { 217 RecordAction(UserMetricsAction("OpenFileSystemTemporary")); 218 } else if (type == fileapi::kFileSystemTypePersistent) { 219 RecordAction(UserMetricsAction("OpenFileSystemPersistent")); 220 } 221 // TODO(kinuko): Use this mode for IPC too. 222 fileapi::OpenFileSystemMode mode = 223 create ? fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT 224 : fileapi::OPEN_FILE_SYSTEM_FAIL_IF_NONEXISTENT; 225 context_->OpenFileSystem(origin_url, type, mode, base::Bind( 226 &FileAPIMessageFilter::DidOpenFileSystem, this, request_id)); 227 } 228 229 void FileAPIMessageFilter::OnDeleteFileSystem( 230 int request_id, 231 const GURL& origin_url, 232 fileapi::FileSystemType type) { 233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 234 context_->DeleteFileSystem(origin_url, type, base::Bind( 235 &FileAPIMessageFilter::DidDeleteFileSystem, this, request_id)); 236 } 237 238 void FileAPIMessageFilter::OnMove( 239 int request_id, const GURL& src_path, const GURL& dest_path) { 240 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 241 base::PlatformFileError error; 242 FileSystemURL src_url(context_->CrackURL(src_path)); 243 FileSystemURL dest_url(context_->CrackURL(dest_path)); 244 const int src_permissions = 245 fileapi::kReadFilePermissions | fileapi::kWriteFilePermissions; 246 if (!HasPermissionsForFile(src_url, src_permissions, &error) || 247 !HasPermissionsForFile( 248 dest_url, fileapi::kCreateFilePermissions, &error)) { 249 Send(new FileSystemMsg_DidFail(request_id, error)); 250 return; 251 } 252 253 operations_[request_id] = operation_runner()->Move( 254 src_url, dest_url, 255 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id)); 256 } 257 258 void FileAPIMessageFilter::OnCopy( 259 int request_id, const GURL& src_path, const GURL& dest_path) { 260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 261 base::PlatformFileError error; 262 FileSystemURL src_url(context_->CrackURL(src_path)); 263 FileSystemURL dest_url(context_->CrackURL(dest_path)); 264 if (!HasPermissionsForFile(src_url, fileapi::kReadFilePermissions, &error) || 265 !HasPermissionsForFile( 266 dest_url, fileapi::kCreateFilePermissions, &error)) { 267 Send(new FileSystemMsg_DidFail(request_id, error)); 268 return; 269 } 270 271 operations_[request_id] = operation_runner()->Copy( 272 src_url, dest_url, 273 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id)); 274 } 275 276 void FileAPIMessageFilter::OnRemove( 277 int request_id, const GURL& path, bool recursive) { 278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 279 base::PlatformFileError error; 280 FileSystemURL url(context_->CrackURL(path)); 281 if (!HasPermissionsForFile(url, fileapi::kWriteFilePermissions, &error)) { 282 Send(new FileSystemMsg_DidFail(request_id, error)); 283 return; 284 } 285 286 operations_[request_id] = operation_runner()->Remove( 287 url, recursive, 288 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id)); 289 } 290 291 void FileAPIMessageFilter::OnReadMetadata( 292 int request_id, const GURL& path) { 293 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 294 base::PlatformFileError error; 295 FileSystemURL url(context_->CrackURL(path)); 296 if (!HasPermissionsForFile(url, fileapi::kReadFilePermissions, &error)) { 297 Send(new FileSystemMsg_DidFail(request_id, error)); 298 return; 299 } 300 301 operations_[request_id] = operation_runner()->GetMetadata( 302 url, base::Bind(&FileAPIMessageFilter::DidGetMetadata, this, request_id)); 303 } 304 305 void FileAPIMessageFilter::OnCreate( 306 int request_id, const GURL& path, bool exclusive, 307 bool is_directory, bool recursive) { 308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 309 base::PlatformFileError error; 310 FileSystemURL url(context_->CrackURL(path)); 311 if (!HasPermissionsForFile(url, fileapi::kCreateFilePermissions, &error)) { 312 Send(new FileSystemMsg_DidFail(request_id, error)); 313 return; 314 } 315 316 if (is_directory) { 317 operations_[request_id] = operation_runner()->CreateDirectory( 318 url, exclusive, recursive, 319 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id)); 320 } else { 321 operations_[request_id] = operation_runner()->CreateFile( 322 url, exclusive, 323 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id)); 324 } 325 } 326 327 void FileAPIMessageFilter::OnExists( 328 int request_id, const GURL& path, bool is_directory) { 329 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 330 base::PlatformFileError error; 331 FileSystemURL url(context_->CrackURL(path)); 332 if (!HasPermissionsForFile(url, fileapi::kReadFilePermissions, &error)) { 333 Send(new FileSystemMsg_DidFail(request_id, error)); 334 return; 335 } 336 337 if (is_directory) { 338 operations_[request_id] = operation_runner()->DirectoryExists( 339 url, 340 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id)); 341 } else { 342 operations_[request_id] = operation_runner()->FileExists( 343 url, 344 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id)); 345 } 346 } 347 348 void FileAPIMessageFilter::OnReadDirectory( 349 int request_id, const GURL& path) { 350 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 351 base::PlatformFileError error; 352 FileSystemURL url(context_->CrackURL(path)); 353 if (!HasPermissionsForFile(url, fileapi::kReadFilePermissions, &error)) { 354 Send(new FileSystemMsg_DidFail(request_id, error)); 355 return; 356 } 357 358 operations_[request_id] = operation_runner()->ReadDirectory( 359 url, base::Bind(&FileAPIMessageFilter::DidReadDirectory, 360 this, request_id)); 361 } 362 363 void FileAPIMessageFilter::OnWrite( 364 int request_id, 365 const GURL& path, 366 const GURL& blob_url, 367 int64 offset) { 368 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 369 if (!request_context_) { 370 // We can't write w/o a request context, trying to do so will crash. 371 NOTREACHED(); 372 return; 373 } 374 375 FileSystemURL url(context_->CrackURL(path)); 376 base::PlatformFileError error; 377 if (!HasPermissionsForFile(url, fileapi::kWriteFilePermissions, &error)) { 378 Send(new FileSystemMsg_DidFail(request_id, error)); 379 return; 380 } 381 382 operations_[request_id] = operation_runner()->Write( 383 request_context_, url, blob_url, offset, 384 base::Bind(&FileAPIMessageFilter::DidWrite, this, request_id)); 385 } 386 387 void FileAPIMessageFilter::OnTruncate( 388 int request_id, 389 const GURL& path, 390 int64 length) { 391 base::PlatformFileError error; 392 FileSystemURL url(context_->CrackURL(path)); 393 if (!HasPermissionsForFile(url, fileapi::kWriteFilePermissions, &error)) { 394 Send(new FileSystemMsg_DidFail(request_id, error)); 395 return; 396 } 397 398 operations_[request_id] = operation_runner()->Truncate( 399 url, length, 400 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id)); 401 } 402 403 void FileAPIMessageFilter::OnTouchFile( 404 int request_id, 405 const GURL& path, 406 const base::Time& last_access_time, 407 const base::Time& last_modified_time) { 408 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 409 FileSystemURL url(context_->CrackURL(path)); 410 base::PlatformFileError error; 411 if (!HasPermissionsForFile(url, fileapi::kCreateFilePermissions, &error)) { 412 Send(new FileSystemMsg_DidFail(request_id, error)); 413 return; 414 } 415 416 operations_[request_id] = operation_runner()->TouchFile( 417 url, last_access_time, last_modified_time, 418 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id)); 419 } 420 421 void FileAPIMessageFilter::OnCancel( 422 int request_id, 423 int request_id_to_cancel) { 424 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 425 426 OperationsMap::iterator found = operations_.find(request_id_to_cancel); 427 if (found != operations_.end()) { 428 // The cancel will eventually send both the write failure and the cancel 429 // success. 430 operation_runner()->Cancel( 431 found->second, 432 base::Bind(&FileAPIMessageFilter::DidFinish, this, request_id)); 433 } else { 434 // The write already finished; report that we failed to stop it. 435 Send(new FileSystemMsg_DidFail( 436 request_id, base::PLATFORM_FILE_ERROR_INVALID_OPERATION)); 437 } 438 } 439 440 void FileAPIMessageFilter::OnOpenFile( 441 int request_id, const GURL& path, int file_flags) { 442 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 443 base::PlatformFileError error; 444 const int open_permissions = file_flags & fileapi::kOpenPepperFilePermissions; 445 FileSystemURL url(context_->CrackURL(path)); 446 if (!HasPermissionsForFile(url, open_permissions, &error)) { 447 Send(new FileSystemMsg_DidFail(request_id, error)); 448 return; 449 } 450 451 quota::QuotaLimitType quota_policy = quota::kQuotaLimitTypeUnknown; 452 quota::QuotaManagerProxy* quota_manager_proxy = 453 context_->quota_manager_proxy(); 454 CHECK(quota_manager_proxy); 455 CHECK(quota_manager_proxy->quota_manager()); 456 457 if (quota_manager_proxy->quota_manager()->IsStorageUnlimited( 458 url.origin(), FileSystemTypeToQuotaStorageType(url.type()))) { 459 quota_policy = quota::kQuotaLimitTypeUnlimited; 460 } else { 461 quota_policy = quota::kQuotaLimitTypeLimited; 462 } 463 464 operations_[request_id] = operation_runner()->OpenFile( 465 url, open_permissions, PeerHandle(), 466 base::Bind(&FileAPIMessageFilter::DidOpenFile, this, request_id, 467 quota_policy)); 468 } 469 470 void FileAPIMessageFilter::OnNotifyCloseFile(int file_open_id) { 471 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 472 473 // Remove |file_open_id| from the map of |on_close_callback|s. 474 // It must only be called for a ID that is successfully opened and enrolled in 475 // DidOpenFile. 476 base::Closure* on_close_callback = on_close_callbacks_.Lookup(file_open_id); 477 if (on_close_callback && !on_close_callback->is_null()) { 478 on_close_callback->Run(); 479 on_close_callbacks_.Remove(file_open_id); 480 } 481 } 482 483 void FileAPIMessageFilter::OnWillUpdate(const GURL& path) { 484 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 485 FileSystemURL url(context_->CrackURL(path)); 486 if (!url.is_valid()) 487 return; 488 const UpdateObserverList* observers = 489 context_->GetUpdateObservers(url.type()); 490 if (!observers) 491 return; 492 observers->Notify(&FileUpdateObserver::OnStartUpdate, MakeTuple(url)); 493 } 494 495 void FileAPIMessageFilter::OnDidUpdate(const GURL& path, int64 delta) { 496 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 497 FileSystemURL url(context_->CrackURL(path)); 498 if (!url.is_valid()) 499 return; 500 const UpdateObserverList* observers = 501 context_->GetUpdateObservers(url.type()); 502 if (!observers) 503 return; 504 observers->Notify(&FileUpdateObserver::OnUpdate, MakeTuple(url, delta)); 505 observers->Notify(&FileUpdateObserver::OnEndUpdate, MakeTuple(url)); 506 } 507 508 void FileAPIMessageFilter::OnSyncGetPlatformPath( 509 const GURL& path, base::FilePath* platform_path) { 510 SyncGetPlatformPath(context_, process_id_, path, platform_path); 511 } 512 513 void FileAPIMessageFilter::OnCreateSnapshotFile( 514 int request_id, const GURL& path) { 515 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 516 FileSystemURL url(context_->CrackURL(path)); 517 518 // Make sure if this file can be read by the renderer as this is 519 // called when the renderer is about to create a new File object 520 // (for reading the file). 521 base::PlatformFileError error; 522 if (!HasPermissionsForFile(url, fileapi::kReadFilePermissions, &error)) { 523 Send(new FileSystemMsg_DidFail(request_id, error)); 524 return; 525 } 526 527 operations_[request_id] = operation_runner()->CreateSnapshotFile( 528 url, 529 base::Bind(&FileAPIMessageFilter::DidCreateSnapshot, 530 this, request_id, url)); 531 } 532 533 void FileAPIMessageFilter::OnDidReceiveSnapshotFile(int request_id) { 534 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 535 in_transit_snapshot_files_.erase(request_id); 536 } 537 538 void FileAPIMessageFilter::OnStartBuildingBlob(const GURL& url) { 539 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 540 blob_storage_context_->controller()->StartBuildingBlob(url); 541 blob_urls_.insert(url.spec()); 542 } 543 544 void FileAPIMessageFilter::OnAppendBlobDataItemToBlob( 545 const GURL& url, const BlobData::Item& item) { 546 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 547 if (item.type() == BlobData::Item::TYPE_FILE_FILESYSTEM) { 548 base::PlatformFileError error; 549 FileSystemURL filesystem_url(context_->CrackURL(item.url())); 550 if (!HasPermissionsForFile(filesystem_url, 551 fileapi::kReadFilePermissions, &error)) { 552 OnRemoveBlob(url); 553 return; 554 } 555 } 556 if (item.type() == BlobData::Item::TYPE_FILE && 557 !ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile( 558 process_id_, item.path())) { 559 OnRemoveBlob(url); 560 return; 561 } 562 if (item.length() == 0) { 563 BadMessageReceived(); 564 return; 565 } 566 blob_storage_context_->controller()->AppendBlobDataItem(url, item); 567 } 568 569 void FileAPIMessageFilter::OnAppendSharedMemoryToBlob( 570 const GURL& url, base::SharedMemoryHandle handle, size_t buffer_size) { 571 DCHECK(base::SharedMemory::IsHandleValid(handle)); 572 if (!buffer_size) { 573 BadMessageReceived(); 574 return; 575 } 576 #if defined(OS_WIN) 577 base::SharedMemory shared_memory(handle, true, PeerHandle()); 578 #else 579 base::SharedMemory shared_memory(handle, true); 580 #endif 581 if (!shared_memory.Map(buffer_size)) { 582 OnRemoveBlob(url); 583 return; 584 } 585 586 BlobData::Item item; 587 item.SetToSharedBytes(static_cast<char*>(shared_memory.memory()), 588 buffer_size); 589 blob_storage_context_->controller()->AppendBlobDataItem(url, item); 590 } 591 592 void FileAPIMessageFilter::OnFinishBuildingBlob( 593 const GURL& url, const std::string& content_type) { 594 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 595 blob_storage_context_->controller()->FinishBuildingBlob(url, content_type); 596 } 597 598 void FileAPIMessageFilter::OnCloneBlob( 599 const GURL& url, const GURL& src_url) { 600 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 601 blob_storage_context_->controller()->CloneBlob(url, src_url); 602 blob_urls_.insert(url.spec()); 603 } 604 605 void FileAPIMessageFilter::OnRemoveBlob(const GURL& url) { 606 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 607 blob_storage_context_->controller()->RemoveBlob(url); 608 blob_urls_.erase(url.spec()); 609 } 610 611 void FileAPIMessageFilter::OnStartBuildingStream( 612 const GURL& url, const std::string& content_type) { 613 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 614 // Only an internal Blob URL is expected here. See the BlobURL of the Blink. 615 if (!StartsWithASCII( 616 url.path(), "blobinternal%3A///", true /* case_sensitive */)) { 617 NOTREACHED() << "Malformed Stream URL: " << url.spec(); 618 BadMessageReceived(); 619 return; 620 } 621 // Use an empty security origin for now. Stream accepts a security origin 622 // but how it's handled is not fixed yet. 623 new Stream(stream_context_->registry(), 624 NULL /* write_observer */, 625 url); 626 stream_urls_.insert(url.spec()); 627 } 628 629 void FileAPIMessageFilter::OnAppendBlobDataItemToStream( 630 const GURL& url, const BlobData::Item& item) { 631 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 632 633 scoped_refptr<Stream> stream(GetStreamForURL(url)); 634 if (!stream.get()) { 635 NOTREACHED(); 636 return; 637 } 638 639 // Data for stream is delivered as TYPE_BYTES item. 640 if (item.type() != BlobData::Item::TYPE_BYTES) { 641 BadMessageReceived(); 642 return; 643 } 644 stream->AddData(item.bytes(), item.length()); 645 } 646 647 void FileAPIMessageFilter::OnAppendSharedMemoryToStream( 648 const GURL& url, base::SharedMemoryHandle handle, size_t buffer_size) { 649 DCHECK(base::SharedMemory::IsHandleValid(handle)); 650 if (!buffer_size) { 651 BadMessageReceived(); 652 return; 653 } 654 #if defined(OS_WIN) 655 base::SharedMemory shared_memory(handle, true, PeerHandle()); 656 #else 657 base::SharedMemory shared_memory(handle, true); 658 #endif 659 if (!shared_memory.Map(buffer_size)) { 660 OnRemoveStream(url); 661 return; 662 } 663 664 scoped_refptr<Stream> stream(GetStreamForURL(url)); 665 if (!stream.get()) { 666 NOTREACHED(); 667 return; 668 } 669 670 stream->AddData(static_cast<char*>(shared_memory.memory()), buffer_size); 671 } 672 673 void FileAPIMessageFilter::OnFinishBuildingStream(const GURL& url) { 674 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 675 scoped_refptr<Stream> stream(GetStreamForURL(url)); 676 if (stream.get()) 677 stream->Finalize(); 678 else 679 NOTREACHED(); 680 } 681 682 void FileAPIMessageFilter::OnCloneStream( 683 const GURL& url, const GURL& src_url) { 684 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 685 if (!GetStreamForURL(src_url)) { 686 NOTREACHED(); 687 return; 688 } 689 690 stream_context_->registry()->CloneStream(url, src_url); 691 stream_urls_.insert(url.spec()); 692 } 693 694 void FileAPIMessageFilter::OnRemoveStream(const GURL& url) { 695 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 696 697 if (!GetStreamForURL(url).get()) { 698 NOTREACHED(); 699 return; 700 } 701 702 stream_context_->registry()->UnregisterStream(url); 703 stream_urls_.erase(url.spec()); 704 } 705 706 void FileAPIMessageFilter::DidFinish(int request_id, 707 base::PlatformFileError result) { 708 if (result == base::PLATFORM_FILE_OK) 709 Send(new FileSystemMsg_DidSucceed(request_id)); 710 else 711 Send(new FileSystemMsg_DidFail(request_id, result)); 712 operations_.erase(request_id); 713 } 714 715 void FileAPIMessageFilter::DidGetMetadata( 716 int request_id, 717 base::PlatformFileError result, 718 const base::PlatformFileInfo& info) { 719 if (result == base::PLATFORM_FILE_OK) 720 Send(new FileSystemMsg_DidReadMetadata(request_id, info)); 721 else 722 Send(new FileSystemMsg_DidFail(request_id, result)); 723 operations_.erase(request_id); 724 } 725 726 void FileAPIMessageFilter::DidReadDirectory( 727 int request_id, 728 base::PlatformFileError result, 729 const std::vector<fileapi::DirectoryEntry>& entries, 730 bool has_more) { 731 if (result == base::PLATFORM_FILE_OK) 732 Send(new FileSystemMsg_DidReadDirectory(request_id, entries, has_more)); 733 else 734 Send(new FileSystemMsg_DidFail(request_id, result)); 735 operations_.erase(request_id); 736 } 737 738 void FileAPIMessageFilter::DidOpenFile(int request_id, 739 quota::QuotaLimitType quota_policy, 740 base::PlatformFileError result, 741 base::PlatformFile file, 742 const base::Closure& on_close_callback, 743 base::ProcessHandle peer_handle) { 744 if (result == base::PLATFORM_FILE_OK) { 745 IPC::PlatformFileForTransit file_for_transit = 746 file != base::kInvalidPlatformFileValue ? 747 IPC::GetFileHandleForProcess(file, peer_handle, true) : 748 IPC::InvalidPlatformFileForTransit(); 749 int file_open_id = on_close_callbacks_.Add( 750 new base::Closure(on_close_callback)); 751 752 Send(new FileSystemMsg_DidOpenFile(request_id, 753 file_for_transit, 754 file_open_id, 755 quota_policy)); 756 } else { 757 Send(new FileSystemMsg_DidFail(request_id, 758 result)); 759 } 760 operations_.erase(request_id); 761 } 762 763 void FileAPIMessageFilter::DidWrite(int request_id, 764 base::PlatformFileError result, 765 int64 bytes, 766 bool complete) { 767 if (result == base::PLATFORM_FILE_OK) { 768 Send(new FileSystemMsg_DidWrite(request_id, bytes, complete)); 769 if (complete) 770 operations_.erase(request_id); 771 } else { 772 Send(new FileSystemMsg_DidFail(request_id, result)); 773 operations_.erase(request_id); 774 } 775 } 776 777 void FileAPIMessageFilter::DidOpenFileSystem(int request_id, 778 base::PlatformFileError result, 779 const std::string& name, 780 const GURL& root) { 781 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 782 if (result == base::PLATFORM_FILE_OK) { 783 DCHECK(root.is_valid()); 784 Send(new FileSystemMsg_DidOpenFileSystem(request_id, name, root)); 785 } else { 786 Send(new FileSystemMsg_DidFail(request_id, result)); 787 } 788 // For OpenFileSystem we do not create a new operation, so no unregister here. 789 } 790 791 void FileAPIMessageFilter::DidDeleteFileSystem( 792 int request_id, 793 base::PlatformFileError result) { 794 if (result == base::PLATFORM_FILE_OK) 795 Send(new FileSystemMsg_DidSucceed(request_id)); 796 else 797 Send(new FileSystemMsg_DidFail(request_id, result)); 798 // For DeleteFileSystem we do not create a new operation, 799 // so no unregister here. 800 } 801 802 void FileAPIMessageFilter::DidCreateSnapshot( 803 int request_id, 804 const fileapi::FileSystemURL& url, 805 base::PlatformFileError result, 806 const base::PlatformFileInfo& info, 807 const base::FilePath& platform_path, 808 const scoped_refptr<webkit_blob::ShareableFileReference>& snapshot_file) { 809 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 810 operations_.erase(request_id); 811 812 if (result != base::PLATFORM_FILE_OK) { 813 Send(new FileSystemMsg_DidFail(request_id, result)); 814 return; 815 } 816 817 scoped_refptr<webkit_blob::ShareableFileReference> file_ref = snapshot_file; 818 if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile( 819 process_id_, platform_path)) { 820 // Give per-file read permission to the snapshot file if it hasn't it yet. 821 // In order for the renderer to be able to read the file via File object, 822 // it must be granted per-file read permission for the file's platform 823 // path. By now, it has already been verified that the renderer has 824 // sufficient permissions to read the file, so giving per-file permission 825 // here must be safe. 826 ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile( 827 process_id_, platform_path); 828 829 // Revoke all permissions for the file when the last ref of the file 830 // is dropped. 831 if (!file_ref.get()) { 832 // Create a reference for temporary permission handling. 833 file_ref = webkit_blob::ShareableFileReference::GetOrCreate( 834 platform_path, 835 webkit_blob::ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE, 836 context_->default_file_task_runner()); 837 } 838 file_ref->AddFinalReleaseCallback( 839 base::Bind(&RevokeFilePermission, process_id_)); 840 } 841 842 if (file_ref.get()) { 843 // This ref is held until OnDidReceiveSnapshotFile is called. 844 in_transit_snapshot_files_[request_id] = file_ref; 845 } 846 847 // Return the file info and platform_path. 848 Send(new FileSystemMsg_DidCreateSnapshotFile( 849 request_id, info, platform_path)); 850 } 851 852 bool FileAPIMessageFilter::HasPermissionsForFile( 853 const FileSystemURL& url, int permissions, base::PlatformFileError* error) { 854 return CheckFileSystemPermissionsForProcess(context_, process_id_, url, 855 permissions, error); 856 } 857 858 scoped_refptr<Stream> FileAPIMessageFilter::GetStreamForURL(const GURL& url) { 859 return stream_context_->registry()->GetStream(url); 860 } 861 862 } // namespace content 863