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

Unified Diff: content/browser/download/mhtml_generation_manager.cc

Issue 1417323006: OOPIFs: Deduplicating MHTML parts across frames. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mhtml-serialization-per-frame
Patch Set: Rebasing... Created 5 years 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 side-by-side diff with in-line comments
Download patch
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 9937db7b2062c785acc8da25c75d45085c7a757e..c1cad619876f93af377af034be4168d0af745131 100644
--- a/content/browser/download/mhtml_generation_manager.cc
+++ b/content/browser/download/mhtml_generation_manager.cc
@@ -18,12 +18,14 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/common/frame_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#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 "url/gurl.h"
namespace content {
@@ -38,14 +40,25 @@ class MHTMLGenerationManager::Job : public RenderProcessHostObserver {
GenerateMHTMLCallback callback() const { return callback_; }
+ // Handler for FrameHostMsg_SerializeAsMHTMLResponse (a notification from the
+ // renderer that the MHTML generation for previous frame has finished).
+ // Returns |true| upon success; |false| otherwise.
+ bool OnSerializeAsMHTMLResponse(
+ RenderFrameHostImpl* sender,
+ const std::set<std::string>& digests_of_uris_of_serialized_resources);
+
// Sends IPC to the renderer, asking for MHTML generation of the next frame.
//
// Returns true if the message was sent successfully; false otherwise.
bool SendToNextRenderFrame();
// Indicates if more calls to SendToNextRenderFrame are needed.
- bool HasMoreFramesToProcess() const {
- return !pending_frame_tree_node_ids_.empty();
+ bool IsDone() const {
+ bool waiting_for_response_from_renderer =
+ frame_tree_node_id_of_busy_frame_ !=
+ FrameTreeNode::kFrameTreeNodeInvalidId;
+ bool no_more_requests_to_send = pending_frame_tree_node_ids_.empty();
+ return !waiting_for_response_from_renderer && no_more_requests_to_send;
}
// Close the file on the file thread and respond back on the UI thread with
@@ -73,12 +86,17 @@ class MHTMLGenerationManager::Job : public RenderProcessHostObserver {
// See also MHTMLGenerationManager::id_to_job_ map.
int job_id_;
+ // The IDs of frames that still need to be processed.
+ std::queue<int> pending_frame_tree_node_ids_;
+
+ // Identifies a frame to which we've sent FrameMsg_SerializeAsMHTML but for
+ // which we didn't yet process FrameHostMsg_SerializeAsMHTMLResponse via
+ // OnSerializeAsMHTMLResponse.
+ int frame_tree_node_id_of_busy_frame_;
+
// The handle to the file the MHTML is saved to for the browser process.
base::File browser_file_;
- // The IDs of frames we still need to process.
- std::queue<int> pending_frame_tree_node_ids_;
-
// Map from frames into content ids (see WebPageSerializer::generateMHTMLParts
// for more details about what "content ids" are and how they are used).
std::map<int, std::string> frame_tree_node_to_content_id_;
@@ -86,6 +104,10 @@ class MHTMLGenerationManager::Job : public RenderProcessHostObserver {
// MIME multipart boundary to use in the MHTML doc.
std::string mhtml_boundary_marker_;
+ // Digests of URIs of already generated MHTML parts.
+ std::set<std::string> digests_of_already_serialized_uris_;
+ std::string salt_;
+
// The callback to call once generation is complete.
GenerateMHTMLCallback callback_;
@@ -100,7 +122,9 @@ MHTMLGenerationManager::Job::Job(int job_id,
WebContents* web_contents,
GenerateMHTMLCallback callback)
: job_id_(job_id),
+ frame_tree_node_id_of_busy_frame_(FrameTreeNode::kFrameTreeNodeInvalidId),
mhtml_boundary_marker_(GenerateMHTMLBoundaryMarker()),
+ salt_(base::GenerateGUID()),
callback_(callback),
observed_renderer_process_host_(this) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -144,9 +168,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.
@@ -157,12 +185,21 @@ 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.
+ ipc_params.salt = salt_;
+ ipc_params.digests_of_uris_to_skip = digests_of_already_serialized_uris_;
+
+ 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());
+
+ // Send the IPC asking the renderer to serialize the frame.
+ DCHECK_EQ(FrameTreeNode::kFrameTreeNodeInvalidId,
+ frame_tree_node_id_of_busy_frame_);
+ frame_tree_node_id_of_busy_frame_ = frame_tree_node_id;
+ rfh->Send(new FrameMsg_SerializeAsMHTML(rfh->GetRoutingID(), ipc_params));
return true;
}
@@ -207,6 +244,31 @@ void MHTMLGenerationManager::Job::CloseFile(
callback);
}
+bool MHTMLGenerationManager::Job::OnSerializeAsMHTMLResponse(
+ RenderFrameHostImpl* sender,
+ const std::set<std::string>& digests_of_uris_of_serialized_resources) {
+ // Sanitize renderer input / reject unexpected messages.
+ int sender_id = sender->frame_tree_node()->frame_tree_node_id();
+ if (sender_id != frame_tree_node_id_of_busy_frame_) {
+ NOTREACHED();
+ return false; // Report failure.
+ }
+ frame_tree_node_id_of_busy_frame_ = FrameTreeNode::kFrameTreeNodeInvalidId;
+
+ // Renderer should be deduping resources with the same uris.
+ DCHECK_EQ(0u, base::STLSetIntersection<std::set<std::string>>(
+ digests_of_already_serialized_uris_,
+ digests_of_uris_of_serialized_resources).size());
+ digests_of_already_serialized_uris_.insert(
+ digests_of_uris_of_serialized_resources.begin(),
+ digests_of_uris_of_serialized_resources.end());
+
+ if (pending_frame_tree_node_ids_.empty())
+ return true; // Report success.
+
+ return SendToNextRenderFrame();
+}
+
// static
int64_t MHTMLGenerationManager::Job::CloseFileOnFileThread(base::File file) {
DCHECK_CURRENTLY_ON(BrowserThread::FILE);
@@ -260,9 +322,11 @@ void MHTMLGenerationManager::SaveMHTML(WebContents* web_contents,
job_id));
}
-void MHTMLGenerationManager::OnSavedFrameAsMHTML(
+void MHTMLGenerationManager::OnSerializeAsMHTMLResponse(
+ RenderFrameHostImpl* sender,
int job_id,
- bool mhtml_generation_in_renderer_succeeded) {
+ bool mhtml_generation_in_renderer_succeeded,
+ const std::set<std::string>& digests_of_uris_of_serialized_resources) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!mhtml_generation_in_renderer_succeeded) {
@@ -274,14 +338,14 @@ void MHTMLGenerationManager::OnSavedFrameAsMHTML(
if (!job)
return;
- if (job->HasMoreFramesToProcess()) {
- if (!job->SendToNextRenderFrame()) {
- JobFinished(job_id, JobStatus::FAILURE);
- }
+ if (!job->OnSerializeAsMHTMLResponse(
+ sender, digests_of_uris_of_serialized_resources)) {
+ JobFinished(job_id, JobStatus::FAILURE);
return;
}
- JobFinished(job_id, JobStatus::SUCCESS);
+ if (job->IsDone())
+ JobFinished(job_id, JobStatus::SUCCESS);
}
// static
« no previous file with comments | « content/browser/download/mhtml_generation_manager.h ('k') | content/browser/frame_host/render_frame_host_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698