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

Side by Side Diff: content/renderer/render_frame_impl.cc

Issue 2379823003: Move MHTML file writing out of the renderer main thread. (Closed)
Patch Set: Fixed logic bug. Created 4 years, 2 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
« no previous file with comments | « content/renderer/render_frame_impl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/renderer/render_frame_impl.h" 5 #include "content/renderer/render_frame_impl.h"
6 6
7 #include <map> 7 #include <map>
8 #include <string> 8 #include <string>
9 #include <utility> 9 #include <utility>
10 #include <vector> 10 #include <vector>
11 11
12 #include "base/auto_reset.h" 12 #include "base/auto_reset.h"
13 #include "base/bind_helpers.h"
13 #include "base/command_line.h" 14 #include "base/command_line.h"
14 #include "base/debug/alias.h" 15 #include "base/debug/alias.h"
15 #include "base/debug/asan_invalid_access.h" 16 #include "base/debug/asan_invalid_access.h"
16 #include "base/debug/crash_logging.h" 17 #include "base/debug/crash_logging.h"
17 #include "base/debug/dump_without_crashing.h" 18 #include "base/debug/dump_without_crashing.h"
18 #include "base/files/file.h" 19 #include "base/files/file.h"
19 #include "base/i18n/char_iterator.h" 20 #include "base/i18n/char_iterator.h"
20 #include "base/logging.h" 21 #include "base/logging.h"
21 #include "base/macros.h" 22 #include "base/macros.h"
22 #include "base/memory/ptr_util.h" 23 #include "base/memory/ptr_util.h"
23 #include "base/memory/shared_memory.h" 24 #include "base/memory/shared_memory.h"
24 #include "base/memory/weak_ptr.h" 25 #include "base/memory/weak_ptr.h"
25 #include "base/metrics/field_trial.h" 26 #include "base/metrics/field_trial.h"
26 #include "base/metrics/histogram_macros.h" 27 #include "base/metrics/histogram_macros.h"
27 #include "base/process/process.h" 28 #include "base/process/process.h"
28 #include "base/stl_util.h" 29 #include "base/stl_util.h"
29 #include "base/strings/string16.h" 30 #include "base/strings/string16.h"
30 #include "base/strings/utf_string_conversions.h" 31 #include "base/strings/utf_string_conversions.h"
32 #include "base/task_runner_util.h"
31 #include "base/threading/thread_task_runner_handle.h" 33 #include "base/threading/thread_task_runner_handle.h"
32 #include "base/time/time.h" 34 #include "base/time/time.h"
33 #include "base/trace_event/trace_event.h" 35 #include "base/trace_event/trace_event.h"
34 #include "build/build_config.h" 36 #include "build/build_config.h"
35 #include "cc/base/switches.h" 37 #include "cc/base/switches.h"
36 #include "content/child/appcache/appcache_dispatcher.h" 38 #include "content/child/appcache/appcache_dispatcher.h"
37 #include "content/child/quota_dispatcher.h" 39 #include "content/child/quota_dispatcher.h"
38 #include "content/child/request_extra_data.h" 40 #include "content/child/request_extra_data.h"
39 #include "content/child/service_worker/service_worker_handle_reference.h" 41 #include "content/child/service_worker/service_worker_handle_reference.h"
40 #include "content/child/service_worker/service_worker_network_provider.h" 42 #include "content/child/service_worker/service_worker_network_provider.h"
(...skipping 681 matching lines...) Expand 10 before | Expand all | Expand 10 after
722 724
723 private: 725 private:
724 const std::map<GURL, base::FilePath>& url_to_local_path_; 726 const std::map<GURL, base::FilePath>& url_to_local_path_;
725 const std::map<int, base::FilePath>& frame_routing_id_to_local_path_; 727 const std::map<int, base::FilePath>& frame_routing_id_to_local_path_;
726 }; 728 };
727 729
728 // Implementation of WebFrameSerializer::MHTMLPartsGenerationDelegate that 730 // Implementation of WebFrameSerializer::MHTMLPartsGenerationDelegate that
729 // 1. Bases shouldSkipResource and getContentID responses on contents of 731 // 1. Bases shouldSkipResource and getContentID responses on contents of
730 // FrameMsg_SerializeAsMHTML_Params. 732 // FrameMsg_SerializeAsMHTML_Params.
731 // 2. Stores digests of urls of serialized resources (i.e. urls reported via 733 // 2. Stores digests of urls of serialized resources (i.e. urls reported via
732 // shouldSkipResource) into |digests_of_uris_of_serialized_resources| passed 734 // shouldSkipResource) into |serialized_resources_uri_digests| passed
733 // to the constructor. 735 // to the constructor.
734 class MHTMLPartsGenerationDelegate 736 class MHTMLPartsGenerationDelegate
735 : public WebFrameSerializer::MHTMLPartsGenerationDelegate { 737 : public WebFrameSerializer::MHTMLPartsGenerationDelegate {
736 public: 738 public:
737 MHTMLPartsGenerationDelegate( 739 MHTMLPartsGenerationDelegate(
738 const FrameMsg_SerializeAsMHTML_Params& params, 740 const FrameMsg_SerializeAsMHTML_Params& params,
739 std::set<std::string>* digests_of_uris_of_serialized_resources) 741 std::set<std::string>* serialized_resources_uri_digests)
740 : params_(params), 742 : params_(params),
741 digests_of_uris_of_serialized_resources_( 743 serialized_resources_uri_digests_(serialized_resources_uri_digests) {
742 digests_of_uris_of_serialized_resources) { 744 DCHECK(serialized_resources_uri_digests_);
743 DCHECK(digests_of_uris_of_serialized_resources_);
744 } 745 }
745 746
746 bool shouldSkipResource(const WebURL& url) override { 747 bool shouldSkipResource(const WebURL& url) override {
747 std::string digest = 748 std::string digest =
748 crypto::SHA256HashString(params_.salt + GURL(url).spec()); 749 crypto::SHA256HashString(params_.salt + GURL(url).spec());
749 750
750 // Skip if the |url| already covered by serialization of an *earlier* frame. 751 // Skip if the |url| already covered by serialization of an *earlier* frame.
751 if (base::ContainsKey(params_.digests_of_uris_to_skip, digest)) 752 if (base::ContainsKey(params_.digests_of_uris_to_skip, digest))
752 return true; 753 return true;
753 754
754 // Let's record |url| as being serialized for the *current* frame. 755 // Let's record |url| as being serialized for the *current* frame.
755 auto pair = digests_of_uris_of_serialized_resources_->insert(digest); 756 auto pair = serialized_resources_uri_digests_->insert(digest);
756 bool insertion_took_place = pair.second; 757 bool insertion_took_place = pair.second;
757 DCHECK(insertion_took_place); // Blink should dedupe within a frame. 758 DCHECK(insertion_took_place); // Blink should dedupe within a frame.
758 759
759 return false; 760 return false;
760 } 761 }
761 762
762 WebString getContentID(WebFrame* frame) override { 763 WebString getContentID(WebFrame* frame) override {
763 int routing_id = GetRoutingIdForFrameOrProxy(frame); 764 int routing_id = GetRoutingIdForFrameOrProxy(frame);
764 765
765 auto it = params_.frame_routing_id_to_content_id.find(routing_id); 766 auto it = params_.frame_routing_id_to_content_id.find(routing_id);
766 if (it == params_.frame_routing_id_to_content_id.end()) 767 if (it == params_.frame_routing_id_to_content_id.end())
767 return WebString(); 768 return WebString();
768 769
769 const std::string& content_id = it->second; 770 const std::string& content_id = it->second;
770 return WebString::fromUTF8(content_id); 771 return WebString::fromUTF8(content_id);
771 } 772 }
772 773
773 blink::WebFrameSerializerCacheControlPolicy cacheControlPolicy() override { 774 blink::WebFrameSerializerCacheControlPolicy cacheControlPolicy() override {
774 return params_.mhtml_cache_control_policy; 775 return params_.mhtml_cache_control_policy;
775 } 776 }
776 777
777 bool useBinaryEncoding() override { return params_.mhtml_binary_encoding; } 778 bool useBinaryEncoding() override { return params_.mhtml_binary_encoding; }
778 779
779 private: 780 private:
780 const FrameMsg_SerializeAsMHTML_Params& params_; 781 const FrameMsg_SerializeAsMHTML_Params& params_;
781 std::set<std::string>* digests_of_uris_of_serialized_resources_; 782 std::set<std::string>* serialized_resources_uri_digests_;
782 783
783 DISALLOW_COPY_AND_ASSIGN(MHTMLPartsGenerationDelegate); 784 DISALLOW_COPY_AND_ASSIGN(MHTMLPartsGenerationDelegate);
784 }; 785 };
785 786
787 bool WriteMHTMLToDisk(std::array<WebData, 3> mhtml_contents, base::File file) {
788 DCHECK(!RenderThread::Get()) << "Should not run in the main renderer thread";
789 // Writes all serialized data to file.
790 TRACE_EVENT0("page-serialization", "WriteMHTMLToDisk (RenderFrameImpl)");
791 SCOPED_UMA_HISTOGRAM_TIMER(
792 "PageSerialization.MhtmlGeneration.WriteToDiskTime.SingleFrame");
793 bool success = true;
794 for (const WebData& data : mhtml_contents) {
795 if (file.WriteAtCurrentPos(data.data(), data.size()) < 0) {
796 success = false;
797 break;
798 }
799 }
800 file.Close(); // Need to flush file contents before sending IPC response.
801 return success;
802 }
803
786 bool IsHttpPost(const blink::WebURLRequest& request) { 804 bool IsHttpPost(const blink::WebURLRequest& request) {
787 return request.httpMethod().utf8() == "POST"; 805 return request.httpMethod().utf8() == "POST";
788 } 806 }
789 807
790 #if defined(OS_ANDROID) 808 #if defined(OS_ANDROID)
791 // Returns true if WMPI should be used for playback, false otherwise. 809 // Returns true if WMPI should be used for playback, false otherwise.
792 // 810 //
793 // Note that HLS and MP4 detection are pre-redirect and path-based. It is 811 // Note that HLS and MP4 detection are pre-redirect and path-based. It is
794 // possible to load such a URL and find different content. 812 // possible to load such a URL and find different content.
795 bool UseWebMediaPlayerImpl(const GURL& url) { 813 bool UseWebMediaPlayerImpl(const GURL& url) {
(...skipping 4395 matching lines...) Expand 10 before | Expand all | Expand 10 after
5191 void RenderFrameImpl::OnSerializeAsMHTML( 5209 void RenderFrameImpl::OnSerializeAsMHTML(
5192 const FrameMsg_SerializeAsMHTML_Params& params) { 5210 const FrameMsg_SerializeAsMHTML_Params& params) {
5193 TRACE_EVENT0("page-serialization", "RenderFrameImpl::OnSerializeAsMHTML"); 5211 TRACE_EVENT0("page-serialization", "RenderFrameImpl::OnSerializeAsMHTML");
5194 base::TimeTicks start_time = base::TimeTicks::Now(); 5212 base::TimeTicks start_time = base::TimeTicks::Now();
5195 // Unpack IPC payload. 5213 // Unpack IPC payload.
5196 base::File file = IPC::PlatformFileForTransitToFile(params.destination_file); 5214 base::File file = IPC::PlatformFileForTransitToFile(params.destination_file);
5197 const WebString mhtml_boundary = 5215 const WebString mhtml_boundary =
5198 WebString::fromUTF8(params.mhtml_boundary_marker); 5216 WebString::fromUTF8(params.mhtml_boundary_marker);
5199 DCHECK(!mhtml_boundary.isEmpty()); 5217 DCHECK(!mhtml_boundary.isEmpty());
5200 5218
5201 // Three WebData instances for header, parts and footer. 5219 // Three WebData instances for header, contents/parts and footer.
5202 WebData mhtml_contents[3]; 5220 std::array<WebData, 3> mhtml_contents;
5203 std::set<std::string> digests_of_uris_of_serialized_resources; 5221 std::set<std::string> serialized_resources_uri_digests;
5204 MHTMLPartsGenerationDelegate delegate( 5222 MHTMLPartsGenerationDelegate delegate(params,
5205 params, &digests_of_uris_of_serialized_resources); 5223 &serialized_resources_uri_digests);
5206 5224
5207 bool success = true; 5225 bool success = true;
5208 5226
5209 // Generate MHTML header if needed. 5227 // Generate MHTML header if needed.
5210 if (IsMainFrame()) { 5228 if (IsMainFrame()) {
5211 TRACE_EVENT0("page-serialization", 5229 TRACE_EVENT0("page-serialization",
5212 "RenderFrameImpl::OnSerializeAsMHTML header"); 5230 "RenderFrameImpl::OnSerializeAsMHTML header");
5213 // |data| can be empty if the main frame should be skipped. If the main 5231 // |data| can be empty if the main frame should be skipped. If the main
5214 // frame is skipped, then the whole archive is bad, so bail to the error 5232 // frame is skipped, then the whole archive is bad, so bail to the error
5215 // condition. 5233 // condition.
(...skipping 13 matching lines...) Expand all
5229 mhtml_boundary, GetWebFrame(), &delegate); 5247 mhtml_boundary, GetWebFrame(), &delegate);
5230 } 5248 }
5231 5249
5232 // Generate MHTML footer if needed. 5250 // Generate MHTML footer if needed.
5233 if (success && params.is_last_frame) { 5251 if (success && params.is_last_frame) {
5234 TRACE_EVENT0("page-serialization", 5252 TRACE_EVENT0("page-serialization",
5235 "RenderFrameImpl::OnSerializeAsMHTML footer"); 5253 "RenderFrameImpl::OnSerializeAsMHTML footer");
5236 mhtml_contents[2] = WebFrameSerializer::generateMHTMLFooter(mhtml_boundary); 5254 mhtml_contents[2] = WebFrameSerializer::generateMHTMLFooter(mhtml_boundary);
5237 } 5255 }
5238 5256
5239 // Writes all serialized data to file. 5257 // Note: we assume RenderFrameImpl::OnWriteMHTMLToDiskComplete and the rest of
5240 // TODO(jcivelli): write the chunks in deferred tasks to give a chance to 5258 // this function will be fast enough to not need to be accounted for in this
5241 // the message loop to process other events. 5259 // metric.
5242 if (success) {
5243 TRACE_EVENT0("page-serialization",
5244 "RenderFrameImpl::OnSerializeAsMHTML writing to file");
5245 SCOPED_UMA_HISTOGRAM_TIMER(
5246 "PageSerialization.MhtmlGeneration.WriteToDiskTime.SingleFrame");
5247 for (const WebData& data : mhtml_contents) {
5248 if (file.WriteAtCurrentPos(data.data(), data.size()) < 0) {
5249 success = false;
5250 break;
5251 }
5252 }
5253 }
5254
5255 // Cleanup and notify the browser process about completion.
5256 file.Close(); // Need to flush file contents before sending IPC response.
5257 base::TimeDelta main_thread_use_time = base::TimeTicks::Now() - start_time; 5260 base::TimeDelta main_thread_use_time = base::TimeTicks::Now() - start_time;
5258 Send(new FrameHostMsg_SerializeAsMHTMLResponse(
5259 routing_id_, params.job_id, success,
5260 digests_of_uris_of_serialized_resources, main_thread_use_time));
5261 UMA_HISTOGRAM_TIMES( 5261 UMA_HISTOGRAM_TIMES(
5262 "PageSerialization.MhtmlGeneration.RendererMainThreadTime.SingleFrame", 5262 "PageSerialization.MhtmlGeneration.RendererMainThreadTime.SingleFrame",
5263 main_thread_use_time); 5263 main_thread_use_time);
5264
5265 if (success &&
5266 !(mhtml_contents[0].isEmpty() && mhtml_contents[1].isEmpty() &&
5267 mhtml_contents[2].isEmpty())) {
5268 base::PostTaskAndReplyWithResult(
5269 RenderThreadImpl::current()->GetFileThreadTaskRunner().get(), FROM_HERE,
5270 base::Bind(&WriteMHTMLToDisk, base::Passed(&mhtml_contents),
5271 base::Passed(&file)),
5272 base::Bind(&RenderFrameImpl::OnWriteMHTMLToDiskComplete,
5273 base::Unretained(this), params.job_id,
5274 base::Passed(&serialized_resources_uri_digests),
5275 main_thread_use_time));
5276 } 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
5277 OnWriteMHTMLToDiskComplete(params.job_id,
5278 std::move(serialized_resources_uri_digests),
5279 main_thread_use_time, success);
5280 }
5281 }
5282
5283 void RenderFrameImpl::OnWriteMHTMLToDiskComplete(
5284 int job_id,
5285 std::set<std::string> serialized_resources_uri_digests,
5286 base::TimeDelta main_thread_use_time,
5287 bool success) {
5288 DCHECK(RenderThread::Get()) << "Must run in the main renderer thread";
5289 // Notify the browser process about completion.
5290 // Note: this method must be short enough to not need to be accounted for in
5291 // PageSerialization.MhtmlGeneration.RendererMainThreadTime.SingleFrame.
5292 Send(new FrameHostMsg_SerializeAsMHTMLResponse(
5293 routing_id_, job_id, success, serialized_resources_uri_digests,
5294 main_thread_use_time));
5264 } 5295 }
5265 5296
5266 void RenderFrameImpl::OnFind(int request_id, 5297 void RenderFrameImpl::OnFind(int request_id,
5267 const base::string16& search_text, 5298 const base::string16& search_text,
5268 const WebFindOptions& options) { 5299 const WebFindOptions& options) {
5269 DCHECK(!search_text.empty()); 5300 DCHECK(!search_text.empty());
5270 5301
5271 blink::WebPlugin* plugin = GetWebPluginForFind(); 5302 blink::WebPlugin* plugin = GetWebPluginForFind();
5272 // Check if the plugin still exists in the document. 5303 // Check if the plugin still exists in the document.
5273 if (plugin) { 5304 if (plugin) {
(...skipping 1165 matching lines...) Expand 10 before | Expand all | Expand 10 after
6439 // event target. Potentially a Pepper plugin will receive the event. 6470 // event target. Potentially a Pepper plugin will receive the event.
6440 // In order to tell whether a plugin gets the last mouse event and which it 6471 // In order to tell whether a plugin gets the last mouse event and which it
6441 // is, we set |pepper_last_mouse_event_target_| to null here. If a plugin gets 6472 // is, we set |pepper_last_mouse_event_target_| to null here. If a plugin gets
6442 // the event, it will notify us via DidReceiveMouseEvent() and set itself as 6473 // the event, it will notify us via DidReceiveMouseEvent() and set itself as
6443 // |pepper_last_mouse_event_target_|. 6474 // |pepper_last_mouse_event_target_|.
6444 pepper_last_mouse_event_target_ = nullptr; 6475 pepper_last_mouse_event_target_ = nullptr;
6445 #endif 6476 #endif
6446 } 6477 }
6447 6478
6448 } // namespace content 6479 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/render_frame_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698