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