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