Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(55)

Side by Side Diff: content/browser/download/mhtml_generation_manager.cc

Issue 2731293004: Move the writing of the MHTML footer to the browser process. (Closed)
Patch Set: Comments and naming changes. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/download/mhtml_generation_manager.h" 5 #include "content/browser/download/mhtml_generation_manager.h"
6 6
7 #include <map> 7 #include <map>
8 #include <queue> 8 #include <queue>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/files/file.h" 12 #include "base/files/file.h"
13 #include "base/guid.h" 13 #include "base/guid.h"
14 #include "base/macros.h" 14 #include "base/macros.h"
15 #include "base/memory/ptr_util.h" 15 #include "base/memory/ptr_util.h"
16 #include "base/metrics/histogram_macros.h" 16 #include "base/metrics/histogram_macros.h"
17 #include "base/scoped_observer.h" 17 #include "base/scoped_observer.h"
18 #include "base/stl_util.h" 18 #include "base/stl_util.h"
19 #include "base/strings/string_util.h"
19 #include "base/strings/stringprintf.h" 20 #include "base/strings/stringprintf.h"
20 #include "base/time/time.h" 21 #include "base/time/time.h"
21 #include "base/trace_event/trace_event.h" 22 #include "base/trace_event/trace_event.h"
22 #include "content/browser/bad_message.h" 23 #include "content/browser/bad_message.h"
23 #include "content/browser/frame_host/frame_tree_node.h" 24 #include "content/browser/frame_host/frame_tree_node.h"
24 #include "content/browser/frame_host/render_frame_host_impl.h" 25 #include "content/browser/frame_host/render_frame_host_impl.h"
25 #include "content/common/frame_messages.h" 26 #include "content/common/frame_messages.h"
26 #include "content/public/browser/browser_thread.h" 27 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/render_frame_host.h" 28 #include "content/public/browser/render_frame_host.h"
28 #include "content/public/browser/render_process_host.h" 29 #include "content/public/browser/render_process_host.h"
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 67
67 // Indicates if more calls to SendToNextRenderFrame are needed. 68 // Indicates if more calls to SendToNextRenderFrame are needed.
68 bool IsDone() const { 69 bool IsDone() const {
69 bool waiting_for_response_from_renderer = 70 bool waiting_for_response_from_renderer =
70 frame_tree_node_id_of_busy_frame_ != 71 frame_tree_node_id_of_busy_frame_ !=
71 FrameTreeNode::kFrameTreeNodeInvalidId; 72 FrameTreeNode::kFrameTreeNodeInvalidId;
72 bool no_more_requests_to_send = pending_frame_tree_node_ids_.empty(); 73 bool no_more_requests_to_send = pending_frame_tree_node_ids_.empty();
73 return !waiting_for_response_from_renderer && no_more_requests_to_send; 74 return !waiting_for_response_from_renderer && no_more_requests_to_send;
74 } 75 }
75 76
76 // Close the file on the file thread and respond back on the UI thread with 77 // Write the MHTML footer and close the file on the file thread and respond
77 // file size. 78 // back on the UI thread with the updated status and file size (which will be
78 void CloseFile(base::Callback<void(int64_t file_size)> callback); 79 // negative in case of errors).
80 void CloseFile(
81 base::Callback<void(std::tuple<MhtmlSaveStatus, int64_t>)> callback,
dcheng 2017/03/09 01:56:51 Pass by const ref. Also, I'm not a content owner,
carlosk 2017/03/09 22:03:35 I did change to const ref. But these are just two
dcheng 2017/03/09 23:16:58 I would still prefer to just declare a simple loca
82 MhtmlSaveStatus save_status);
79 83
80 // RenderProcessHostObserver: 84 // RenderProcessHostObserver:
81 void RenderProcessExited(RenderProcessHost* host, 85 void RenderProcessExited(RenderProcessHost* host,
82 base::TerminationStatus status, 86 base::TerminationStatus status,
83 int exit_code) override; 87 int exit_code) override;
84 void RenderProcessHostDestroyed(RenderProcessHost* host) override; 88 void RenderProcessHostDestroyed(RenderProcessHost* host) override;
85 89
86 void MarkAsFinished(); 90 void MarkAsFinished();
87 91
88 void ReportRendererMainThreadTime(base::TimeDelta renderer_main_thread_time); 92 void ReportRendererMainThreadTime(base::TimeDelta renderer_main_thread_time);
89 93
90 private: 94 private:
91 static int64_t CloseFileOnFileThread(base::File file); 95 // Writes the MHTML footer to the file and closes it.
96 //
97 // Note: The same |boundary| marker must be used for all "boundaries" -- in
98 // the header, parts and footer -- that belong to the same MHTML document (see
99 // also rfc1341, section 7.2.1, "boundary" description).
100 static std::tuple<MhtmlSaveStatus, int64_t> CloseFileOnFileThread(
101 MhtmlSaveStatus save_status,
102 std::string boundary,
dcheng 2017/03/09 01:56:51 const std::string&
carlosk 2017/03/09 22:03:36 In this specific case the copy was intended. Betwe
dcheng 2017/03/09 22:08:46 The default callback binding is always by copy, ev
carlosk 2017/03/09 23:07:29 Understood and done. Thanks for the pointer.
103 base::File file);
92 void AddFrame(RenderFrameHost* render_frame_host); 104 void AddFrame(RenderFrameHost* render_frame_host);
93 105
94 // Creates a new map with values (content ids) the same as in 106 // Creates a new map with values (content ids) the same as in
95 // |frame_tree_node_to_content_id_| map, but with the keys translated from 107 // |frame_tree_node_to_content_id_| map, but with the keys translated from
96 // frame_tree_node_id into a |site_instance|-specific routing_id. 108 // frame_tree_node_id into a |site_instance|-specific routing_id.
97 std::map<int, std::string> CreateFrameRoutingIdToContentId( 109 std::map<int, std::string> CreateFrameRoutingIdToContentId(
98 SiteInstance* site_instance); 110 SiteInstance* site_instance);
99 111
100 // Id used to map renderer responses to jobs. 112 // Id used to map renderer responses to jobs.
101 // See also MHTMLGenerationManager::id_to_job_ map. 113 // See also MHTMLGenerationManager::id_to_job_ map.
(...skipping 20 matching lines...) Expand all
122 int frame_tree_node_id_of_busy_frame_; 134 int frame_tree_node_id_of_busy_frame_;
123 135
124 // The handle to the file the MHTML is saved to for the browser process. 136 // The handle to the file the MHTML is saved to for the browser process.
125 base::File browser_file_; 137 base::File browser_file_;
126 138
127 // Map from frames to content ids (see WebFrameSerializer::generateMHTMLParts 139 // Map from frames to content ids (see WebFrameSerializer::generateMHTMLParts
128 // for more details about what "content ids" are and how they are used). 140 // for more details about what "content ids" are and how they are used).
129 std::map<int, std::string> frame_tree_node_to_content_id_; 141 std::map<int, std::string> frame_tree_node_to_content_id_;
130 142
131 // MIME multipart boundary to use in the MHTML doc. 143 // MIME multipart boundary to use in the MHTML doc.
132 std::string mhtml_boundary_marker_; 144 const std::string mhtml_boundary_marker_;
133 145
134 // Digests of URIs of already generated MHTML parts. 146 // Digests of URIs of already generated MHTML parts.
135 std::set<std::string> digests_of_already_serialized_uris_; 147 std::set<std::string> digests_of_already_serialized_uris_;
136 std::string salt_; 148 std::string salt_;
137 149
138 // The callback to call once generation is complete. 150 // The callback to call once generation is complete.
139 const GenerateMHTMLCallback callback_; 151 const GenerateMHTMLCallback callback_;
140 152
141 // Whether the job is finished (set to true only for the short duration of 153 // Whether the job is finished (set to true only for the short duration of
142 // time between MHTMLGenerationManager::JobFinished is called and the job is 154 // time between MHTMLGenerationManager::JobFinished is called and the job is
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 218
207 FrameMsg_SerializeAsMHTML_Params ipc_params; 219 FrameMsg_SerializeAsMHTML_Params ipc_params;
208 ipc_params.job_id = job_id_; 220 ipc_params.job_id = job_id_;
209 ipc_params.mhtml_boundary_marker = mhtml_boundary_marker_; 221 ipc_params.mhtml_boundary_marker = mhtml_boundary_marker_;
210 ipc_params.mhtml_binary_encoding = params_.use_binary_encoding; 222 ipc_params.mhtml_binary_encoding = params_.use_binary_encoding;
211 ipc_params.mhtml_cache_control_policy = params_.cache_control_policy; 223 ipc_params.mhtml_cache_control_policy = params_.cache_control_policy;
212 ipc_params.mhtml_popup_overlay_removal = params_.remove_popup_overlay; 224 ipc_params.mhtml_popup_overlay_removal = params_.remove_popup_overlay;
213 225
214 int frame_tree_node_id = pending_frame_tree_node_ids_.front(); 226 int frame_tree_node_id = pending_frame_tree_node_ids_.front();
215 pending_frame_tree_node_ids_.pop(); 227 pending_frame_tree_node_ids_.pop();
216 ipc_params.is_last_frame = pending_frame_tree_node_ids_.empty();
217 228
218 FrameTreeNode* ftn = FrameTreeNode::GloballyFindByID(frame_tree_node_id); 229 FrameTreeNode* ftn = FrameTreeNode::GloballyFindByID(frame_tree_node_id);
219 if (!ftn) // The contents went away. 230 if (!ftn) // The contents went away.
220 return MhtmlSaveStatus::FRAME_NO_LONGER_EXISTS; 231 return MhtmlSaveStatus::FRAME_NO_LONGER_EXISTS;
221 RenderFrameHost* rfh = ftn->current_frame_host(); 232 RenderFrameHost* rfh = ftn->current_frame_host();
222 233
223 // Get notified if the target of the IPC message dies between responding. 234 // Get notified if the target of the IPC message dies between responding.
224 observed_renderer_process_host_.RemoveAll(); 235 observed_renderer_process_host_.RemoveAll();
225 observed_renderer_process_host_.Add(rfh->GetProcess()); 236 observed_renderer_process_host_.Add(rfh->GetProcess());
226 237
(...skipping 26 matching lines...) Expand all
253 DCHECK_CURRENTLY_ON(BrowserThread::UI); 264 DCHECK_CURRENTLY_ON(BrowserThread::UI);
254 MHTMLGenerationManager::GetInstance()->RenderProcessExited(this); 265 MHTMLGenerationManager::GetInstance()->RenderProcessExited(this);
255 } 266 }
256 267
257 void MHTMLGenerationManager::Job::MarkAsFinished() { 268 void MHTMLGenerationManager::Job::MarkAsFinished() {
258 DCHECK(!is_finished_); 269 DCHECK(!is_finished_);
259 if (is_finished_) 270 if (is_finished_)
260 return; 271 return;
261 272
262 is_finished_ = true; 273 is_finished_ = true;
274
275 // Stopping RenderProcessExited notifications is needed to avoid calling
276 // JobFinished twice. See also https://crbug.com/612098.
277 observed_renderer_process_host_.RemoveAll();
278
263 TRACE_EVENT_NESTABLE_ASYNC_INSTANT0("page-serialization", "JobFinished", 279 TRACE_EVENT_NESTABLE_ASYNC_INSTANT0("page-serialization", "JobFinished",
264 this); 280 this);
265 281
266 // End of job timing reports. 282 // End of job timing reports.
267 if (!wait_on_renderer_start_time_.is_null()) { 283 if (!wait_on_renderer_start_time_.is_null()) {
268 base::TimeDelta renderer_wait_time = 284 base::TimeDelta renderer_wait_time =
269 base::TimeTicks::Now() - wait_on_renderer_start_time_; 285 base::TimeTicks::Now() - wait_on_renderer_start_time_;
270 UMA_HISTOGRAM_TIMES( 286 UMA_HISTOGRAM_TIMES(
271 "PageSerialization.MhtmlGeneration.BrowserWaitForRendererTime." 287 "PageSerialization.MhtmlGeneration.BrowserWaitForRendererTime."
272 "SingleFrame", 288 "SingleFrame",
273 renderer_wait_time); 289 renderer_wait_time);
274 all_renderers_wait_time_ += renderer_wait_time; 290 all_renderers_wait_time_ += renderer_wait_time;
275 } 291 }
276 if (!all_renderers_wait_time_.is_zero()) { 292 if (!all_renderers_wait_time_.is_zero()) {
277 UMA_HISTOGRAM_TIMES( 293 UMA_HISTOGRAM_TIMES(
278 "PageSerialization.MhtmlGeneration.BrowserWaitForRendererTime." 294 "PageSerialization.MhtmlGeneration.BrowserWaitForRendererTime."
279 "FrameTree", 295 "FrameTree",
280 all_renderers_wait_time_); 296 all_renderers_wait_time_);
281 } 297 }
282 if (!all_renderers_main_thread_time_.is_zero()) { 298 if (!all_renderers_main_thread_time_.is_zero()) {
283 UMA_HISTOGRAM_TIMES( 299 UMA_HISTOGRAM_TIMES(
284 "PageSerialization.MhtmlGeneration.RendererMainThreadTime.FrameTree", 300 "PageSerialization.MhtmlGeneration.RendererMainThreadTime.FrameTree",
285 all_renderers_main_thread_time_); 301 all_renderers_main_thread_time_);
286 } 302 }
287 if (!longest_renderer_main_thread_time_.is_zero()) { 303 if (!longest_renderer_main_thread_time_.is_zero()) {
288 UMA_HISTOGRAM_TIMES( 304 UMA_HISTOGRAM_TIMES(
289 "PageSerialization.MhtmlGeneration.RendererMainThreadTime.SlowestFrame", 305 "PageSerialization.MhtmlGeneration.RendererMainThreadTime.SlowestFrame",
290 longest_renderer_main_thread_time_); 306 longest_renderer_main_thread_time_);
291 } 307 }
292
293 // Stopping RenderProcessExited notifications is needed to avoid calling
294 // JobFinished twice. See also https://crbug.com/612098.
295 observed_renderer_process_host_.RemoveAll();
296 } 308 }
297 309
298 void MHTMLGenerationManager::Job::ReportRendererMainThreadTime( 310 void MHTMLGenerationManager::Job::ReportRendererMainThreadTime(
299 base::TimeDelta renderer_main_thread_time) { 311 base::TimeDelta renderer_main_thread_time) {
300 DCHECK(renderer_main_thread_time > base::TimeDelta()); 312 DCHECK(renderer_main_thread_time > base::TimeDelta());
301 if (renderer_main_thread_time > base::TimeDelta()) 313 if (renderer_main_thread_time > base::TimeDelta())
302 all_renderers_main_thread_time_ += renderer_main_thread_time; 314 all_renderers_main_thread_time_ += renderer_main_thread_time;
303 if (renderer_main_thread_time > longest_renderer_main_thread_time_) 315 if (renderer_main_thread_time > longest_renderer_main_thread_time_)
304 longest_renderer_main_thread_time_ = renderer_main_thread_time; 316 longest_renderer_main_thread_time_ = renderer_main_thread_time;
305 } 317 }
306 318
307 void MHTMLGenerationManager::Job::AddFrame(RenderFrameHost* render_frame_host) { 319 void MHTMLGenerationManager::Job::AddFrame(RenderFrameHost* render_frame_host) {
308 auto* rfhi = static_cast<RenderFrameHostImpl*>(render_frame_host); 320 auto* rfhi = static_cast<RenderFrameHostImpl*>(render_frame_host);
309 int frame_tree_node_id = rfhi->frame_tree_node()->frame_tree_node_id(); 321 int frame_tree_node_id = rfhi->frame_tree_node()->frame_tree_node_id();
310 pending_frame_tree_node_ids_.push(frame_tree_node_id); 322 pending_frame_tree_node_ids_.push(frame_tree_node_id);
311 323
312 std::string guid = base::GenerateGUID(); 324 std::string guid = base::GenerateGUID();
313 std::string content_id = base::StringPrintf("<frame-%d-%s@mhtml.blink>", 325 std::string content_id = base::StringPrintf("<frame-%d-%s@mhtml.blink>",
314 frame_tree_node_id, guid.c_str()); 326 frame_tree_node_id, guid.c_str());
315 frame_tree_node_to_content_id_[frame_tree_node_id] = content_id; 327 frame_tree_node_to_content_id_[frame_tree_node_id] = content_id;
316 } 328 }
317 329
318 void MHTMLGenerationManager::Job::RenderProcessHostDestroyed( 330 void MHTMLGenerationManager::Job::RenderProcessHostDestroyed(
319 RenderProcessHost* host) { 331 RenderProcessHost* host) {
320 DCHECK_CURRENTLY_ON(BrowserThread::UI); 332 DCHECK_CURRENTLY_ON(BrowserThread::UI);
321 observed_renderer_process_host_.Remove(host); 333 observed_renderer_process_host_.Remove(host);
322 } 334 }
323 335
324 void MHTMLGenerationManager::Job::CloseFile( 336 void MHTMLGenerationManager::Job::CloseFile(
325 base::Callback<void(int64_t)> callback) { 337 base::Callback<void(std::tuple<MhtmlSaveStatus, int64_t>)> callback,
338 MhtmlSaveStatus save_status) {
326 DCHECK_CURRENTLY_ON(BrowserThread::UI); 339 DCHECK_CURRENTLY_ON(BrowserThread::UI);
340 DCHECK(!mhtml_boundary_marker_.empty());
327 341
328 if (!browser_file_.IsValid()) { 342 if (!browser_file_.IsValid()) {
329 callback.Run(-1); 343 // Only update the status if that won't hide an earlier error.
344 if (save_status == MhtmlSaveStatus::SUCCESS)
345 save_status = MhtmlSaveStatus::FILE_WRITTING_ERROR;
346 callback.Run(std::make_tuple(save_status, -1));
330 return; 347 return;
331 } 348 }
332 349
350 // If no previous error occurred the boundary should be sent.
333 BrowserThread::PostTaskAndReplyWithResult( 351 BrowserThread::PostTaskAndReplyWithResult(
334 BrowserThread::FILE, FROM_HERE, 352 BrowserThread::FILE, FROM_HERE,
335 base::Bind(&MHTMLGenerationManager::Job::CloseFileOnFileThread, 353 base::Bind(
336 base::Passed(std::move(browser_file_))), 354 &MHTMLGenerationManager::Job::CloseFileOnFileThread, save_status,
355 (save_status == MhtmlSaveStatus::SUCCESS ? mhtml_boundary_marker_
356 : std::string()),
357 base::Passed(std::move(browser_file_))),
dcheng 2017/03/09 01:56:51 Nit: base::Passed(&browser_file_)
carlosk 2017/03/09 22:03:35 Done.
337 callback); 358 callback);
338 } 359 }
339 360
340 bool MHTMLGenerationManager::Job::IsMessageFromFrameExpected( 361 bool MHTMLGenerationManager::Job::IsMessageFromFrameExpected(
341 RenderFrameHostImpl* sender) { 362 RenderFrameHostImpl* sender) {
342 int sender_id = sender->frame_tree_node()->frame_tree_node_id(); 363 int sender_id = sender->frame_tree_node()->frame_tree_node_id();
343 if (sender_id != frame_tree_node_id_of_busy_frame_) 364 if (sender_id != frame_tree_node_id_of_busy_frame_)
344 return false; 365 return false;
345 366
346 // We only expect one message per frame - let's make sure subsequent messages 367 // We only expect one message per frame - let's make sure subsequent messages
(...skipping 24 matching lines...) Expand all
371 digests_of_uris_of_serialized_resources.end()); 392 digests_of_uris_of_serialized_resources.end());
372 393
373 // Report success if all frames have been processed. 394 // Report success if all frames have been processed.
374 if (pending_frame_tree_node_ids_.empty()) 395 if (pending_frame_tree_node_ids_.empty())
375 return MhtmlSaveStatus::SUCCESS; 396 return MhtmlSaveStatus::SUCCESS;
376 397
377 return SendToNextRenderFrame(); 398 return SendToNextRenderFrame();
378 } 399 }
379 400
380 // static 401 // static
381 int64_t MHTMLGenerationManager::Job::CloseFileOnFileThread(base::File file) { 402 std::tuple<MhtmlSaveStatus, int64_t>
403 MHTMLGenerationManager::Job::CloseFileOnFileThread(MhtmlSaveStatus save_status,
404 std::string boundary,
405 base::File file) {
382 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 406 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
383 DCHECK(file.IsValid()); 407
384 int64_t file_size = file.GetLength(); 408 // If no previous error occurred the boundary should have been provided.
385 file.Close(); 409 if (save_status == MhtmlSaveStatus::SUCCESS) {
386 return file_size; 410 TRACE_EVENT0("page-serialization",
411 "MHTMLGenerationManager::Job MHTML footer writing");
412 DCHECK(!boundary.empty());
413 std::string footer = base::StringPrintf("--%s--\r\n", boundary.c_str());
414 DCHECK(base::IsStringASCII(footer));
415 if (file.WriteAtCurrentPos(footer.data(), footer.size()) < 0)
416 save_status = MhtmlSaveStatus::FILE_WRITTING_ERROR;
417 }
418
419 // If the file is still valid try to close it. Only update the status if that
420 // won't hide an earlier error.
421 int64_t file_size = -1;
422 if (file.IsValid()) {
423 file_size = file.GetLength();
424 file.Close();
425 } else if (save_status == MhtmlSaveStatus::SUCCESS) {
426 save_status = MhtmlSaveStatus::FILE_CLOSING_ERROR;
427 }
428
429 return std::make_tuple(save_status, file_size);
387 } 430 }
388 431
389 MHTMLGenerationManager* MHTMLGenerationManager::GetInstance() { 432 MHTMLGenerationManager* MHTMLGenerationManager::GetInstance() {
390 return base::Singleton<MHTMLGenerationManager>::get(); 433 return base::Singleton<MHTMLGenerationManager>::get();
391 } 434 }
392 435
393 MHTMLGenerationManager::MHTMLGenerationManager() : next_job_id_(0) {} 436 MHTMLGenerationManager::MHTMLGenerationManager() : next_job_id_(0) {}
394 437
395 MHTMLGenerationManager::~MHTMLGenerationManager() { 438 MHTMLGenerationManager::~MHTMLGenerationManager() {
396 } 439 }
(...skipping 30 matching lines...) Expand all
427 NOTREACHED(); 470 NOTREACHED();
428 ReceivedBadMessage(sender->GetProcess(), 471 ReceivedBadMessage(sender->GetProcess(),
429 bad_message::DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE); 472 bad_message::DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE);
430 return; 473 return;
431 } 474 }
432 475
433 TRACE_EVENT_NESTABLE_ASYNC_END0("page-serialization", "WaitingOnRenderer", 476 TRACE_EVENT_NESTABLE_ASYNC_END0("page-serialization", "WaitingOnRenderer",
434 job); 477 job);
435 job->ReportRendererMainThreadTime(renderer_main_thread_time); 478 job->ReportRendererMainThreadTime(renderer_main_thread_time);
436 479
480 // If the renderer succeeded notify the Job and update the status.
437 if (save_status == MhtmlSaveStatus::SUCCESS) { 481 if (save_status == MhtmlSaveStatus::SUCCESS) {
438 save_status = job->OnSerializeAsMHTMLResponse( 482 save_status = job->OnSerializeAsMHTMLResponse(
439 digests_of_uris_of_serialized_resources); 483 digests_of_uris_of_serialized_resources);
440 } 484 }
441 485
486 // If there was a failure (either from the renderer or from the job) then
487 // terminate the job and return.
442 if (save_status != MhtmlSaveStatus::SUCCESS) { 488 if (save_status != MhtmlSaveStatus::SUCCESS) {
443 JobFinished(job, save_status); 489 JobFinished(job, save_status);
444 return; 490 return;
445 } 491 }
446 492
493 // Otherwise report completion if the job is done.
447 if (job->IsDone()) 494 if (job->IsDone())
448 JobFinished(job, MhtmlSaveStatus::SUCCESS); 495 JobFinished(job, MhtmlSaveStatus::SUCCESS);
449 } 496 }
450 497
451 // static 498 // static
452 base::File MHTMLGenerationManager::CreateFile(const base::FilePath& file_path) { 499 base::File MHTMLGenerationManager::CreateFile(const base::FilePath& file_path) {
453 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 500 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
454 501
455 // SECURITY NOTE: A file descriptor to the file created below will be passed 502 // SECURITY NOTE: A file descriptor to the file created below will be passed
456 // to multiple renderer processes which (in out-of-process iframes mode) can 503 // to multiple renderer processes which (in out-of-process iframes mode) can
(...skipping 29 matching lines...) Expand all
486 MhtmlSaveStatus save_status = job->SendToNextRenderFrame(); 533 MhtmlSaveStatus save_status = job->SendToNextRenderFrame();
487 if (save_status != MhtmlSaveStatus::SUCCESS) { 534 if (save_status != MhtmlSaveStatus::SUCCESS) {
488 JobFinished(job, save_status); 535 JobFinished(job, save_status);
489 } 536 }
490 } 537 }
491 538
492 void MHTMLGenerationManager::JobFinished(Job* job, 539 void MHTMLGenerationManager::JobFinished(Job* job,
493 MhtmlSaveStatus save_status) { 540 MhtmlSaveStatus save_status) {
494 DCHECK_CURRENTLY_ON(BrowserThread::UI); 541 DCHECK_CURRENTLY_ON(BrowserThread::UI);
495 DCHECK(job); 542 DCHECK(job);
496
497 job->MarkAsFinished(); 543 job->MarkAsFinished();
498 job->CloseFile( 544 job->CloseFile(
499 base::Bind(&MHTMLGenerationManager::OnFileClosed, 545 base::Bind(&MHTMLGenerationManager::OnFileClosed,
500 base::Unretained(this), // Safe b/c |this| is a singleton. 546 base::Unretained(this), // Safe b/c |this| is a singleton.
501 job->id(), save_status)); 547 job->id()),
548 save_status);
502 } 549 }
503 550
504 void MHTMLGenerationManager::OnFileClosed(int job_id, 551 void MHTMLGenerationManager::OnFileClosed(
505 MhtmlSaveStatus save_status, 552 int job_id,
506 int64_t file_size) { 553 std::tuple<MhtmlSaveStatus, int64_t> save_status_size) {
507 DCHECK_CURRENTLY_ON(BrowserThread::UI); 554 DCHECK_CURRENTLY_ON(BrowserThread::UI);
508 555 MhtmlSaveStatus save_status = std::get<0>(save_status_size);
509 // Checks if an error happened while closing the file. 556 int64_t file_size = std::get<1>(save_status_size);
510 if (save_status == MhtmlSaveStatus::SUCCESS && file_size < 0)
511 save_status = MhtmlSaveStatus::FILE_CLOSING_ERROR;
512 557
513 Job* job = FindJob(job_id); 558 Job* job = FindJob(job_id);
559 DCHECK(job);
514 TRACE_EVENT_NESTABLE_ASYNC_END2( 560 TRACE_EVENT_NESTABLE_ASYNC_END2(
515 "page-serialization", "SavingMhtmlJob", job, "job save status", 561 "page-serialization", "SavingMhtmlJob", job, "job save status",
516 GetMhtmlSaveStatusLabel(save_status), "file size", file_size); 562 GetMhtmlSaveStatusLabel(save_status), "file size", file_size);
517 UMA_HISTOGRAM_TIMES("PageSerialization.MhtmlGeneration.FullPageSavingTime", 563 UMA_HISTOGRAM_TIMES("PageSerialization.MhtmlGeneration.FullPageSavingTime",
518 base::TimeTicks::Now() - job->creation_time()); 564 base::TimeTicks::Now() - job->creation_time());
519 UMA_HISTOGRAM_ENUMERATION("PageSerialization.MhtmlGeneration.FinalSaveStatus", 565 UMA_HISTOGRAM_ENUMERATION("PageSerialization.MhtmlGeneration.FinalSaveStatus",
520 static_cast<int>(save_status), 566 static_cast<int>(save_status),
521 static_cast<int>(MhtmlSaveStatus::LAST)); 567 static_cast<int>(MhtmlSaveStatus::LAST));
522 job->callback().Run(save_status == MhtmlSaveStatus::SUCCESS ? file_size : -1); 568 job->callback().Run(save_status == MhtmlSaveStatus::SUCCESS ? file_size : -1);
523 id_to_job_.erase(job_id); 569 id_to_job_.erase(job_id);
(...skipping 21 matching lines...) Expand all
545 return iter->second.get(); 591 return iter->second.get();
546 } 592 }
547 593
548 void MHTMLGenerationManager::RenderProcessExited(Job* job) { 594 void MHTMLGenerationManager::RenderProcessExited(Job* job) {
549 DCHECK_CURRENTLY_ON(BrowserThread::UI); 595 DCHECK_CURRENTLY_ON(BrowserThread::UI);
550 DCHECK(job); 596 DCHECK(job);
551 JobFinished(job, MhtmlSaveStatus::RENDER_PROCESS_EXITED); 597 JobFinished(job, MhtmlSaveStatus::RENDER_PROCESS_EXITED);
552 } 598 }
553 599
554 } // namespace content 600 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698