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