IndexedDBFactory now ForceCloses databases.
[chromium-blink-merge.git] / content / browser / download / mhtml_generation_manager.cc
blobf1114a6d9ee201bb11c8c2a1e62a760bacf6a9e5
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/platform_file.h"
9 #include "content/browser/renderer_host/render_view_host_impl.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/browser/render_process_host.h"
12 #include "content/public/browser/render_process_host_observer.h"
13 #include "content/public/browser/web_contents.h"
14 #include "content/common/view_messages.h"
16 namespace content {
18 class MHTMLGenerationManager::Job : public RenderProcessHostObserver {
19 public:
20 Job();
21 virtual ~Job();
23 void SetWebContents(WebContents* web_contents);
25 base::PlatformFile browser_file() { return browser_file_; }
26 void set_browser_file(base::PlatformFile file) { browser_file_ = file; }
28 int process_id() { return process_id_; }
29 int routing_id() { return routing_id_; }
31 GenerateMHTMLCallback callback() { return callback_; }
32 void set_callback(GenerateMHTMLCallback callback) { callback_ = callback; }
34 // RenderProcessHostObserver:
35 virtual void RenderProcessExited(RenderProcessHost* host,
36 base::ProcessHandle handle,
37 base::TerminationStatus status,
38 int exit_code) OVERRIDE;
39 virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE;
42 private:
43 // The handle to the file the MHTML is saved to for the browser process.
44 base::PlatformFile browser_file_;
46 // The IDs mapping to a specific contents.
47 int process_id_;
48 int routing_id_;
50 // The callback to call once generation is complete.
51 GenerateMHTMLCallback callback_;
53 // The RenderProcessHost being observed, or NULL if none is.
54 RenderProcessHost* host_;
57 MHTMLGenerationManager::Job::Job()
58 : browser_file_(base::kInvalidPlatformFileValue),
59 process_id_(-1),
60 routing_id_(-1),
61 host_(NULL) {
64 MHTMLGenerationManager::Job::~Job() {
65 if (host_)
66 host_->RemoveObserver(this);
69 void MHTMLGenerationManager::Job::SetWebContents(WebContents* web_contents) {
70 process_id_ = web_contents->GetRenderProcessHost()->GetID();
71 routing_id_ = web_contents->GetRenderViewHost()->GetRoutingID();
72 host_ = web_contents->GetRenderProcessHost();
73 host_->AddObserver(this);
76 void MHTMLGenerationManager::Job::RenderProcessExited(
77 RenderProcessHost* host,
78 base::ProcessHandle handle,
79 base::TerminationStatus status,
80 int exit_code) {
81 MHTMLGenerationManager::GetInstance()->RenderProcessExited(this);
84 void MHTMLGenerationManager::Job::RenderProcessHostDestroyed(
85 RenderProcessHost* host) {
86 host_ = NULL;
89 MHTMLGenerationManager* MHTMLGenerationManager::GetInstance() {
90 return Singleton<MHTMLGenerationManager>::get();
93 MHTMLGenerationManager::MHTMLGenerationManager() {
96 MHTMLGenerationManager::~MHTMLGenerationManager() {
99 void MHTMLGenerationManager::SaveMHTML(WebContents* web_contents,
100 const base::FilePath& file,
101 const GenerateMHTMLCallback& callback) {
102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
104 int job_id = NewJob(web_contents, callback);
106 base::ProcessHandle renderer_process =
107 web_contents->GetRenderProcessHost()->GetHandle();
108 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
109 base::Bind(&MHTMLGenerationManager::CreateFile, base::Unretained(this),
110 job_id, file, renderer_process));
113 void MHTMLGenerationManager::StreamMHTML(
114 WebContents* web_contents,
115 const base::PlatformFile browser_file,
116 const GenerateMHTMLCallback& callback) {
117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
119 int job_id = NewJob(web_contents, callback);
121 base::ProcessHandle renderer_process =
122 web_contents->GetRenderProcessHost()->GetHandle();
123 IPC::PlatformFileForTransit renderer_file =
124 IPC::GetFileHandleForProcess(browser_file, renderer_process, false);
126 FileHandleAvailable(job_id, browser_file, renderer_file);
130 void MHTMLGenerationManager::MHTMLGenerated(int job_id, int64 mhtml_data_size) {
131 JobFinished(job_id, mhtml_data_size);
134 void MHTMLGenerationManager::CreateFile(
135 int job_id, const base::FilePath& file_path,
136 base::ProcessHandle renderer_process) {
137 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
138 base::PlatformFile browser_file = base::CreatePlatformFile(file_path,
139 base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE,
140 NULL, NULL);
141 if (browser_file == base::kInvalidPlatformFileValue) {
142 LOG(ERROR) << "Failed to create file to save MHTML at: " <<
143 file_path.value();
146 IPC::PlatformFileForTransit renderer_file =
147 IPC::GetFileHandleForProcess(browser_file, renderer_process, false);
149 BrowserThread::PostTask(
150 BrowserThread::UI,
151 FROM_HERE,
152 base::Bind(&MHTMLGenerationManager::FileHandleAvailable,
153 base::Unretained(this),
154 job_id,
155 browser_file,
156 renderer_file));
159 void MHTMLGenerationManager::FileHandleAvailable(
160 int job_id,
161 base::PlatformFile browser_file,
162 IPC::PlatformFileForTransit renderer_file) {
163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
164 if (browser_file == base::kInvalidPlatformFileValue) {
165 LOG(ERROR) << "Failed to create file";
166 JobFinished(job_id, -1);
167 return;
170 IDToJobMap::iterator iter = id_to_job_.find(job_id);
171 if (iter == id_to_job_.end()) {
172 NOTREACHED();
173 return;
176 Job& job = iter->second;
177 job.set_browser_file(browser_file);
179 RenderViewHost* rvh = RenderViewHost::FromID(
180 job.process_id(), job.routing_id());
181 if (!rvh) {
182 // The contents went away.
183 JobFinished(job_id, -1);
184 return;
187 rvh->Send(new ViewMsg_SavePageAsMHTML(rvh->GetRoutingID(), job_id,
188 renderer_file));
191 void MHTMLGenerationManager::JobFinished(int job_id, int64 file_size) {
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
193 IDToJobMap::iterator iter = id_to_job_.find(job_id);
194 if (iter == id_to_job_.end()) {
195 NOTREACHED();
196 return;
199 Job& job = iter->second;
200 job.callback().Run(file_size);
202 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
203 base::Bind(&MHTMLGenerationManager::CloseFile, base::Unretained(this),
204 job.browser_file()));
206 id_to_job_.erase(job_id);
209 void MHTMLGenerationManager::CloseFile(base::PlatformFile file) {
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
211 base::ClosePlatformFile(file);
214 int MHTMLGenerationManager::NewJob(WebContents* web_contents,
215 const GenerateMHTMLCallback& callback) {
216 static int id_counter = 0;
217 int job_id = id_counter++;
218 Job& job = id_to_job_[job_id];
219 job.SetWebContents(web_contents);
220 job.set_callback(callback);
221 return job_id;
224 void MHTMLGenerationManager::RenderProcessExited(Job* job) {
225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
226 for (IDToJobMap::iterator it = id_to_job_.begin(); it != id_to_job_.end();
227 ++it) {
228 if (&it->second == job) {
229 JobFinished(it->first, -1);
230 return;
233 NOTREACHED();
236 } // namespace content