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.
5 #include "chrome/browser/extensions/api/page_capture/page_capture_api.h"
10 #include "base/file_util.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/extensions/extension_tab_util.h"
13 #include "content/public/browser/child_process_security_policy.h"
14 #include "content/public/browser/notification_details.h"
15 #include "content/public/browser/notification_source.h"
16 #include "content/public/browser/notification_types.h"
17 #include "content/public/browser/render_process_host.h"
18 #include "content/public/browser/render_view_host.h"
19 #include "content/public/browser/web_contents.h"
20 #include "extensions/common/extension_messages.h"
22 using content::BrowserThread
;
23 using content::ChildProcessSecurityPolicy
;
24 using content::WebContents
;
25 using extensions::PageCaptureSaveAsMHTMLFunction
;
26 using webkit_blob::ShareableFileReference
;
28 namespace SaveAsMHTML
= extensions::api::page_capture::SaveAsMHTML
;
32 const char kFileTooBigError
[] = "The MHTML file generated is too big.";
33 const char kMHTMLGenerationFailedError
[] = "Failed to generate MHTML.";
34 const char kTemporaryFileError
[] = "Failed to create a temporary file.";
35 const char kTabClosedError
[] = "Cannot find the tab for this request.";
39 static PageCaptureSaveAsMHTMLFunction::TestDelegate
* test_delegate_
= NULL
;
41 PageCaptureSaveAsMHTMLFunction::PageCaptureSaveAsMHTMLFunction() {
44 PageCaptureSaveAsMHTMLFunction::~PageCaptureSaveAsMHTMLFunction() {
45 if (mhtml_file_
.get()) {
46 webkit_blob::ShareableFileReference
* to_release
= mhtml_file_
.get();
49 BrowserThread::ReleaseSoon(BrowserThread::IO
, FROM_HERE
, to_release
);
53 void PageCaptureSaveAsMHTMLFunction::SetTestDelegate(TestDelegate
* delegate
) {
54 test_delegate_
= delegate
;
57 bool PageCaptureSaveAsMHTMLFunction::RunAsync() {
58 params_
= SaveAsMHTML::Params::Create(*args_
);
59 EXTENSION_FUNCTION_VALIDATE(params_
.get());
61 AddRef(); // Balanced in ReturnFailure/ReturnSuccess()
63 BrowserThread::PostTask(
64 BrowserThread::FILE, FROM_HERE
,
65 base::Bind(&PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile
, this));
69 bool PageCaptureSaveAsMHTMLFunction::OnMessageReceived(
70 const IPC::Message
& message
) {
71 if (message
.type() != ExtensionHostMsg_ResponseAck::ID
)
74 int message_request_id
;
75 PickleIterator
iter(message
);
76 if (!message
.ReadInt(&iter
, &message_request_id
)) {
77 NOTREACHED() << "malformed extension message";
81 if (message_request_id
!= request_id())
84 // The extension process has processed the response and has created a
85 // reference to the blob, it is safe for us to go away.
86 Release(); // Balanced in Run()
91 void PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile() {
92 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
93 bool success
= base::CreateTemporaryFile(&mhtml_path_
);
94 BrowserThread::PostTask(
95 BrowserThread::IO
, FROM_HERE
,
96 base::Bind(&PageCaptureSaveAsMHTMLFunction::TemporaryFileCreated
, this,
100 void PageCaptureSaveAsMHTMLFunction::TemporaryFileCreated(bool success
) {
101 if (BrowserThread::CurrentlyOn(BrowserThread::IO
)) {
103 // Setup a ShareableFileReference so the temporary file gets deleted
104 // once it is no longer used.
105 mhtml_file_
= ShareableFileReference::GetOrCreate(
107 ShareableFileReference::DELETE_ON_FINAL_RELEASE
,
108 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)
111 BrowserThread::PostTask(
112 BrowserThread::UI
, FROM_HERE
,
113 base::Bind(&PageCaptureSaveAsMHTMLFunction::TemporaryFileCreated
, this,
118 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
120 ReturnFailure(kTemporaryFileError
);
125 test_delegate_
->OnTemporaryFileCreated(mhtml_path_
);
127 WebContents
* web_contents
= GetWebContents();
129 ReturnFailure(kTabClosedError
);
133 web_contents
->GenerateMHTML(
135 base::Bind(&PageCaptureSaveAsMHTMLFunction::MHTMLGenerated
, this));
138 void PageCaptureSaveAsMHTMLFunction::MHTMLGenerated(
139 int64 mhtml_file_size
) {
140 if (mhtml_file_size
<= 0) {
141 ReturnFailure(kMHTMLGenerationFailedError
);
145 if (mhtml_file_size
> std::numeric_limits
<int>::max()) {
146 ReturnFailure(kFileTooBigError
);
150 ReturnSuccess(mhtml_file_size
);
153 void PageCaptureSaveAsMHTMLFunction::ReturnFailure(const std::string
& error
) {
154 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
160 Release(); // Balanced in Run()
163 void PageCaptureSaveAsMHTMLFunction::ReturnSuccess(int64 file_size
) {
164 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
166 WebContents
* web_contents
= GetWebContents();
167 if (!web_contents
|| !render_view_host()) {
168 ReturnFailure(kTabClosedError
);
172 int child_id
= render_view_host()->GetProcess()->GetID();
173 ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(
174 child_id
, mhtml_path_
);
176 base::DictionaryValue
* dict
= new base::DictionaryValue();
178 dict
->SetString("mhtmlFilePath", mhtml_path_
.value());
179 dict
->SetInteger("mhtmlFileLength", file_size
);
183 // Note that we'll wait for a response ack message received in
184 // OnMessageReceived before we call Release() (to prevent the blob file from
188 WebContents
* PageCaptureSaveAsMHTMLFunction::GetWebContents() {
189 Browser
* browser
= NULL
;
190 content::WebContents
* web_contents
= NULL
;
192 if (!ExtensionTabUtil::GetTabById(params_
->details
.tab_id
,