blob: 351c92ca75a9658c56ba5081418113e91887b415 [file] [log] [blame]
// Copyright (c) 2011 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 "chrome/browser/extensions/extension_page_capture_api.h"
#include "base/bind.h"
#include "base/file_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/extensions/extension_messages.h"
#include "content/browser/child_process_security_policy.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/browser/download/mhtml_generation_manager.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
using content::BrowserThread;
// Error messages.
const char* const kFileTooBigError = "The MHTML file generated is too big.";
const char* const kMHTMLGenerationFailedError = "Failed to generate MHTML.";
const char* const kSizeRetrievalError =
"Failed to retrieve size of generated MHTML.";
const char* const kTemporaryFileError = "Failed to create a temporary file.";
const char* const kTabClosedError = "Cannot find the tab for thie request.";
static PageCaptureSaveAsMHTMLFunction::TestDelegate* test_delegate_ = NULL;
PageCaptureSaveAsMHTMLFunction::PageCaptureSaveAsMHTMLFunction() : tab_id_(0) {
}
PageCaptureSaveAsMHTMLFunction::~PageCaptureSaveAsMHTMLFunction() {
}
void PageCaptureSaveAsMHTMLFunction::SetTestDelegate(TestDelegate* delegate) {
test_delegate_ = delegate;
}
bool PageCaptureSaveAsMHTMLFunction::RunImpl() {
DictionaryValue* args;
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
if (!args->HasKey("tabId"))
return false;
EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id_));
AddRef(); // Balanced in ReturnFailure/ReturnSuccess()
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(this,
&PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile));
return true;
}
bool PageCaptureSaveAsMHTMLFunction::OnMessageReceivedFromRenderView(
const IPC::Message& message) {
if (message.type() != ExtensionHostMsg_ResponseAck::ID)
return false;
int message_request_id;
void* iter = NULL;
if (!message.ReadInt(&iter, &message_request_id)) {
NOTREACHED() << "malformed extension message";
return true;
}
if (message_request_id != request_id())
return false;
// The extension process has processed the response and has created a
// reference to the blob, it is safe for us to go away.
Release(); // Balanced in Run()
return true;
}
void PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
bool success = file_util::CreateTemporaryFile(&mhtml_path_);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
NewRunnableMethod(this,
&PageCaptureSaveAsMHTMLFunction::TemporaryFileCreated,
success));
}
void PageCaptureSaveAsMHTMLFunction::TemporaryFileCreated(bool success) {
if (!success) {
ReturnFailure(kTemporaryFileError);
return;
}
if (test_delegate_)
test_delegate_->OnTemporaryFileCreated(mhtml_path_);
// Sets a DeletableFileReference so the temporary file gets deleted once it is
// no longer used.
mhtml_file_ = webkit_blob::DeletableFileReference::GetOrCreate(mhtml_path_,
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
TabContents* tab_contents = GetTabContents();
if (!tab_contents) {
ReturnFailure(kTabClosedError);
return;
}
MHTMLGenerationManager::GenerateMHTMLCallback callback =
base::Bind(&PageCaptureSaveAsMHTMLFunction::MHTMLGenerated, this);
g_browser_process->mhtml_generation_manager()->GenerateMHTML(
tab_contents, mhtml_path_, callback);
}
void PageCaptureSaveAsMHTMLFunction::MHTMLGenerated(const FilePath& file_path,
int64 mhtml_file_size) {
DCHECK(mhtml_path_ == file_path);
if (mhtml_file_size <= 0) {
ReturnFailure(kMHTMLGenerationFailedError);
return;
}
if (mhtml_file_size > std::numeric_limits<int>::max()) {
ReturnFailure(kFileTooBigError);
return;
}
ReturnSuccess(mhtml_file_size);
}
void PageCaptureSaveAsMHTMLFunction::ReturnFailure(const std::string& error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
error_ = error;
SendResponse(false);
Release(); // Balanced in Run()
}
void PageCaptureSaveAsMHTMLFunction::ReturnSuccess(int64 file_size) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
TabContents* tab_contents = GetTabContents();
if (!tab_contents || !render_view_host()) {
ReturnFailure(kTabClosedError);
return;
}
int child_id = render_view_host()->process()->GetID();
ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(
child_id, mhtml_path_);
DictionaryValue* dict = new DictionaryValue();
result_.reset(dict);
dict->SetString("mhtmlFilePath", mhtml_path_.value());
dict->SetInteger("mhtmlFileLength", file_size);
SendResponse(true);
// Note that we'll wait for a response ack message received in
// OnMessageReceivedFromRenderView before we call Release() (to prevent the
// blob file from being deleted).
}
TabContents* PageCaptureSaveAsMHTMLFunction::GetTabContents() {
Browser* browser = NULL;
TabContentsWrapper* tab_contents_wrapper = NULL;
if (!ExtensionTabUtil::GetTabById(tab_id_, profile(), include_incognito(),
&browser, NULL, &tab_contents_wrapper, NULL)) {
return NULL;
}
return tab_contents_wrapper->tab_contents();
}