Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / download / mhtml_generation_manager.cc
blobdb4ba30533f02c022cf00d3e550bd5b939663736
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 "content/browser/download/mhtml_generation_manager.h"
7 #include "base/bind.h"
8 #include "base/files/file.h"
9 #include "base/stl_util.h"
10 #include "content/browser/renderer_host/render_view_host_impl.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/render_process_host.h"
13 #include "content/public/browser/render_process_host_observer.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/common/view_messages.h"
17 namespace content {
19 class MHTMLGenerationManager::Job : public RenderProcessHostObserver {
20 public:
21 Job();
22 virtual ~Job();
24 void SetWebContents(WebContents* web_contents);
26 base::File browser_file() { return browser_file_.Pass(); }
27 void set_browser_file(base::File file) { browser_file_ = file.Pass(); }
29 int process_id() { return process_id_; }
30 int routing_id() { return routing_id_; }
32 GenerateMHTMLCallback callback() { return callback_; }
33 void set_callback(GenerateMHTMLCallback callback) { callback_ = callback; }
35 // RenderProcessHostObserver:
36 virtual void RenderProcessExited(RenderProcessHost* host,
37 base::ProcessHandle handle,
38 base::TerminationStatus status,
39 int exit_code) OVERRIDE;
40 virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE;
43 private:
44 // The handle to the file the MHTML is saved to for the browser process.
45 base::File browser_file_;
47 // The IDs mapping to a specific contents.
48 int process_id_;
49 int routing_id_;
51 // The callback to call once generation is complete.
52 GenerateMHTMLCallback callback_;
54 // The RenderProcessHost being observed, or NULL if none is.
55 RenderProcessHost* host_;
56 DISALLOW_COPY_AND_ASSIGN(Job);
59 MHTMLGenerationManager::Job::Job()
60 : process_id_(-1),
61 routing_id_(-1),
62 host_(NULL) {
65 MHTMLGenerationManager::Job::~Job() {
66 if (host_)
67 host_->RemoveObserver(this);
70 void MHTMLGenerationManager::Job::SetWebContents(WebContents* web_contents) {
71 process_id_ = web_contents->GetRenderProcessHost()->GetID();
72 routing_id_ = web_contents->GetRenderViewHost()->GetRoutingID();
73 host_ = web_contents->GetRenderProcessHost();
74 host_->AddObserver(this);
77 void MHTMLGenerationManager::Job::RenderProcessExited(
78 RenderProcessHost* host,
79 base::ProcessHandle handle,
80 base::TerminationStatus status,
81 int exit_code) {
82 MHTMLGenerationManager::GetInstance()->RenderProcessExited(this);
85 void MHTMLGenerationManager::Job::RenderProcessHostDestroyed(
86 RenderProcessHost* host) {
87 host_ = NULL;
90 MHTMLGenerationManager* MHTMLGenerationManager::GetInstance() {
91 return Singleton<MHTMLGenerationManager>::get();
94 MHTMLGenerationManager::MHTMLGenerationManager() {
97 MHTMLGenerationManager::~MHTMLGenerationManager() {
98 STLDeleteValues(&id_to_job_);
101 void MHTMLGenerationManager::SaveMHTML(WebContents* web_contents,
102 const base::FilePath& file,
103 const GenerateMHTMLCallback& callback) {
104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
106 int job_id = NewJob(web_contents, callback);
108 base::ProcessHandle renderer_process =
109 web_contents->GetRenderProcessHost()->GetHandle();
110 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
111 base::Bind(&MHTMLGenerationManager::CreateFile, base::Unretained(this),
112 job_id, file, renderer_process));
115 void MHTMLGenerationManager::StreamMHTML(
116 WebContents* web_contents,
117 base::File browser_file,
118 const GenerateMHTMLCallback& callback) {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
121 int job_id = NewJob(web_contents, callback);
123 base::ProcessHandle renderer_process =
124 web_contents->GetRenderProcessHost()->GetHandle();
125 IPC::PlatformFileForTransit renderer_file =
126 IPC::GetFileHandleForProcess(browser_file.GetPlatformFile(),
127 renderer_process, false);
129 FileAvailable(job_id, browser_file.Pass(), renderer_file);
133 void MHTMLGenerationManager::MHTMLGenerated(int job_id, int64 mhtml_data_size) {
134 JobFinished(job_id, mhtml_data_size);
137 void MHTMLGenerationManager::CreateFile(
138 int job_id, const base::FilePath& file_path,
139 base::ProcessHandle renderer_process) {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
141 base::File browser_file(
142 file_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
143 if (!browser_file.IsValid()) {
144 LOG(ERROR) << "Failed to create file to save MHTML at: " <<
145 file_path.value();
148 IPC::PlatformFileForTransit renderer_file =
149 IPC::GetFileHandleForProcess(browser_file.GetPlatformFile(),
150 renderer_process, false);
152 BrowserThread::PostTask(
153 BrowserThread::UI,
154 FROM_HERE,
155 base::Bind(&MHTMLGenerationManager::FileAvailable,
156 base::Unretained(this),
157 job_id,
158 base::Passed(&browser_file),
159 renderer_file));
162 void MHTMLGenerationManager::FileAvailable(
163 int job_id,
164 base::File browser_file,
165 IPC::PlatformFileForTransit renderer_file) {
166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
167 if (!browser_file.IsValid()) {
168 LOG(ERROR) << "Failed to create file";
169 JobFinished(job_id, -1);
170 return;
173 IDToJobMap::iterator iter = id_to_job_.find(job_id);
174 if (iter == id_to_job_.end()) {
175 NOTREACHED();
176 return;
179 Job* job = iter->second;
180 job->set_browser_file(browser_file.Pass());
182 RenderViewHost* rvh = RenderViewHost::FromID(
183 job->process_id(), job->routing_id());
184 if (!rvh) {
185 // The contents went away.
186 JobFinished(job_id, -1);
187 return;
190 rvh->Send(new ViewMsg_SavePageAsMHTML(rvh->GetRoutingID(), job_id,
191 renderer_file));
194 void MHTMLGenerationManager::JobFinished(int job_id, int64 file_size) {
195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
196 IDToJobMap::iterator iter = id_to_job_.find(job_id);
197 if (iter == id_to_job_.end()) {
198 NOTREACHED();
199 return;
202 Job* job = iter->second;
203 job->callback().Run(file_size);
205 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
206 base::Bind(&MHTMLGenerationManager::CloseFile, base::Unretained(this),
207 base::Passed(job->browser_file())));
209 id_to_job_.erase(job_id);
210 delete job;
213 void MHTMLGenerationManager::CloseFile(base::File file) {
214 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
215 file.Close();
218 int MHTMLGenerationManager::NewJob(WebContents* web_contents,
219 const GenerateMHTMLCallback& callback) {
220 static int id_counter = 0;
221 int job_id = id_counter++;
222 Job* job = new Job();
223 id_to_job_[job_id] = job;
224 job->SetWebContents(web_contents);
225 job->set_callback(callback);
226 return job_id;
229 void MHTMLGenerationManager::RenderProcessExited(Job* job) {
230 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
231 for (IDToJobMap::iterator it = id_to_job_.begin(); it != id_to_job_.end();
232 ++it) {
233 if (it->second == job) {
234 JobFinished(it->first, -1);
235 return;
238 NOTREACHED();
241 } // namespace content