• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "chrome/browser/extensions/api/page_capture/page_capture_api.h"
6 
7 #include <limits>
8 
9 #include "base/bind.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 "chrome/common/extensions/extension_messages.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_process_host.h"
19 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/web_contents.h"
21 
22 using content::BrowserThread;
23 using content::ChildProcessSecurityPolicy;
24 using content::WebContents;
25 using extensions::PageCaptureSaveAsMHTMLFunction;
26 using webkit_blob::ShareableFileReference;
27 
28 namespace SaveAsMHTML = extensions::api::page_capture::SaveAsMHTML;
29 
30 namespace {
31 
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 thie request.";
36 
37 }  // namespace
38 
39 static PageCaptureSaveAsMHTMLFunction::TestDelegate* test_delegate_ = NULL;
40 
PageCaptureSaveAsMHTMLFunction()41 PageCaptureSaveAsMHTMLFunction::PageCaptureSaveAsMHTMLFunction() {
42 }
43 
~PageCaptureSaveAsMHTMLFunction()44 PageCaptureSaveAsMHTMLFunction::~PageCaptureSaveAsMHTMLFunction() {
45   if (mhtml_file_.get()) {
46     webkit_blob::ShareableFileReference* to_release = mhtml_file_.get();
47     to_release->AddRef();
48     mhtml_file_ = NULL;
49     BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, to_release);
50   }
51 }
52 
SetTestDelegate(TestDelegate * delegate)53 void PageCaptureSaveAsMHTMLFunction::SetTestDelegate(TestDelegate* delegate) {
54   test_delegate_ = delegate;
55 }
56 
RunImpl()57 bool PageCaptureSaveAsMHTMLFunction::RunImpl() {
58   params_ = SaveAsMHTML::Params::Create(*args_);
59   EXTENSION_FUNCTION_VALIDATE(params_.get());
60 
61   AddRef();  // Balanced in ReturnFailure/ReturnSuccess()
62 
63   BrowserThread::PostTask(
64       BrowserThread::FILE, FROM_HERE,
65       base::Bind(&PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile, this));
66   return true;
67 }
68 
OnMessageReceivedFromRenderView(const IPC::Message & message)69 bool PageCaptureSaveAsMHTMLFunction::OnMessageReceivedFromRenderView(
70     const IPC::Message& message) {
71   if (message.type() != ExtensionHostMsg_ResponseAck::ID)
72     return false;
73 
74   int message_request_id;
75   PickleIterator iter(message);
76   if (!message.ReadInt(&iter, &message_request_id)) {
77     NOTREACHED() << "malformed extension message";
78     return true;
79   }
80 
81   if (message_request_id != request_id())
82     return false;
83 
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()
87 
88   return true;
89 }
90 
CreateTemporaryFile()91 void PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile() {
92   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
93   bool success = base::CreateTemporaryFile(&mhtml_path_);
94   BrowserThread::PostTask(
95       BrowserThread::IO, FROM_HERE,
96       base::Bind(&PageCaptureSaveAsMHTMLFunction::TemporaryFileCreated, this,
97                  success));
98 }
99 
TemporaryFileCreated(bool success)100 void PageCaptureSaveAsMHTMLFunction::TemporaryFileCreated(bool success) {
101   if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
102     if (success) {
103       // Setup a ShareableFileReference so the temporary file gets deleted
104       // once it is no longer used.
105       mhtml_file_ = ShareableFileReference::GetOrCreate(
106           mhtml_path_,
107           ShareableFileReference::DELETE_ON_FINAL_RELEASE,
108           BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)
109               .get());
110     }
111     BrowserThread::PostTask(
112         BrowserThread::UI, FROM_HERE,
113         base::Bind(&PageCaptureSaveAsMHTMLFunction::TemporaryFileCreated, this,
114                    success));
115     return;
116   }
117 
118   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
119   if (!success) {
120     ReturnFailure(kTemporaryFileError);
121     return;
122   }
123 
124   if (test_delegate_)
125     test_delegate_->OnTemporaryFileCreated(mhtml_path_);
126 
127   WebContents* web_contents = GetWebContents();
128   if (!web_contents) {
129     ReturnFailure(kTabClosedError);
130     return;
131   }
132 
133   web_contents->GenerateMHTML(
134       mhtml_path_,
135       base::Bind(&PageCaptureSaveAsMHTMLFunction::MHTMLGenerated, this));
136 }
137 
MHTMLGenerated(int64 mhtml_file_size)138 void PageCaptureSaveAsMHTMLFunction::MHTMLGenerated(
139     int64 mhtml_file_size) {
140   if (mhtml_file_size <= 0) {
141     ReturnFailure(kMHTMLGenerationFailedError);
142     return;
143   }
144 
145   if (mhtml_file_size > std::numeric_limits<int>::max()) {
146     ReturnFailure(kFileTooBigError);
147     return;
148   }
149 
150   ReturnSuccess(mhtml_file_size);
151 }
152 
ReturnFailure(const std::string & error)153 void PageCaptureSaveAsMHTMLFunction::ReturnFailure(const std::string& error) {
154   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
155 
156   error_ = error;
157 
158   SendResponse(false);
159 
160   Release();  // Balanced in Run()
161 }
162 
ReturnSuccess(int64 file_size)163 void PageCaptureSaveAsMHTMLFunction::ReturnSuccess(int64 file_size) {
164   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
165 
166   WebContents* web_contents = GetWebContents();
167   if (!web_contents || !render_view_host()) {
168     ReturnFailure(kTabClosedError);
169     return;
170   }
171 
172   int child_id = render_view_host()->GetProcess()->GetID();
173   ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(
174       child_id, mhtml_path_);
175 
176   base::DictionaryValue* dict = new base::DictionaryValue();
177   SetResult(dict);
178   dict->SetString("mhtmlFilePath", mhtml_path_.value());
179   dict->SetInteger("mhtmlFileLength", file_size);
180 
181   SendResponse(true);
182 
183   // Note that we'll wait for a response ack message received in
184   // OnMessageReceivedFromRenderView before we call Release() (to prevent the
185   // blob file from being deleted).
186 }
187 
GetWebContents()188 WebContents* PageCaptureSaveAsMHTMLFunction::GetWebContents() {
189   Browser* browser = NULL;
190   content::WebContents* web_contents = NULL;
191 
192   if (!ExtensionTabUtil::GetTabById(params_->details.tab_id,
193                                     GetProfile(),
194                                     include_incognito(),
195                                     &browser,
196                                     NULL,
197                                     &web_contents,
198                                     NULL)) {
199     return NULL;
200   }
201   return web_contents;
202 }
203