| Index: content/browser/loader/temporary_file_manager.cc
|
| diff --git a/content/browser/loader/temporary_file_manager.cc b/content/browser/loader/temporary_file_manager.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8979270a48799c84bff4eea8308dad75038fc563
|
| --- /dev/null
|
| +++ b/content/browser/loader/temporary_file_manager.cc
|
| @@ -0,0 +1,154 @@
|
| +// Copyright 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "content/browser/loader/temporary_file_manager.h"
|
| +
|
| +#include "base/files/file_util_proxy.h"
|
| +#include "content/browser/child_process_security_policy_impl.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +#include "net/base/file_stream.h"
|
| +#include "webkit/common/blob/shareable_file_reference.h"
|
| +
|
| +using webkit_blob::ShareableFileReference;
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +
|
| +void RemoveDownloadFileFromChildSecurityPolicy(int child_id,
|
| + const base::FilePath& path) {
|
| + ChildProcessSecurityPolicyImpl::GetInstance()->RevokeAllPermissionsForFile(
|
| + child_id, path);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +struct TemporaryFileManager::PendingTemporary {
|
| + int child_id;
|
| + int request_id;
|
| + TemporaryFileStreamFactory::Callback callback;
|
| + bool cancelled;
|
| +
|
| + PendingTemporary(int child_id,
|
| + int request_id,
|
| + const TemporaryFileStreamFactory::Callback& callback)
|
| + : child_id(child_id),
|
| + request_id(request_id),
|
| + callback(callback),
|
| + cancelled(false) {
|
| + }
|
| +};
|
| +
|
| +TemporaryFileManager::TemporaryFileManager() : weak_factory_(this) {
|
| +}
|
| +
|
| +TemporaryFileManager::~TemporaryFileManager() {
|
| +}
|
| +
|
| +void TemporaryFileManager::UnregisterDownloadedTempFile(
|
| + int child_id, int request_id) {
|
| + DeletableFilesMap& map = registered_temp_files_[child_id];
|
| + DeletableFilesMap::iterator found = map.find(request_id);
|
| + if (found != map.end()) {
|
| + map.erase(found);
|
| + }
|
| +
|
| + // Cancel any pending requests.
|
| + PendingTemporaryMap::iterator found_pending =
|
| + pending_temporary_map_.find(GlobalRequestID(child_id, request_id));
|
| + if (found_pending != pending_temporary_map_.end()) {
|
| + found_pending->second->cancelled = true;
|
| + }
|
| +
|
| + // Note that we don't remove the security bits here. This will be done
|
| + // when all file refs are deleted (see RegisterDownloadedTempFile).
|
| +}
|
| +
|
| +void TemporaryFileManager::UnregisterFilesForChild(int child_id) {
|
| + registered_temp_files_.erase(child_id);
|
| +
|
| + // Cancel all pending requests.
|
| + PendingTemporaryMap::iterator iter =
|
| + pending_temporary_map_.lower_bound(GlobalRequestID(child_id, -1));
|
| + PendingTemporaryMap::iterator stop =
|
| + pending_temporary_map_.lower_bound(GlobalRequestID(child_id + 1, -1));
|
| + for (; iter != stop; ++iter) {
|
| + DCHECK_EQ(child_id, iter->first.child_id);
|
| + iter->second->cancelled = true;
|
| + }
|
| +}
|
| +
|
| +void TemporaryFileManager::CreateTemporary(
|
| + int child_id,
|
| + int request_id,
|
| + const TemporaryFileStreamFactory::Callback& callback) {
|
| + PendingTemporary* pending =
|
| + new PendingTemporary(child_id, request_id, callback);
|
| + pending_temporary_map_[GlobalRequestID(child_id, request_id)] = pending;
|
| +
|
| + base::FileUtilProxy::CreateTemporary(
|
| + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
|
| + base::PLATFORM_FILE_ASYNC,
|
| + base::Bind(&TemporaryFileManager::DidCreateTemporaryFile, AsWeakPtr(),
|
| + base::Owned(pending)));
|
| +}
|
| +
|
| +void TemporaryFileManager::DidCreateTemporaryFile(
|
| + TemporaryFileManager::PendingTemporary* pending,
|
| + base::PlatformFileError error_code,
|
| + base::PassPlatformFile file_handle,
|
| + const base::FilePath& file_path) {
|
| + DCHECK_EQ(pending,
|
| + pending_temporary_map_[GlobalRequestID(pending->child_id,
|
| + pending->request_id)]);
|
| + pending_temporary_map_.erase(GlobalRequestID(pending->child_id,
|
| + pending->request_id));
|
| +
|
| + if (error_code != base::PLATFORM_FILE_OK) {
|
| + if (!pending->cancelled)
|
| + pending->callback.Run(error_code, scoped_ptr<net::FileStream>(), NULL);
|
| + return;
|
| + }
|
| +
|
| + // Cancelled or not, create the deletable_file so the temporary is cleaned up.
|
| + scoped_refptr<ShareableFileReference> deletable_file =
|
| + ShareableFileReference::GetOrCreate(
|
| + file_path,
|
| + ShareableFileReference::DELETE_ON_FINAL_RELEASE,
|
| + BrowserThread::GetMessageLoopProxyForThread(
|
| + BrowserThread::FILE).get());
|
| +
|
| + if (pending->cancelled)
|
| + return;
|
| +
|
| + scoped_ptr<net::FileStream> file_stream(new net::FileStream(
|
| + file_handle.ReleaseValue(),
|
| + base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_ASYNC,
|
| + NULL));
|
| +
|
| + RegisterDownloadedTempFile(pending->child_id, pending->request_id,
|
| + deletable_file.get());
|
| + pending->callback.Run(error_code, file_stream.Pass(), deletable_file);
|
| +}
|
| +
|
| +void TemporaryFileManager::RegisterDownloadedTempFile(
|
| + int child_id, int request_id, ShareableFileReference* reference) {
|
| + registered_temp_files_[child_id][request_id] = reference;
|
| + ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
|
| + child_id, reference->path());
|
| +
|
| + // When the temp file is deleted, revoke permissions that the renderer has
|
| + // to that file. This covers an edge case where the file is deleted and then
|
| + // the same name is re-used for some other purpose, we don't want the old
|
| + // renderer to still have access to it.
|
| + //
|
| + // We do this when the file is deleted because the renderer can take a blob
|
| + // reference to the temp file that outlives the url loaded that it was
|
| + // loaded with to keep the file (and permissions) alive.
|
| + reference->AddFinalReleaseCallback(
|
| + base::Bind(&RemoveDownloadFileFromChildSecurityPolicy,
|
| + child_id));
|
| +}
|
| +
|
| +} // namespace content
|
|
|