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

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

Issue 2519273002: Fail when saving page as MHTML provides information about the cause. (Closed)
Patch Set: Minor changes. Created 4 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 unified diff | Download patch
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>
(...skipping 10 matching lines...) Expand all
21 #include "base/logging.h" 21 #include "base/logging.h"
22 #include "base/macros.h" 22 #include "base/macros.h"
23 #include "base/memory/ptr_util.h" 23 #include "base/memory/ptr_util.h"
24 #include "base/memory/shared_memory.h" 24 #include "base/memory/shared_memory.h"
25 #include "base/memory/weak_ptr.h" 25 #include "base/memory/weak_ptr.h"
26 #include "base/metrics/field_trial.h" 26 #include "base/metrics/field_trial.h"
27 #include "base/metrics/histogram_macros.h" 27 #include "base/metrics/histogram_macros.h"
28 #include "base/process/process.h" 28 #include "base/process/process.h"
29 #include "base/stl_util.h" 29 #include "base/stl_util.h"
30 #include "base/strings/string16.h" 30 #include "base/strings/string16.h"
31 #include "base/strings/stringprintf.h"
31 #include "base/strings/utf_string_conversions.h" 32 #include "base/strings/utf_string_conversions.h"
32 #include "base/task_runner_util.h" 33 #include "base/task_runner_util.h"
33 #include "base/threading/thread_task_runner_handle.h" 34 #include "base/threading/thread_task_runner_handle.h"
34 #include "base/time/time.h" 35 #include "base/time/time.h"
35 #include "base/trace_event/trace_event.h" 36 #include "base/trace_event/trace_event.h"
36 #include "build/build_config.h" 37 #include "build/build_config.h"
37 #include "cc/base/switches.h" 38 #include "cc/base/switches.h"
38 #include "content/child/appcache/appcache_dispatcher.h" 39 #include "content/child/appcache/appcache_dispatcher.h"
39 #include "content/child/quota_dispatcher.h" 40 #include "content/child/quota_dispatcher.h"
40 #include "content/child/request_extra_data.h" 41 #include "content/child/request_extra_data.h"
(...skipping 753 matching lines...) Expand 10 before | Expand all | Expand 10 after
794 795
795 DISALLOW_COPY_AND_ASSIGN(MHTMLPartsGenerationDelegate); 796 DISALLOW_COPY_AND_ASSIGN(MHTMLPartsGenerationDelegate);
796 }; 797 };
797 798
798 bool IsHttpPost(const blink::WebURLRequest& request) { 799 bool IsHttpPost(const blink::WebURLRequest& request) {
799 return request.httpMethod().utf8() == "POST"; 800 return request.httpMethod().utf8() == "POST";
800 } 801 }
801 802
802 // Writes to file the serialized and encoded MHTML data from WebThreadSafeData 803 // Writes to file the serialized and encoded MHTML data from WebThreadSafeData
803 // instances. 804 // instances.
804 bool WriteMHTMLToDisk(std::vector<WebThreadSafeData> mhtml_contents, 805 MhtmlSaveStatus WriteMHTMLToDisk(std::vector<WebThreadSafeData> mhtml_contents,
805 base::File file) { 806 base::File file) {
806 TRACE_EVENT0("page-serialization", "WriteMHTMLToDisk (RenderFrameImpl)"); 807 TRACE_EVENT0("page-serialization", "WriteMHTMLToDisk (RenderFrameImpl)");
807 SCOPED_UMA_HISTOGRAM_TIMER( 808 SCOPED_UMA_HISTOGRAM_TIMER(
808 "PageSerialization.MhtmlGeneration.WriteToDiskTime.SingleFrame"); 809 "PageSerialization.MhtmlGeneration.WriteToDiskTime.SingleFrame");
809 DCHECK(!RenderThread::Get()) << "Should not run in the main renderer thread"; 810 DCHECK(!RenderThread::Get()) << "Should not run in the main renderer thread";
810 bool success = true; 811 MhtmlSaveStatus save_status = MhtmlSaveStatus::SUCCESS;
811 for (const WebThreadSafeData& data : mhtml_contents) { 812 for (const WebThreadSafeData& data : mhtml_contents) {
812 if (!data.isEmpty() && 813 if (!data.isEmpty() &&
813 file.WriteAtCurrentPos(data.data(), data.size()) < 0) { 814 file.WriteAtCurrentPos(data.data(), data.size()) < 0) {
814 success = false; 815 save_status = MhtmlSaveStatus::FILE_WRITTING_ERROR;
815 break; 816 break;
816 } 817 }
817 } 818 }
818 // Explicitly close |file| here to make sure to include any flush operations 819 // Explicitly close |file| here to make sure to include any flush operations
819 // in the UMA metric. 820 // in the UMA metric.
820 file.Close(); 821 file.Close();
821 return success; 822 return save_status;
822 } 823 }
823 824
824 #if defined(OS_ANDROID) 825 #if defined(OS_ANDROID)
825 // Returns true if WMPI should be used for playback, false otherwise. 826 // Returns true if WMPI should be used for playback, false otherwise.
826 // 827 //
827 // Note that HLS and MP4 detection are pre-redirect and path-based. It is 828 // Note that HLS and MP4 detection are pre-redirect and path-based. It is
828 // possible to load such a URL and find different content. 829 // possible to load such a URL and find different content.
829 bool UseWebMediaPlayerImpl(const GURL& url) { 830 bool UseWebMediaPlayerImpl(const GURL& url) {
830 // Always use WMPI for playing blob URLs since WMPA could never play them very 831 // Always use WMPI for playing blob URLs since WMPA could never play them very
831 // well and no longer has support for MSE based playbacks. 832 // well and no longer has support for MSE based playbacks.
(...skipping 4542 matching lines...) Expand 10 before | Expand all | Expand 10 after
5374 WebString::fromUTF8(params.mhtml_boundary_marker); 5375 WebString::fromUTF8(params.mhtml_boundary_marker);
5375 DCHECK(!mhtml_boundary.isEmpty()); 5376 DCHECK(!mhtml_boundary.isEmpty());
5376 5377
5377 // Holds WebThreadSafeData instances for some or all of header, contents and 5378 // Holds WebThreadSafeData instances for some or all of header, contents and
5378 // footer. 5379 // footer.
5379 std::vector<WebThreadSafeData> mhtml_contents; 5380 std::vector<WebThreadSafeData> mhtml_contents;
5380 std::set<std::string> serialized_resources_uri_digests; 5381 std::set<std::string> serialized_resources_uri_digests;
5381 MHTMLPartsGenerationDelegate delegate(params, 5382 MHTMLPartsGenerationDelegate delegate(params,
5382 &serialized_resources_uri_digests); 5383 &serialized_resources_uri_digests);
5383 5384
5384 bool success = true; 5385 MhtmlSaveStatus save_status = MhtmlSaveStatus::SUCCESS;
5385 bool has_some_data = false; 5386 bool has_some_data = false;
5386 5387
5387 // Generate MHTML header if needed. 5388 // Generate MHTML header if needed.
5388 if (IsMainFrame()) { 5389 if (IsMainFrame()) {
5389 TRACE_EVENT0("page-serialization", 5390 TRACE_EVENT0("page-serialization",
5390 "RenderFrameImpl::OnSerializeAsMHTML header"); 5391 "RenderFrameImpl::OnSerializeAsMHTML header");
5391 // The returned data can be empty if the main frame should be skipped. If 5392 // The returned data can be empty if the main frame should be skipped. If
5392 // the main frame is skipped, then the whole archive is bad. 5393 // the main frame is skipped, then the whole archive is bad.
5393 mhtml_contents.emplace_back(WebFrameSerializer::generateMHTMLHeader( 5394 mhtml_contents.emplace_back(WebFrameSerializer::generateMHTMLHeader(
5394 mhtml_boundary, GetWebFrame(), &delegate)); 5395 mhtml_boundary, GetWebFrame(), &delegate));
5395 has_some_data = !mhtml_contents.back().isEmpty(); 5396 if (mhtml_contents.back().isEmpty())
5396 success = has_some_data; 5397 save_status = MhtmlSaveStatus::FRAME_SERIALIZATION_FORBIDDEN;
5398 else
5399 has_some_data = true;
5397 } 5400 }
5398 5401
5399 // Generate MHTML parts. Note that if this is not the main frame, then even 5402 // Generate MHTML parts. Note that if this is not the main frame, then even
5400 // skipping the whole parts generation step is not an error - it simply 5403 // skipping the whole parts generation step is not an error - it simply
5401 // results in an omitted resource in the final file. 5404 // results in an omitted resource in the final file.
5402 if (success) { 5405 if (save_status == MhtmlSaveStatus::SUCCESS) {
5403 TRACE_EVENT0("page-serialization", 5406 TRACE_EVENT0("page-serialization",
5404 "RenderFrameImpl::OnSerializeAsMHTML parts serialization"); 5407 "RenderFrameImpl::OnSerializeAsMHTML parts serialization");
5405 // The returned data can be empty if the frame should be skipped, but this 5408 // The returned data can be empty if the frame should be skipped, but this
5406 // is OK. 5409 // is OK.
5407 mhtml_contents.emplace_back(WebFrameSerializer::generateMHTMLParts( 5410 mhtml_contents.emplace_back(WebFrameSerializer::generateMHTMLParts(
5408 mhtml_boundary, GetWebFrame(), &delegate)); 5411 mhtml_boundary, GetWebFrame(), &delegate));
5409 has_some_data |= !mhtml_contents.back().isEmpty(); 5412 has_some_data |= !mhtml_contents.back().isEmpty();
5410 } 5413 }
5411 5414
5412 // Generate MHTML footer if needed. 5415 // Generate MHTML footer if needed.
5413 if (success && params.is_last_frame) { 5416 if (save_status == MhtmlSaveStatus::SUCCESS && params.is_last_frame) {
5414 TRACE_EVENT0("page-serialization", 5417 TRACE_EVENT0("page-serialization",
5415 "RenderFrameImpl::OnSerializeAsMHTML footer"); 5418 "RenderFrameImpl::OnSerializeAsMHTML footer");
5416 mhtml_contents.emplace_back( 5419 mhtml_contents.emplace_back(
5417 WebFrameSerializer::generateMHTMLFooter(mhtml_boundary)); 5420 WebFrameSerializer::generateMHTMLFooter(mhtml_boundary));
5418 has_some_data |= !mhtml_contents.back().isEmpty(); 5421 has_some_data |= !mhtml_contents.back().isEmpty();
5419 } 5422 }
5420 5423
5421 // Note: we assume RenderFrameImpl::OnWriteMHTMLToDiskComplete and the rest of 5424 // Note: we assume RenderFrameImpl::OnWriteMHTMLToDiskComplete and the rest of
5422 // this function will be fast enough to not need to be accounted for in this 5425 // this function will be fast enough to not need to be accounted for in this
5423 // metric. 5426 // metric.
5424 base::TimeDelta main_thread_use_time = base::TimeTicks::Now() - start_time; 5427 base::TimeDelta main_thread_use_time = base::TimeTicks::Now() - start_time;
5425 UMA_HISTOGRAM_TIMES( 5428 UMA_HISTOGRAM_TIMES(
5426 "PageSerialization.MhtmlGeneration.RendererMainThreadTime.SingleFrame", 5429 "PageSerialization.MhtmlGeneration.RendererMainThreadTime.SingleFrame",
5427 main_thread_use_time); 5430 main_thread_use_time);
5428 5431
5429 if (success && has_some_data) { 5432 if (save_status == MhtmlSaveStatus::SUCCESS && has_some_data) {
5430 base::PostTaskAndReplyWithResult( 5433 base::PostTaskAndReplyWithResult(
5431 RenderThreadImpl::current()->GetFileThreadTaskRunner().get(), FROM_HERE, 5434 RenderThreadImpl::current()->GetFileThreadTaskRunner().get(), FROM_HERE,
5432 base::Bind(&WriteMHTMLToDisk, base::Passed(&mhtml_contents), 5435 base::Bind(&WriteMHTMLToDisk, base::Passed(&mhtml_contents),
5433 base::Passed(&file)), 5436 base::Passed(&file)),
5434 base::Bind(&RenderFrameImpl::OnWriteMHTMLToDiskComplete, 5437 base::Bind(&RenderFrameImpl::OnWriteMHTMLToDiskComplete,
5435 weak_factory_.GetWeakPtr(), params.job_id, 5438 weak_factory_.GetWeakPtr(), params.job_id,
5436 base::Passed(&serialized_resources_uri_digests), 5439 base::Passed(&serialized_resources_uri_digests),
5437 main_thread_use_time)); 5440 main_thread_use_time));
5438 } else { 5441 } else {
5439 file.Close(); 5442 file.Close();
5440 OnWriteMHTMLToDiskComplete(params.job_id, serialized_resources_uri_digests, 5443 OnWriteMHTMLToDiskComplete(params.job_id, serialized_resources_uri_digests,
5441 main_thread_use_time, success); 5444 main_thread_use_time, save_status);
5442 } 5445 }
5443 } 5446 }
5444 5447
5445 void RenderFrameImpl::OnWriteMHTMLToDiskComplete( 5448 void RenderFrameImpl::OnWriteMHTMLToDiskComplete(
5446 int job_id, 5449 int job_id,
5447 std::set<std::string> serialized_resources_uri_digests, 5450 std::set<std::string> serialized_resources_uri_digests,
5448 base::TimeDelta main_thread_use_time, 5451 base::TimeDelta main_thread_use_time,
5449 bool success) { 5452 MhtmlSaveStatus save_status) {
5450 TRACE_EVENT1("page-serialization", 5453 TRACE_EVENT1(
5451 "RenderFrameImpl::OnWriteMHTMLToDiskComplete", 5454 "page-serialization", "RenderFrameImpl::OnWriteMHTMLToDiskComplete",
5452 "frame serialization was successful", success); 5455 "frame save status",
5456 save_status == MhtmlSaveStatus::SUCCESS
5457 ? "success"
5458 : base::StringPrintf("failure (%d)", static_cast<int>(save_status)));
Łukasz Anforowicz 2016/11/22 19:22:13 I wonder if it would make sense to introduce a hel
carlosk 2016/11/22 23:26:24 Done.
5453 DCHECK(RenderThread::Get()) << "Must run in the main renderer thread"; 5459 DCHECK(RenderThread::Get()) << "Must run in the main renderer thread";
5454 // Notify the browser process about completion. 5460 // Notify the browser process about completion.
5455 // Note: we assume this method is fast enough to not need to be accounted for 5461 // Note: we assume this method is fast enough to not need to be accounted for
5456 // in PageSerialization.MhtmlGeneration.RendererMainThreadTime.SingleFrame. 5462 // in PageSerialization.MhtmlGeneration.RendererMainThreadTime.SingleFrame.
5457 Send(new FrameHostMsg_SerializeAsMHTMLResponse( 5463 Send(new FrameHostMsg_SerializeAsMHTMLResponse(
5458 routing_id_, job_id, success, serialized_resources_uri_digests, 5464 routing_id_, job_id, save_status, serialized_resources_uri_digests,
5459 main_thread_use_time)); 5465 main_thread_use_time));
5460 } 5466 }
5461 5467
5462 void RenderFrameImpl::OnFind(int request_id, 5468 void RenderFrameImpl::OnFind(int request_id,
5463 const base::string16& search_text, 5469 const base::string16& search_text,
5464 const WebFindOptions& options) { 5470 const WebFindOptions& options) {
5465 DCHECK(!search_text.empty()); 5471 DCHECK(!search_text.empty());
5466 5472
5467 blink::WebPlugin* plugin = GetWebPluginForFind(); 5473 blink::WebPlugin* plugin = GetWebPluginForFind();
5468 // Check if the plugin still exists in the document. 5474 // Check if the plugin still exists in the document.
(...skipping 1162 matching lines...) Expand 10 before | Expand all | Expand 10 after
6631 // event target. Potentially a Pepper plugin will receive the event. 6637 // event target. Potentially a Pepper plugin will receive the event.
6632 // In order to tell whether a plugin gets the last mouse event and which it 6638 // In order to tell whether a plugin gets the last mouse event and which it
6633 // is, we set |pepper_last_mouse_event_target_| to null here. If a plugin gets 6639 // is, we set |pepper_last_mouse_event_target_| to null here. If a plugin gets
6634 // the event, it will notify us via DidReceiveMouseEvent() and set itself as 6640 // the event, it will notify us via DidReceiveMouseEvent() and set itself as
6635 // |pepper_last_mouse_event_target_|. 6641 // |pepper_last_mouse_event_target_|.
6636 pepper_last_mouse_event_target_ = nullptr; 6642 pepper_last_mouse_event_target_ = nullptr;
6637 #endif 6643 #endif
6638 } 6644 }
6639 6645
6640 } // namespace content 6646 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698