Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / page_capture / page_capture_api.cc
blob672c29596025bccfc4d98fa10ffb61b21be721e9
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"
7 #include <limits>
9 #include "base/bind.h"
10 #include "base/files/file_util.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/extensions/extension_tab_util.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "content/public/browser/child_process_security_policy.h"
15 #include "content/public/browser/notification_details.h"
16 #include "content/public/browser/notification_source.h"
17 #include "content/public/browser/notification_types.h"
18 #include "content/public/browser/render_frame_host.h"
19 #include "content/public/browser/render_process_host.h"
20 #include "content/public/browser/web_contents.h"
21 #include "extensions/common/extension_messages.h"
23 using content::BrowserThread;
24 using content::ChildProcessSecurityPolicy;
25 using content::WebContents;
26 using extensions::PageCaptureSaveAsMHTMLFunction;
27 using storage::ShareableFileReference;
29 namespace SaveAsMHTML = extensions::api::page_capture::SaveAsMHTML;
31 namespace {
33 const char kFileTooBigError[] = "The MHTML file generated is too big.";
34 const char kMHTMLGenerationFailedError[] = "Failed to generate MHTML.";
35 const char kTemporaryFileError[] = "Failed to create a temporary file.";
36 const char kTabClosedError[] = "Cannot find the tab for this request.";
38 } // namespace
40 static PageCaptureSaveAsMHTMLFunction::TestDelegate* test_delegate_ = NULL;
42 PageCaptureSaveAsMHTMLFunction::PageCaptureSaveAsMHTMLFunction() {
45 PageCaptureSaveAsMHTMLFunction::~PageCaptureSaveAsMHTMLFunction() {
46 if (mhtml_file_.get()) {
47 storage::ShareableFileReference* to_release = mhtml_file_.get();
48 to_release->AddRef();
49 mhtml_file_ = NULL;
50 BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, to_release);
54 void PageCaptureSaveAsMHTMLFunction::SetTestDelegate(TestDelegate* delegate) {
55 test_delegate_ = delegate;
58 bool PageCaptureSaveAsMHTMLFunction::RunAsync() {
59 params_ = SaveAsMHTML::Params::Create(*args_);
60 EXTENSION_FUNCTION_VALIDATE(params_.get());
62 AddRef(); // Balanced in ReturnFailure/ReturnSuccess()
64 BrowserThread::PostTask(
65 BrowserThread::FILE, FROM_HERE,
66 base::Bind(&PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile, this));
67 return true;
70 bool PageCaptureSaveAsMHTMLFunction::OnMessageReceived(
71 const IPC::Message& message) {
72 if (message.type() != ExtensionHostMsg_ResponseAck::ID)
73 return false;
75 int message_request_id;
76 base::PickleIterator iter(message);
77 if (!iter.ReadInt(&message_request_id)) {
78 NOTREACHED() << "malformed extension message";
79 return true;
82 if (message_request_id != request_id())
83 return false;
85 // The extension process has processed the response and has created a
86 // reference to the blob, it is safe for us to go away.
87 Release(); // Balanced in Run()
89 return true;
92 void PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile() {
93 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
94 bool success = base::CreateTemporaryFile(&mhtml_path_);
95 BrowserThread::PostTask(
96 BrowserThread::IO, FROM_HERE,
97 base::Bind(&PageCaptureSaveAsMHTMLFunction::TemporaryFileCreated, this,
98 success));
101 void PageCaptureSaveAsMHTMLFunction::TemporaryFileCreated(bool success) {
102 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
103 if (success) {
104 // Setup a ShareableFileReference so the temporary file gets deleted
105 // once it is no longer used.
106 mhtml_file_ = ShareableFileReference::GetOrCreate(
107 mhtml_path_,
108 ShareableFileReference::DELETE_ON_FINAL_RELEASE,
109 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)
110 .get());
112 BrowserThread::PostTask(
113 BrowserThread::UI, FROM_HERE,
114 base::Bind(&PageCaptureSaveAsMHTMLFunction::TemporaryFileCreated, this,
115 success));
116 return;
119 DCHECK_CURRENTLY_ON(BrowserThread::UI);
120 if (!success) {
121 ReturnFailure(kTemporaryFileError);
122 return;
125 if (test_delegate_)
126 test_delegate_->OnTemporaryFileCreated(mhtml_path_);
128 WebContents* web_contents = GetWebContents();
129 if (!web_contents) {
130 ReturnFailure(kTabClosedError);
131 return;
134 web_contents->GenerateMHTML(
135 mhtml_path_,
136 base::Bind(&PageCaptureSaveAsMHTMLFunction::MHTMLGenerated, this));
139 void PageCaptureSaveAsMHTMLFunction::MHTMLGenerated(
140 int64 mhtml_file_size) {
141 if (mhtml_file_size <= 0) {
142 ReturnFailure(kMHTMLGenerationFailedError);
143 return;
146 if (mhtml_file_size > std::numeric_limits<int>::max()) {
147 ReturnFailure(kFileTooBigError);
148 return;
151 ReturnSuccess(mhtml_file_size);
154 void PageCaptureSaveAsMHTMLFunction::ReturnFailure(const std::string& error) {
155 DCHECK_CURRENTLY_ON(BrowserThread::UI);
157 error_ = error;
159 SendResponse(false);
161 Release(); // Balanced in Run()
164 void PageCaptureSaveAsMHTMLFunction::ReturnSuccess(int64 file_size) {
165 DCHECK_CURRENTLY_ON(BrowserThread::UI);
167 WebContents* web_contents = GetWebContents();
168 if (!web_contents || !render_frame_host()) {
169 ReturnFailure(kTabClosedError);
170 return;
173 int child_id = render_frame_host()->GetProcess()->GetID();
174 ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(
175 child_id, mhtml_path_);
177 base::DictionaryValue* dict = new base::DictionaryValue();
178 SetResult(dict);
179 dict->SetString("mhtmlFilePath", mhtml_path_.value());
180 dict->SetInteger("mhtmlFileLength", file_size);
182 SendResponse(true);
184 // Note that we'll wait for a response ack message received in
185 // OnMessageReceived before we call Release() (to prevent the blob file from
186 // being deleted).
189 WebContents* PageCaptureSaveAsMHTMLFunction::GetWebContents() {
190 Browser* browser = NULL;
191 content::WebContents* web_contents = NULL;
193 if (!ExtensionTabUtil::GetTabById(params_->details.tab_id,
194 GetProfile(),
195 include_incognito(),
196 &browser,
197 NULL,
198 &web_contents,
199 NULL)) {
200 return NULL;
202 return web_contents;