[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 1 | // Copyright (c) 2011 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 | |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 5 | #include "chrome/browser/extensions/extension_page_capture_api.h" |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 6 | |
[email protected] | 7477b271 | 2011-11-23 07:53:03 | [diff] [blame] | 7 | #include "base/bind.h" |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 8 | #include "base/file_util.h" |
| 9 | #include "chrome/browser/browser_process.h" |
[email protected] | ac84431b | 2011-09-27 17:26:11 | [diff] [blame] | 10 | #include "chrome/browser/extensions/extension_tab_util.h" |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 11 | #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
[email protected] | 0f7daaa | 2011-11-22 18:34:56 | [diff] [blame] | 12 | #include "chrome/common/extensions/extension_messages.h" |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 13 | #include "content/browser/child_process_security_policy.h" |
| 14 | #include "content/browser/renderer_host/render_view_host.h" |
| 15 | #include "content/browser/tab_contents/tab_contents.h" |
| 16 | #include "content/browser/download/mhtml_generation_manager.h" |
[email protected] | ad50def5 | 2011-10-19 23:17:07 | [diff] [blame] | 17 | #include "content/public/browser/notification_details.h" |
| 18 | #include "content/public/browser/notification_source.h" |
[email protected] | 0d6e9bd | 2011-10-18 04:29:16 | [diff] [blame] | 19 | #include "content/public/browser/notification_types.h" |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 20 | |
[email protected] | 631bb74 | 2011-11-02 11:29:39 | [diff] [blame] | 21 | using content::BrowserThread; |
| 22 | |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 23 | // Error messages. |
| 24 | const char* const kFileTooBigError = "The MHTML file generated is too big."; |
| 25 | const char* const kMHTMLGenerationFailedError = "Failed to generate MHTML."; |
| 26 | const char* const kSizeRetrievalError = |
| 27 | "Failed to retrieve size of generated MHTML."; |
| 28 | const char* const kTemporaryFileError = "Failed to create a temporary file."; |
| 29 | const char* const kTabClosedError = "Cannot find the tab for thie request."; |
| 30 | |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 31 | static PageCaptureSaveAsMHTMLFunction::TestDelegate* test_delegate_ = NULL; |
[email protected] | 0f7daaa | 2011-11-22 18:34:56 | [diff] [blame] | 32 | |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 33 | PageCaptureSaveAsMHTMLFunction::PageCaptureSaveAsMHTMLFunction() : tab_id_(0) { |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 34 | } |
| 35 | |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 36 | PageCaptureSaveAsMHTMLFunction::~PageCaptureSaveAsMHTMLFunction() { |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 37 | } |
| 38 | |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 39 | void PageCaptureSaveAsMHTMLFunction::SetTestDelegate(TestDelegate* delegate) { |
[email protected] | 0f7daaa | 2011-11-22 18:34:56 | [diff] [blame] | 40 | test_delegate_ = delegate; |
| 41 | } |
| 42 | |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 43 | bool PageCaptureSaveAsMHTMLFunction::RunImpl() { |
[email protected] | 8077c95 | 2011-11-22 23:27:14 | [diff] [blame] | 44 | DictionaryValue* args; |
| 45 | EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); |
| 46 | |
| 47 | if (!args->HasKey("tabId")) |
| 48 | return false; |
| 49 | |
| 50 | EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id_)); |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 51 | |
| 52 | AddRef(); // Balanced in ReturnFailure/ReturnSuccess() |
| 53 | |
| 54 | BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 55 | NewRunnableMethod(this, |
| 56 | &PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile)); |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 57 | return true; |
| 58 | } |
| 59 | |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 60 | bool PageCaptureSaveAsMHTMLFunction::OnMessageReceivedFromRenderView( |
[email protected] | 0f7daaa | 2011-11-22 18:34:56 | [diff] [blame] | 61 | const IPC::Message& message) { |
| 62 | if (message.type() != ExtensionHostMsg_ResponseAck::ID) |
| 63 | return false; |
| 64 | |
| 65 | int message_request_id; |
| 66 | void* iter = NULL; |
| 67 | if (!message.ReadInt(&iter, &message_request_id)) { |
| 68 | NOTREACHED() << "malformed extension message"; |
| 69 | return true; |
| 70 | } |
| 71 | |
| 72 | if (message_request_id != request_id()) |
| 73 | return false; |
| 74 | |
| 75 | // The extension process has processed the response and has created a |
| 76 | // reference to the blob, it is safe for us to go away. |
| 77 | Release(); // Balanced in Run() |
| 78 | |
| 79 | return true; |
| 80 | } |
| 81 | |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 82 | void PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile() { |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 83 | DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 84 | bool success = file_util::CreateTemporaryFile(&mhtml_path_); |
| 85 | BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 86 | NewRunnableMethod(this, |
| 87 | &PageCaptureSaveAsMHTMLFunction::TemporaryFileCreated, |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 88 | success)); |
| 89 | } |
| 90 | |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 91 | void PageCaptureSaveAsMHTMLFunction::TemporaryFileCreated(bool success) { |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 92 | if (!success) { |
| 93 | ReturnFailure(kTemporaryFileError); |
| 94 | return; |
| 95 | } |
| 96 | |
[email protected] | 0f7daaa | 2011-11-22 18:34:56 | [diff] [blame] | 97 | if (test_delegate_) |
| 98 | test_delegate_->OnTemporaryFileCreated(mhtml_path_); |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 99 | |
[email protected] | 0f7daaa | 2011-11-22 18:34:56 | [diff] [blame] | 100 | // Sets a DeletableFileReference so the temporary file gets deleted once it is |
| 101 | // no longer used. |
| 102 | mhtml_file_ = webkit_blob::DeletableFileReference::GetOrCreate(mhtml_path_, |
| 103 | BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)); |
| 104 | |
| 105 | TabContents* tab_contents = GetTabContents(); |
| 106 | if (!tab_contents) { |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 107 | ReturnFailure(kTabClosedError); |
| 108 | return; |
| 109 | } |
| 110 | |
[email protected] | 7477b271 | 2011-11-23 07:53:03 | [diff] [blame] | 111 | MHTMLGenerationManager::GenerateMHTMLCallback callback = |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 112 | base::Bind(&PageCaptureSaveAsMHTMLFunction::MHTMLGenerated, this); |
[email protected] | 7477b271 | 2011-11-23 07:53:03 | [diff] [blame] | 113 | |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 114 | g_browser_process->mhtml_generation_manager()->GenerateMHTML( |
[email protected] | 7477b271 | 2011-11-23 07:53:03 | [diff] [blame] | 115 | tab_contents, mhtml_path_, callback); |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 116 | } |
| 117 | |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 118 | void PageCaptureSaveAsMHTMLFunction::MHTMLGenerated(const FilePath& file_path, |
| 119 | int64 mhtml_file_size) { |
[email protected] | 7477b271 | 2011-11-23 07:53:03 | [diff] [blame] | 120 | DCHECK(mhtml_path_ == file_path); |
| 121 | if (mhtml_file_size <= 0) { |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 122 | ReturnFailure(kMHTMLGenerationFailedError); |
| 123 | return; |
| 124 | } |
| 125 | |
[email protected] | 7477b271 | 2011-11-23 07:53:03 | [diff] [blame] | 126 | if (mhtml_file_size > std::numeric_limits<int>::max()) { |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 127 | ReturnFailure(kFileTooBigError); |
| 128 | return; |
| 129 | } |
| 130 | |
[email protected] | 7477b271 | 2011-11-23 07:53:03 | [diff] [blame] | 131 | ReturnSuccess(mhtml_file_size); |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 132 | } |
| 133 | |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 134 | void PageCaptureSaveAsMHTMLFunction::ReturnFailure(const std::string& error) { |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 135 | DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 136 | |
| 137 | error_ = error; |
| 138 | |
| 139 | SendResponse(false); |
| 140 | |
| 141 | Release(); // Balanced in Run() |
| 142 | } |
| 143 | |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 144 | void PageCaptureSaveAsMHTMLFunction::ReturnSuccess(int64 file_size) { |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 145 | DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 146 | |
[email protected] | 0f7daaa | 2011-11-22 18:34:56 | [diff] [blame] | 147 | TabContents* tab_contents = GetTabContents(); |
| 148 | if (!tab_contents || !render_view_host()) { |
| 149 | ReturnFailure(kTabClosedError); |
| 150 | return; |
| 151 | } |
| 152 | |
[email protected] | f3b1a08 | 2011-11-18 00:34:30 | [diff] [blame] | 153 | int child_id = render_view_host()->process()->GetID(); |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 154 | ChildProcessSecurityPolicy::GetInstance()->GrantReadFile( |
| 155 | child_id, mhtml_path_); |
| 156 | |
| 157 | DictionaryValue* dict = new DictionaryValue(); |
| 158 | result_.reset(dict); |
| 159 | dict->SetString("mhtmlFilePath", mhtml_path_.value()); |
| 160 | dict->SetInteger("mhtmlFileLength", file_size); |
| 161 | |
| 162 | SendResponse(true); |
| 163 | |
[email protected] | 0f7daaa | 2011-11-22 18:34:56 | [diff] [blame] | 164 | // Note that we'll wait for a response ack message received in |
| 165 | // OnMessageReceivedFromRenderView before we call Release() (to prevent the |
| 166 | // blob file from being deleted). |
| 167 | } |
| 168 | |
[email protected] | 9e4430f | 2011-11-28 07:43:29 | [diff] [blame] | 169 | TabContents* PageCaptureSaveAsMHTMLFunction::GetTabContents() { |
[email protected] | 0f7daaa | 2011-11-22 18:34:56 | [diff] [blame] | 170 | Browser* browser = NULL; |
| 171 | TabContentsWrapper* tab_contents_wrapper = NULL; |
| 172 | |
| 173 | if (!ExtensionTabUtil::GetTabById(tab_id_, profile(), include_incognito(), |
| 174 | &browser, NULL, &tab_contents_wrapper, NULL)) { |
| 175 | return NULL; |
| 176 | } |
| 177 | return tab_contents_wrapper->tab_contents(); |
[email protected] | 3a605e8 | 2011-09-26 17:26:16 | [diff] [blame] | 178 | } |