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

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

Issue 2519273002: Fail when saving page as MHTML provides information about the cause. (Closed)
Patch Set: Minor changes. Created 4 years, 1 month 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
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 49
50 const GenerateMHTMLCallback& callback() const { return callback_; } 50 const GenerateMHTMLCallback& callback() const { return callback_; }
51 51
52 // Indicates whether we expect a message from the |sender| at this time. 52 // Indicates whether we expect a message from the |sender| at this time.
53 // We expect only one message per frame - therefore calling this method 53 // We expect only one message per frame - therefore calling this method
54 // will always clear |frame_tree_node_id_of_busy_frame_|. 54 // will always clear |frame_tree_node_id_of_busy_frame_|.
55 bool IsMessageFromFrameExpected(RenderFrameHostImpl* sender); 55 bool IsMessageFromFrameExpected(RenderFrameHostImpl* sender);
56 56
57 // Handler for FrameHostMsg_SerializeAsMHTMLResponse (a notification from the 57 // Handler for FrameHostMsg_SerializeAsMHTMLResponse (a notification from the
58 // renderer that the MHTML generation for previous frame has finished). 58 // renderer that the MHTML generation for previous frame has finished).
59 // Returns |true| upon success; |false| otherwise. 59 // Returns MhtmlSaveStatus::SUCCESS or a specific error status.
60 bool OnSerializeAsMHTMLResponse( 60 MhtmlSaveStatus OnSerializeAsMHTMLResponse(
61 const std::set<std::string>& digests_of_uris_of_serialized_resources); 61 const std::set<std::string>& digests_of_uris_of_serialized_resources);
62 62
63 // Sends IPC to the renderer, asking for MHTML generation of the next frame. 63 // Sends IPC to the renderer, asking for MHTML generation of the next frame.
64 // 64 // Returns MhtmlSaveStatus::SUCCESS or a specific error status.
65 // Returns true if the message was sent successfully; false otherwise. 65 MhtmlSaveStatus SendToNextRenderFrame();
66 bool SendToNextRenderFrame();
67 66
68 // Indicates if more calls to SendToNextRenderFrame are needed. 67 // Indicates if more calls to SendToNextRenderFrame are needed.
69 bool IsDone() const { 68 bool IsDone() const {
70 bool waiting_for_response_from_renderer = 69 bool waiting_for_response_from_renderer =
71 frame_tree_node_id_of_busy_frame_ != 70 frame_tree_node_id_of_busy_frame_ !=
72 FrameTreeNode::kFrameTreeNodeInvalidId; 71 FrameTreeNode::kFrameTreeNodeInvalidId;
73 bool no_more_requests_to_send = pending_frame_tree_node_ids_.empty(); 72 bool no_more_requests_to_send = pending_frame_tree_node_ids_.empty();
74 return !waiting_for_response_from_renderer && no_more_requests_to_send; 73 return !waiting_for_response_from_renderer && no_more_requests_to_send;
75 } 74 }
76 75
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
194 int routing_id = 193 int routing_id =
195 ftn->render_manager()->GetRoutingIdForSiteInstance(site_instance); 194 ftn->render_manager()->GetRoutingIdForSiteInstance(site_instance);
196 if (routing_id == MSG_ROUTING_NONE) 195 if (routing_id == MSG_ROUTING_NONE)
197 continue; 196 continue;
198 197
199 result[routing_id] = content_id; 198 result[routing_id] = content_id;
200 } 199 }
201 return result; 200 return result;
202 } 201 }
203 202
204 bool MHTMLGenerationManager::Job::SendToNextRenderFrame() { 203 MhtmlSaveStatus MHTMLGenerationManager::Job::SendToNextRenderFrame() {
205 DCHECK(browser_file_.IsValid()); 204 DCHECK(browser_file_.IsValid());
206 DCHECK(!pending_frame_tree_node_ids_.empty()); 205 DCHECK(!pending_frame_tree_node_ids_.empty());
207 206
208 FrameMsg_SerializeAsMHTML_Params ipc_params; 207 FrameMsg_SerializeAsMHTML_Params ipc_params;
209 ipc_params.job_id = job_id_; 208 ipc_params.job_id = job_id_;
210 ipc_params.mhtml_boundary_marker = mhtml_boundary_marker_; 209 ipc_params.mhtml_boundary_marker = mhtml_boundary_marker_;
211 ipc_params.mhtml_binary_encoding = params_.use_binary_encoding; 210 ipc_params.mhtml_binary_encoding = params_.use_binary_encoding;
212 ipc_params.mhtml_cache_control_policy = params_.cache_control_policy; 211 ipc_params.mhtml_cache_control_policy = params_.cache_control_policy;
213 212
214 int frame_tree_node_id = pending_frame_tree_node_ids_.front(); 213 int frame_tree_node_id = pending_frame_tree_node_ids_.front();
215 pending_frame_tree_node_ids_.pop(); 214 pending_frame_tree_node_ids_.pop();
216 ipc_params.is_last_frame = pending_frame_tree_node_ids_.empty(); 215 ipc_params.is_last_frame = pending_frame_tree_node_ids_.empty();
217 216
218 FrameTreeNode* ftn = FrameTreeNode::GloballyFindByID(frame_tree_node_id); 217 FrameTreeNode* ftn = FrameTreeNode::GloballyFindByID(frame_tree_node_id);
219 if (!ftn) // The contents went away. 218 if (!ftn) // The contents went away.
220 return false; 219 return MhtmlSaveStatus::FRAME_NO_LONGER_EXIST;
221 RenderFrameHost* rfh = ftn->current_frame_host(); 220 RenderFrameHost* rfh = ftn->current_frame_host();
222 221
223 // Get notified if the target of the IPC message dies between responding. 222 // Get notified if the target of the IPC message dies between responding.
224 observed_renderer_process_host_.RemoveAll(); 223 observed_renderer_process_host_.RemoveAll();
225 observed_renderer_process_host_.Add(rfh->GetProcess()); 224 observed_renderer_process_host_.Add(rfh->GetProcess());
226 225
227 // Tell the renderer to skip (= deduplicate) already covered MHTML parts. 226 // Tell the renderer to skip (= deduplicate) already covered MHTML parts.
228 ipc_params.salt = salt_; 227 ipc_params.salt = salt_;
229 ipc_params.digests_of_uris_to_skip = digests_of_already_serialized_uris_; 228 ipc_params.digests_of_uris_to_skip = digests_of_already_serialized_uris_;
230 229
231 ipc_params.destination_file = IPC::GetPlatformFileForTransit( 230 ipc_params.destination_file = IPC::GetPlatformFileForTransit(
232 browser_file_.GetPlatformFile(), false); // |close_source_handle|. 231 browser_file_.GetPlatformFile(), false); // |close_source_handle|.
233 ipc_params.frame_routing_id_to_content_id = 232 ipc_params.frame_routing_id_to_content_id =
234 CreateFrameRoutingIdToContentId(rfh->GetSiteInstance()); 233 CreateFrameRoutingIdToContentId(rfh->GetSiteInstance());
235 234
236 // Send the IPC asking the renderer to serialize the frame. 235 // Send the IPC asking the renderer to serialize the frame.
237 DCHECK_EQ(FrameTreeNode::kFrameTreeNodeInvalidId, 236 DCHECK_EQ(FrameTreeNode::kFrameTreeNodeInvalidId,
238 frame_tree_node_id_of_busy_frame_); 237 frame_tree_node_id_of_busy_frame_);
239 frame_tree_node_id_of_busy_frame_ = frame_tree_node_id; 238 frame_tree_node_id_of_busy_frame_ = frame_tree_node_id;
240 rfh->Send(new FrameMsg_SerializeAsMHTML(rfh->GetRoutingID(), ipc_params)); 239 rfh->Send(new FrameMsg_SerializeAsMHTML(rfh->GetRoutingID(), ipc_params));
241 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("page-serialization", "WaitingOnRenderer", 240 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("page-serialization", "WaitingOnRenderer",
242 this, "frame tree node id", 241 this, "frame tree node id",
243 frame_tree_node_id); 242 frame_tree_node_id);
244 DCHECK(wait_on_renderer_start_time_.is_null()); 243 DCHECK(wait_on_renderer_start_time_.is_null());
245 wait_on_renderer_start_time_ = base::TimeTicks::Now(); 244 wait_on_renderer_start_time_ = base::TimeTicks::Now();
246 return true; 245 return MhtmlSaveStatus::SUCCESS;
247 } 246 }
248 247
249 void MHTMLGenerationManager::Job::RenderProcessExited( 248 void MHTMLGenerationManager::Job::RenderProcessExited(
250 RenderProcessHost* host, 249 RenderProcessHost* host,
251 base::TerminationStatus status, 250 base::TerminationStatus status,
252 int exit_code) { 251 int exit_code) {
253 DCHECK_CURRENTLY_ON(BrowserThread::UI); 252 DCHECK_CURRENTLY_ON(BrowserThread::UI);
254 MHTMLGenerationManager::GetInstance()->RenderProcessExited(this); 253 MHTMLGenerationManager::GetInstance()->RenderProcessExited(this);
255 } 254 }
256 255
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 if (sender_id != frame_tree_node_id_of_busy_frame_) 342 if (sender_id != frame_tree_node_id_of_busy_frame_)
344 return false; 343 return false;
345 344
346 // We only expect one message per frame - let's make sure subsequent messages 345 // We only expect one message per frame - let's make sure subsequent messages
347 // from the same |sender| will be rejected. 346 // from the same |sender| will be rejected.
348 frame_tree_node_id_of_busy_frame_ = FrameTreeNode::kFrameTreeNodeInvalidId; 347 frame_tree_node_id_of_busy_frame_ = FrameTreeNode::kFrameTreeNodeInvalidId;
349 348
350 return true; 349 return true;
351 } 350 }
352 351
353 bool MHTMLGenerationManager::Job::OnSerializeAsMHTMLResponse( 352 MhtmlSaveStatus MHTMLGenerationManager::Job::OnSerializeAsMHTMLResponse(
354 const std::set<std::string>& digests_of_uris_of_serialized_resources) { 353 const std::set<std::string>& digests_of_uris_of_serialized_resources) {
355 DCHECK(!wait_on_renderer_start_time_.is_null()); 354 DCHECK(!wait_on_renderer_start_time_.is_null());
356 base::TimeDelta renderer_wait_time = 355 base::TimeDelta renderer_wait_time =
357 base::TimeTicks::Now() - wait_on_renderer_start_time_; 356 base::TimeTicks::Now() - wait_on_renderer_start_time_;
358 UMA_HISTOGRAM_TIMES( 357 UMA_HISTOGRAM_TIMES(
359 "PageSerialization.MhtmlGeneration.BrowserWaitForRendererTime." 358 "PageSerialization.MhtmlGeneration.BrowserWaitForRendererTime."
360 "SingleFrame", 359 "SingleFrame",
361 renderer_wait_time); 360 renderer_wait_time);
362 all_renderers_wait_time_ += renderer_wait_time; 361 all_renderers_wait_time_ += renderer_wait_time;
363 wait_on_renderer_start_time_ = base::TimeTicks(); 362 wait_on_renderer_start_time_ = base::TimeTicks();
364 363
365 // Renderer should be deduping resources with the same uris. 364 // Renderer should be deduping resources with the same uris.
366 DCHECK_EQ(0u, base::STLSetIntersection<std::set<std::string>>( 365 DCHECK_EQ(0u, base::STLSetIntersection<std::set<std::string>>(
367 digests_of_already_serialized_uris_, 366 digests_of_already_serialized_uris_,
368 digests_of_uris_of_serialized_resources).size()); 367 digests_of_uris_of_serialized_resources).size());
369 digests_of_already_serialized_uris_.insert( 368 digests_of_already_serialized_uris_.insert(
370 digests_of_uris_of_serialized_resources.begin(), 369 digests_of_uris_of_serialized_resources.begin(),
371 digests_of_uris_of_serialized_resources.end()); 370 digests_of_uris_of_serialized_resources.end());
372 371
372 // Report success if all frames have been processed.
373 if (pending_frame_tree_node_ids_.empty()) 373 if (pending_frame_tree_node_ids_.empty())
374 return true; // Report success - all frames have been processed. 374 return MhtmlSaveStatus::SUCCESS;
375 375
376 return SendToNextRenderFrame(); 376 return SendToNextRenderFrame();
377 } 377 }
378 378
379 // static 379 // static
380 int64_t MHTMLGenerationManager::Job::CloseFileOnFileThread(base::File file) { 380 int64_t MHTMLGenerationManager::Job::CloseFileOnFileThread(base::File file) {
381 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 381 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
382 DCHECK(file.IsValid()); 382 DCHECK(file.IsValid());
383 int64_t file_size = file.GetLength(); 383 int64_t file_size = file.GetLength();
384 file.Close(); 384 file.Close();
(...skipping 24 matching lines...) Expand all
409 BrowserThread::FILE, FROM_HERE, 409 BrowserThread::FILE, FROM_HERE,
410 base::Bind(&MHTMLGenerationManager::CreateFile, params.file_path), 410 base::Bind(&MHTMLGenerationManager::CreateFile, params.file_path),
411 base::Bind(&MHTMLGenerationManager::OnFileAvailable, 411 base::Bind(&MHTMLGenerationManager::OnFileAvailable,
412 base::Unretained(this), // Safe b/c |this| is a singleton. 412 base::Unretained(this), // Safe b/c |this| is a singleton.
413 job->id())); 413 job->id()));
414 } 414 }
415 415
416 void MHTMLGenerationManager::OnSerializeAsMHTMLResponse( 416 void MHTMLGenerationManager::OnSerializeAsMHTMLResponse(
417 RenderFrameHostImpl* sender, 417 RenderFrameHostImpl* sender,
418 int job_id, 418 int job_id,
419 bool mhtml_generation_in_renderer_succeeded, 419 MhtmlSaveStatus save_status,
420 const std::set<std::string>& digests_of_uris_of_serialized_resources, 420 const std::set<std::string>& digests_of_uris_of_serialized_resources,
421 base::TimeDelta renderer_main_thread_time) { 421 base::TimeDelta renderer_main_thread_time) {
422 DCHECK_CURRENTLY_ON(BrowserThread::UI); 422 DCHECK_CURRENTLY_ON(BrowserThread::UI);
423 423
424 Job* job = FindJob(job_id); 424 Job* job = FindJob(job_id);
425 if (!job || !job->IsMessageFromFrameExpected(sender)) { 425 if (!job || !job->IsMessageFromFrameExpected(sender)) {
426 NOTREACHED(); 426 NOTREACHED();
427 ReceivedBadMessage(sender->GetProcess(), 427 ReceivedBadMessage(sender->GetProcess(),
428 bad_message::DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE); 428 bad_message::DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE);
429 return; 429 return;
430 } 430 }
431 431
432 TRACE_EVENT_NESTABLE_ASYNC_END0("page-serialization", "WaitingOnRenderer", 432 TRACE_EVENT_NESTABLE_ASYNC_END0("page-serialization", "WaitingOnRenderer",
433 job); 433 job);
434 job->ReportRendererMainThreadTime(renderer_main_thread_time); 434 job->ReportRendererMainThreadTime(renderer_main_thread_time);
435 435
436 if (!mhtml_generation_in_renderer_succeeded) { 436 if (save_status == MhtmlSaveStatus::SUCCESS) {
437 JobFinished(job, JobStatus::FAILURE); 437 save_status = job->OnSerializeAsMHTMLResponse(
438 return; 438 digests_of_uris_of_serialized_resources);
439 } 439 }
440 440
441 if (!job->OnSerializeAsMHTMLResponse( 441 if (save_status != MhtmlSaveStatus::SUCCESS) {
442 digests_of_uris_of_serialized_resources)) { 442 JobFinished(job, save_status);
443 JobFinished(job, JobStatus::FAILURE);
444 return; 443 return;
445 } 444 }
446 445
447 if (job->IsDone()) 446 if (job->IsDone())
448 JobFinished(job, JobStatus::SUCCESS); 447 JobFinished(job, MhtmlSaveStatus::SUCCESS);
449 } 448 }
450 449
451 // static 450 // static
452 base::File MHTMLGenerationManager::CreateFile(const base::FilePath& file_path) { 451 base::File MHTMLGenerationManager::CreateFile(const base::FilePath& file_path) {
453 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 452 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
454 453
455 // SECURITY NOTE: A file descriptor to the file created below will be passed 454 // 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 455 // to multiple renderer processes which (in out-of-process iframes mode) can
457 // act on behalf of separate web principals. Therefore it is important to 456 // act on behalf of separate web principals. Therefore it is important to
458 // only allow writing to the file and forbid reading from the file (as this 457 // only allow writing to the file and forbid reading from the file (as this
(...skipping 11 matching lines...) Expand all
470 469
471 void MHTMLGenerationManager::OnFileAvailable(int job_id, 470 void MHTMLGenerationManager::OnFileAvailable(int job_id,
472 base::File browser_file) { 471 base::File browser_file) {
473 DCHECK_CURRENTLY_ON(BrowserThread::UI); 472 DCHECK_CURRENTLY_ON(BrowserThread::UI);
474 473
475 Job* job = FindJob(job_id); 474 Job* job = FindJob(job_id);
476 DCHECK(job); 475 DCHECK(job);
477 476
478 if (!browser_file.IsValid()) { 477 if (!browser_file.IsValid()) {
479 LOG(ERROR) << "Failed to create file"; 478 LOG(ERROR) << "Failed to create file";
480 JobFinished(job, JobStatus::FAILURE); 479 JobFinished(job, MhtmlSaveStatus::FILE_CREATION_ERROR);
481 return; 480 return;
482 } 481 }
483 482
484 job->set_browser_file(std::move(browser_file)); 483 job->set_browser_file(std::move(browser_file));
485 484
486 if (!job->SendToNextRenderFrame()) { 485 MhtmlSaveStatus save_status = job->SendToNextRenderFrame();
487 JobFinished(job, JobStatus::FAILURE); 486 if (save_status != MhtmlSaveStatus::SUCCESS) {
487 JobFinished(job, save_status);
488 } 488 }
489 } 489 }
490 490
491 void MHTMLGenerationManager::JobFinished(Job* job, JobStatus job_status) { 491 void MHTMLGenerationManager::JobFinished(Job* job,
492 MhtmlSaveStatus save_status) {
492 DCHECK_CURRENTLY_ON(BrowserThread::UI); 493 DCHECK_CURRENTLY_ON(BrowserThread::UI);
493 DCHECK(job); 494 DCHECK(job);
494 495
495 job->MarkAsFinished(); 496 job->MarkAsFinished();
496 job->CloseFile( 497 job->CloseFile(
497 base::Bind(&MHTMLGenerationManager::OnFileClosed, 498 base::Bind(&MHTMLGenerationManager::OnFileClosed,
498 base::Unretained(this), // Safe b/c |this| is a singleton. 499 base::Unretained(this), // Safe b/c |this| is a singleton.
499 job->id(), job_status)); 500 job->id(), save_status));
500 } 501 }
501 502
502 void MHTMLGenerationManager::OnFileClosed(int job_id, 503 void MHTMLGenerationManager::OnFileClosed(int job_id,
503 JobStatus job_status, 504 MhtmlSaveStatus save_status,
504 int64_t file_size) { 505 int64_t file_size) {
505 DCHECK_CURRENTLY_ON(BrowserThread::UI); 506 DCHECK_CURRENTLY_ON(BrowserThread::UI);
506 507
508 // Checks if an error happened while closing the file.
509 if (save_status == MhtmlSaveStatus::SUCCESS && file_size < 0)
510 save_status = MhtmlSaveStatus::FILE_CLOSING_ERROR;
Łukasz Anforowicz 2016/11/22 19:22:13 Interesting, I didn't know that base::File::GetLen
carlosk 2016/11/22 23:26:23 It can't. But that's the "error code" response whe
511
507 Job* job = FindJob(job_id); 512 Job* job = FindJob(job_id);
508 TRACE_EVENT_NESTABLE_ASYNC_END2( 513 TRACE_EVENT_NESTABLE_ASYNC_END2(
509 "page-serialization", "SavingMhtmlJob", job, "job result", 514 "page-serialization", "SavingMhtmlJob", job, "job save status",
510 job_status == JobStatus::SUCCESS ? "success" : "failure", "file size", 515 save_status == MhtmlSaveStatus::SUCCESS
511 file_size); 516 ? "success"
517 : base::StringPrintf("failure (%d)", static_cast<int>(save_status)),
518 "file size", file_size);
512 UMA_HISTOGRAM_TIMES("PageSerialization.MhtmlGeneration.FullPageSavingTime", 519 UMA_HISTOGRAM_TIMES("PageSerialization.MhtmlGeneration.FullPageSavingTime",
513 base::TimeTicks::Now() - job->creation_time()); 520 base::TimeTicks::Now() - job->creation_time());
514 job->callback().Run(job_status == JobStatus::SUCCESS ? file_size : -1); 521 UMA_HISTOGRAM_ENUMERATION("PageSerialization.MhtmlGeneration.FinalSaveStatus",
522 static_cast<int>(save_status),
523 static_cast<int>(MhtmlSaveStatus::STATUS_COUNT));
524 job->callback().Run(save_status == MhtmlSaveStatus::SUCCESS ? file_size : -1);
515 id_to_job_.erase(job_id); 525 id_to_job_.erase(job_id);
516 } 526 }
517 527
518 MHTMLGenerationManager::Job* MHTMLGenerationManager::NewJob( 528 MHTMLGenerationManager::Job* MHTMLGenerationManager::NewJob(
519 WebContents* web_contents, 529 WebContents* web_contents,
520 const MHTMLGenerationParams& params, 530 const MHTMLGenerationParams& params,
521 const GenerateMHTMLCallback& callback) { 531 const GenerateMHTMLCallback& callback) {
522 DCHECK_CURRENTLY_ON(BrowserThread::UI); 532 DCHECK_CURRENTLY_ON(BrowserThread::UI);
523 533
524 Job* job = new Job(++next_job_id_, web_contents, params, callback); 534 Job* job = new Job(++next_job_id_, web_contents, params, callback);
525 id_to_job_[job->id()] = base::WrapUnique(job); 535 id_to_job_[job->id()] = base::WrapUnique(job);
526 return job; 536 return job;
527 } 537 }
528 538
529 MHTMLGenerationManager::Job* MHTMLGenerationManager::FindJob(int job_id) { 539 MHTMLGenerationManager::Job* MHTMLGenerationManager::FindJob(int job_id) {
530 DCHECK_CURRENTLY_ON(BrowserThread::UI); 540 DCHECK_CURRENTLY_ON(BrowserThread::UI);
531 541
532 auto iter = id_to_job_.find(job_id); 542 auto iter = id_to_job_.find(job_id);
533 if (iter == id_to_job_.end()) { 543 if (iter == id_to_job_.end()) {
534 NOTREACHED(); 544 NOTREACHED();
535 return nullptr; 545 return nullptr;
536 } 546 }
537 return iter->second.get(); 547 return iter->second.get();
538 } 548 }
539 549
540 void MHTMLGenerationManager::RenderProcessExited(Job* job) { 550 void MHTMLGenerationManager::RenderProcessExited(Job* job) {
541 DCHECK_CURRENTLY_ON(BrowserThread::UI); 551 DCHECK_CURRENTLY_ON(BrowserThread::UI);
542 DCHECK(job); 552 DCHECK(job);
543 JobFinished(job, JobStatus::FAILURE); 553 JobFinished(job, MhtmlSaveStatus::RENDER_PROCESS_EXITED);
544 } 554 }
545 555
546 } // namespace content 556 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698