Chromium Code Reviews| Index: content/browser/download/mhtml_generation_manager.cc |
| diff --git a/content/browser/download/mhtml_generation_manager.cc b/content/browser/download/mhtml_generation_manager.cc |
| index e011f42dae39635230366e9daa7947ffb863d6d8..9d112ffb716b1a29caf5bb17a657b4f0d8d94a2c 100644 |
| --- a/content/browser/download/mhtml_generation_manager.cc |
| +++ b/content/browser/download/mhtml_generation_manager.cc |
| @@ -20,6 +20,8 @@ |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/render_process_host_observer.h" |
| #include "content/public/browser/web_contents.h" |
| +#include "crypto/sha2.h" |
| +#include "url/gurl.h" |
| namespace content { |
| @@ -34,15 +36,18 @@ class MHTMLGenerationManager::Job : public RenderProcessHostObserver { |
| GenerateMHTMLCallback callback() const { return callback_; } |
| - // Sends IPC to the renderer, asking for MHTML generation of the next frame. |
| - // |
| - // Returns true if the message was sent successfully; false otherwise. |
| - // |
| - // See FrameMsg_SerializeAsMHTML IPC message for description of |
| - // |mhtml_boundary_marker| parameter. |
| - bool SendToNextRenderFrame(const std::string& mhtml_boundary_marker); |
| + // Sends IPC to the renderer of the first frame, asking it to start |
| + // MHTML serialization. |
| + // Returns |true| upon success; |false| otherwise. |
| + bool SendToFirstFrame(); |
| - // Indicates if more calls to SendToNextRenderFrame are needed. |
| + // Handler for ViewHostMsg_SavedPageAsMHTML (a notification from the renderer |
| + // that the MHTML generation for previous frame has finished). |
| + // Returns |true| upon success; |false| otherwise. |
| + bool OnSavedPageAsMHTML(std::string mhtml_boundary_marker, |
| + const std::set<GURL>& uris_of_generated_mhtml_parts); |
| + |
| + // Indicates if the job has completed. |
| bool GotMoreFramesToProcess() { |
| return !pending_frame_tree_node_ids_.empty(); |
| } |
| @@ -66,6 +71,14 @@ class MHTMLGenerationManager::Job : public RenderProcessHostObserver { |
| std::map<int, std::string> CreateFrameRoutingIdToContentId( |
| SiteInstance* site_instance); |
| + // Sends IPC to the renderer, asking for MHTML generation of the next frame. |
| + // |
| + // Returns true if the message was sent successfully; false otherwise. |
| + // |
| + // See FrameMsg_SerializeAsMHTML IPC message for description of |
| + // |mhtml_boundary_marker| parameter. |
| + bool SendToNextRenderFrame(const std::string& mhtml_boundary_marker); |
| + |
| // Id used to map renderer responses to jobs. |
| // See also MHTMLGenerationManager::id_to_job_ map. |
| int job_id_; |
| @@ -80,6 +93,9 @@ class MHTMLGenerationManager::Job : public RenderProcessHostObserver { |
| // for more details about what "content ids" are and how they are used). |
| std::map<int, std::string> frame_tree_node_to_content_id_; |
| + // URIs of already generated MHTML parts. |
| + std::set<GURL> already_serialized_uris_; |
| + |
| // The callback to call once generation is complete. |
| GenerateMHTMLCallback callback_; |
| @@ -138,9 +154,13 @@ bool MHTMLGenerationManager::Job::SendToNextRenderFrame( |
| DCHECK(browser_file_.IsValid()); |
| DCHECK_LT(0u, pending_frame_tree_node_ids_.size()); |
| + FrameMsg_SerializeAsMHTML_Params ipc_params; |
| + ipc_params.job_id = job_id_; |
| + ipc_params.mhtml_boundary_marker = mhtml_boundary_marker; |
| + |
| int frame_tree_node_id = pending_frame_tree_node_ids_.front(); |
| pending_frame_tree_node_ids_.pop(); |
| - bool is_last_frame = pending_frame_tree_node_ids_.empty(); |
| + ipc_params.is_last_frame = pending_frame_tree_node_ids_.empty(); |
| FrameTreeNode* ftn = FrameTreeNode::GloballyFindByID(frame_tree_node_id); |
| if (!ftn) // The contents went away. |
| @@ -151,12 +171,20 @@ bool MHTMLGenerationManager::Job::SendToNextRenderFrame( |
| observed_renderer_process_host_.RemoveAll(); |
| observed_renderer_process_host_.Add(rfh->GetProcess()); |
| - IPC::PlatformFileForTransit renderer_file = IPC::GetFileHandleForProcess( |
| + // Tell the renderer to skip (= deduplicate) already covered MHTML parts. |
| + std::set<std::string> digests_of_uris_to_skip; |
|
ncarter (slow)
2015/12/04 21:52:39
This is unused.
Łukasz Anforowicz
2015/12/04 22:55:43
Thanks for catching this. I must have missed this
|
| + ipc_params.salt = base::GenerateGUID(); |
| + for (const GURL& uri : already_serialized_uris_) { |
| + std::string digest = crypto::SHA256HashString(ipc_params.salt + uri.spec()); |
| + ipc_params.digests_of_uris_to_skip.insert(digest); |
| + } |
| + |
| + ipc_params.destination_file = IPC::GetFileHandleForProcess( |
| browser_file_.GetPlatformFile(), rfh->GetProcess()->GetHandle(), |
| false); // |close_source_handle|. |
| - rfh->Send(new FrameMsg_SerializeAsMHTML( |
| - rfh->GetRoutingID(), job_id_, renderer_file, mhtml_boundary_marker, |
| - CreateFrameRoutingIdToContentId(rfh->GetSiteInstance()), is_last_frame)); |
| + ipc_params.frame_routing_id_to_content_id = |
| + CreateFrameRoutingIdToContentId(rfh->GetSiteInstance()); |
| + rfh->Send(new FrameMsg_SerializeAsMHTML(rfh->GetRoutingID(), ipc_params)); |
| return true; |
| } |
| @@ -202,6 +230,27 @@ void MHTMLGenerationManager::Job::CloseFile( |
| callback); |
| } |
| +bool MHTMLGenerationManager::Job::SendToFirstFrame() { |
| + // We don't yet have an mhtml boundary marker when serializing the 1st frame. |
| + std::string initial_mhtml_boundary_marker = ""; |
| + |
| + return SendToNextRenderFrame(initial_mhtml_boundary_marker); |
| +} |
| + |
| +bool MHTMLGenerationManager::Job::OnSavedPageAsMHTML( |
| + std::string mhtml_boundary_marker, |
| + const std::set<GURL>& uris_of_generated_mhtml_parts) { |
| + bool success = true; |
| + |
| + already_serialized_uris_.insert(uris_of_generated_mhtml_parts.begin(), |
| + uris_of_generated_mhtml_parts.end()); |
| + |
| + if (GotMoreFramesToProcess()) |
| + success = SendToNextRenderFrame(mhtml_boundary_marker); |
| + |
| + return success; |
| +} |
| + |
| // static |
| int64 MHTMLGenerationManager::Job::CloseFileOnFileThread(base::File file) { |
| DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| @@ -239,7 +288,8 @@ void MHTMLGenerationManager::SaveMHTML(WebContents* web_contents, |
| void MHTMLGenerationManager::OnSavedPageAsMHTML( |
| int job_id, |
| bool mhtml_generation_in_renderer_succeeded, |
| - const std::string& mhtml_boundary_marker) { |
| + const std::string& mhtml_boundary_marker, |
| + const std::set<GURL>& uris_of_generated_mhtml_parts) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| if (!mhtml_generation_in_renderer_succeeded) { |
| @@ -251,14 +301,15 @@ void MHTMLGenerationManager::OnSavedPageAsMHTML( |
| if (!job) |
| return; |
| - if (job->GotMoreFramesToProcess()) { |
| - if (!job->SendToNextRenderFrame(mhtml_boundary_marker)) { |
| - JobFinished(job_id, JobStatus::FAILURE); |
| - } |
| + if (!job->GotMoreFramesToProcess()) { |
| + JobFinished(job_id, JobStatus::SUCCESS); |
| return; |
| } |
| - JobFinished(job_id, JobStatus::SUCCESS); |
| + if (!job->OnSavedPageAsMHTML(mhtml_boundary_marker, |
| + uris_of_generated_mhtml_parts)) { |
| + JobFinished(job_id, JobStatus::FAILURE); |
| + } |
| } |
| // static |
| @@ -297,9 +348,7 @@ void MHTMLGenerationManager::OnFileAvailable(int job_id, |
| job->set_browser_file(browser_file.Pass()); |
| - // We don't yet have an mhtml boundary marker when serializing the 1st frame. |
| - std::string initial_mhtml_boundary_marker = ""; |
| - if (!job->SendToNextRenderFrame(initial_mhtml_boundary_marker)) { |
| + if (!job->SendToFirstFrame()) { |
| JobFinished(job_id, JobStatus::FAILURE); |
| } |
| } |