Chromium Code Reviews| Index: content/renderer/render_frame_impl.cc |
| diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc |
| index 9c240ac977347efdcd472f25514886b84ac4b654..ef6f77b2a040d0ef174711c10f8d29d8df344d6f 100644 |
| --- a/content/renderer/render_frame_impl.cc |
| +++ b/content/renderer/render_frame_impl.cc |
| @@ -10,6 +10,7 @@ |
| #include <vector> |
| #include "base/auto_reset.h" |
| +#include "base/bind_helpers.h" |
| #include "base/command_line.h" |
| #include "base/debug/alias.h" |
| #include "base/debug/asan_invalid_access.h" |
| @@ -28,6 +29,7 @@ |
| #include "base/stl_util.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/utf_string_conversions.h" |
| +#include "base/task_runner_util.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "base/trace_event/trace_event.h" |
| @@ -729,18 +731,17 @@ class LinkRewritingDelegate : public WebFrameSerializer::LinkRewritingDelegate { |
| // 1. Bases shouldSkipResource and getContentID responses on contents of |
| // FrameMsg_SerializeAsMHTML_Params. |
| // 2. Stores digests of urls of serialized resources (i.e. urls reported via |
| -// shouldSkipResource) into |digests_of_uris_of_serialized_resources| passed |
| +// shouldSkipResource) into |serialized_resources_uri_digests| passed |
| // to the constructor. |
| class MHTMLPartsGenerationDelegate |
| : public WebFrameSerializer::MHTMLPartsGenerationDelegate { |
| public: |
| MHTMLPartsGenerationDelegate( |
| const FrameMsg_SerializeAsMHTML_Params& params, |
| - std::set<std::string>* digests_of_uris_of_serialized_resources) |
| + std::set<std::string>* serialized_resources_uri_digests) |
| : params_(params), |
| - digests_of_uris_of_serialized_resources_( |
| - digests_of_uris_of_serialized_resources) { |
| - DCHECK(digests_of_uris_of_serialized_resources_); |
| + serialized_resources_uri_digests_(serialized_resources_uri_digests) { |
| + DCHECK(serialized_resources_uri_digests_); |
| } |
| bool shouldSkipResource(const WebURL& url) override { |
| @@ -752,7 +753,7 @@ class MHTMLPartsGenerationDelegate |
| return true; |
| // Let's record |url| as being serialized for the *current* frame. |
| - auto pair = digests_of_uris_of_serialized_resources_->insert(digest); |
| + auto pair = serialized_resources_uri_digests_->insert(digest); |
| bool insertion_took_place = pair.second; |
| DCHECK(insertion_took_place); // Blink should dedupe within a frame. |
| @@ -778,11 +779,28 @@ class MHTMLPartsGenerationDelegate |
| private: |
| const FrameMsg_SerializeAsMHTML_Params& params_; |
| - std::set<std::string>* digests_of_uris_of_serialized_resources_; |
| + std::set<std::string>* serialized_resources_uri_digests_; |
| DISALLOW_COPY_AND_ASSIGN(MHTMLPartsGenerationDelegate); |
| }; |
| +bool WriteMHTMLToDisk(std::array<WebData, 3> mhtml_contents, base::File file) { |
| + DCHECK(!RenderThread::Get()) << "Should not run in the main renderer thread"; |
| + // Writes all serialized data to file. |
| + TRACE_EVENT0("page-serialization", "WriteMHTMLToDisk (RenderFrameImpl)"); |
| + SCOPED_UMA_HISTOGRAM_TIMER( |
| + "PageSerialization.MhtmlGeneration.WriteToDiskTime.SingleFrame"); |
| + bool success = true; |
| + for (const WebData& data : mhtml_contents) { |
| + if (file.WriteAtCurrentPos(data.data(), data.size()) < 0) { |
| + success = false; |
| + break; |
| + } |
| + } |
| + file.Close(); // Need to flush file contents before sending IPC response. |
| + return success; |
| +} |
| + |
| bool IsHttpPost(const blink::WebURLRequest& request) { |
| return request.httpMethod().utf8() == "POST"; |
| } |
| @@ -5198,11 +5216,11 @@ void RenderFrameImpl::OnSerializeAsMHTML( |
| WebString::fromUTF8(params.mhtml_boundary_marker); |
| DCHECK(!mhtml_boundary.isEmpty()); |
| - // Three WebData instances for header, parts and footer. |
| - WebData mhtml_contents[3]; |
| - std::set<std::string> digests_of_uris_of_serialized_resources; |
| - MHTMLPartsGenerationDelegate delegate( |
| - params, &digests_of_uris_of_serialized_resources); |
| + // Three WebData instances for header, contents/parts and footer. |
| + std::array<WebData, 3> mhtml_contents; |
| + std::set<std::string> serialized_resources_uri_digests; |
| + MHTMLPartsGenerationDelegate delegate(params, |
| + &serialized_resources_uri_digests); |
| bool success = true; |
| @@ -5236,31 +5254,44 @@ void RenderFrameImpl::OnSerializeAsMHTML( |
| mhtml_contents[2] = WebFrameSerializer::generateMHTMLFooter(mhtml_boundary); |
| } |
| - // Writes all serialized data to file. |
| - // TODO(jcivelli): write the chunks in deferred tasks to give a chance to |
| - // the message loop to process other events. |
| - if (success) { |
| - TRACE_EVENT0("page-serialization", |
| - "RenderFrameImpl::OnSerializeAsMHTML writing to file"); |
| - SCOPED_UMA_HISTOGRAM_TIMER( |
| - "PageSerialization.MhtmlGeneration.WriteToDiskTime.SingleFrame"); |
| - for (const WebData& data : mhtml_contents) { |
| - if (file.WriteAtCurrentPos(data.data(), data.size()) < 0) { |
| - success = false; |
| - break; |
| - } |
| - } |
| - } |
| - |
| - // Cleanup and notify the browser process about completion. |
| - file.Close(); // Need to flush file contents before sending IPC response. |
| + // Note: we assume RenderFrameImpl::OnWriteMHTMLToDiskComplete and the rest of |
| + // this function will be fast enough to not need to be accounted for in this |
| + // metric. |
| base::TimeDelta main_thread_use_time = base::TimeTicks::Now() - start_time; |
| - Send(new FrameHostMsg_SerializeAsMHTMLResponse( |
| - routing_id_, params.job_id, success, |
| - digests_of_uris_of_serialized_resources, main_thread_use_time)); |
| UMA_HISTOGRAM_TIMES( |
| "PageSerialization.MhtmlGeneration.RendererMainThreadTime.SingleFrame", |
| main_thread_use_time); |
| + |
| + if (success && |
| + !(mhtml_contents[0].isEmpty() && mhtml_contents[1].isEmpty() && |
| + mhtml_contents[2].isEmpty())) { |
| + base::PostTaskAndReplyWithResult( |
| + RenderThreadImpl::current()->GetFileThreadTaskRunner().get(), FROM_HERE, |
| + base::Bind(&WriteMHTMLToDisk, base::Passed(&mhtml_contents), |
| + base::Passed(&file)), |
| + base::Bind(&RenderFrameImpl::OnWriteMHTMLToDiskComplete, |
| + base::Unretained(this), params.job_id, |
| + base::Passed(&serialized_resources_uri_digests), |
| + main_thread_use_time)); |
| + } else { |
|
Łukasz Anforowicz
2016/09/29 19:56:18
I think we need to call |file.Close()| here?
Alte
carlosk
2016/09/30 00:20:18
Done.
I agree that the else should happen way les
|
| + OnWriteMHTMLToDiskComplete(params.job_id, |
| + std::move(serialized_resources_uri_digests), |
| + main_thread_use_time, success); |
| + } |
| +} |
| + |
| +void RenderFrameImpl::OnWriteMHTMLToDiskComplete( |
| + int job_id, |
| + std::set<std::string> serialized_resources_uri_digests, |
| + base::TimeDelta main_thread_use_time, |
| + bool success) { |
| + DCHECK(RenderThread::Get()) << "Must run in the main renderer thread"; |
| + // Notify the browser process about completion. |
| + // Note: this method must be short enough to not need to be accounted for in |
| + // PageSerialization.MhtmlGeneration.RendererMainThreadTime.SingleFrame. |
| + Send(new FrameHostMsg_SerializeAsMHTMLResponse( |
| + routing_id_, job_id, success, serialized_resources_uri_digests, |
| + main_thread_use_time)); |
| } |
| void RenderFrameImpl::OnFind(int request_id, |