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

Side by Side Diff: content/browser/download/mhtml_generation_manager.cc

Issue 2683493002: Get signals working in the EXTRA_DATA section of MHTML (Closed)
Patch Set: Move MHTMLExtraData and MHTMLExtraPart out of the .h file Created 3 years, 9 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/browser/download/mhtml_generation_manager.h" 5 #include "content/browser/download/mhtml_generation_manager.h"
6 6
7 #include <map> 7 #include <map>
8 #include <queue> 8 #include <queue>
9 #include <utility> 9 #include <utility>
10 10
(...skipping 14 matching lines...) Expand all
25 #include "content/browser/frame_host/render_frame_host_impl.h" 25 #include "content/browser/frame_host/render_frame_host_impl.h"
26 #include "content/common/frame_messages.h" 26 #include "content/common/frame_messages.h"
27 #include "content/public/browser/browser_thread.h" 27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/render_frame_host.h" 28 #include "content/public/browser/render_frame_host.h"
29 #include "content/public/browser/render_process_host.h" 29 #include "content/public/browser/render_process_host.h"
30 #include "content/public/browser/render_process_host_observer.h" 30 #include "content/public/browser/render_process_host_observer.h"
31 #include "content/public/browser/web_contents.h" 31 #include "content/public/browser/web_contents.h"
32 #include "content/public/common/mhtml_generation_params.h" 32 #include "content/public/common/mhtml_generation_params.h"
33 #include "net/base/mime_util.h" 33 #include "net/base/mime_util.h"
34 34
35 namespace {
36 const char kContentLocation[] = "Content-Location: ";
37 const char kContentType[] = "Content-Type: ";
38 const int kMHTMLExtraDataKey = 0;
39
40 // Data fields used to build an additional MHTML part in the output file.
41 struct MHTMLExtraPart {
42 std::string content_type;
43 std::string content_location;
44 std::string body;
45 };
46
47 // Class used as a data object for WebContents UserData to represent a MHTML
48 // part that we plan to write into the output MHTML file. Each MHTMLExtraPart
49 // object in the contained vector lets us hold enough information to generate
50 // one MHTML part. Arbitrary extra MHTML parts to be added into the complete
51 // file. For instance, this might be used for gathering load time signals in
52 // debug code for analysis.
53 class MHTMLExtraData : public base::SupportsUserData::Data {
54 public:
55 MHTMLExtraData() {}
56 ~MHTMLExtraData() override {}
57
58 // Return the vector of parts to be disassembled.
59 std::vector<MHTMLExtraPart>& parts() { return parts_; }
60 const std::vector<MHTMLExtraPart>& parts() const { return parts_; }
61
62 // Get the data string out of the web contents. The web contents retains
63 // ownership of the vector. Returns nullptr if none found.
64 static MHTMLExtraData* FromWebContents(content::WebContents* contents) {
65 return static_cast<MHTMLExtraData*>(
66 contents->GetUserData(&kMHTMLExtraDataKey));
67 }
68
69 private:
70 std::vector<MHTMLExtraPart> parts_;
71 };
72 } // namespace
73
35 namespace content { 74 namespace content {
36 75
37 // The class and all of its members live on the UI thread. Only static methods 76 // The class and all of its members live on the UI thread. Only static methods
38 // are executed on other threads. 77 // are executed on other threads.
39 class MHTMLGenerationManager::Job : public RenderProcessHostObserver { 78 class MHTMLGenerationManager::Job : public RenderProcessHostObserver {
40 public: 79 public:
41 Job(int job_id, 80 Job(int job_id,
42 WebContents* web_contents, 81 WebContents* web_contents,
43 const MHTMLGenerationParams& params, 82 const MHTMLGenerationParams& params,
44 const GenerateMHTMLCallback& callback); 83 const GenerateMHTMLCallback& callback);
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
94 133
95 private: 134 private:
96 // Writes the MHTML footer to the file and closes it. 135 // Writes the MHTML footer to the file and closes it.
97 // 136 //
98 // Note: The same |boundary| marker must be used for all "boundaries" -- in 137 // Note: The same |boundary| marker must be used for all "boundaries" -- in
99 // the header, parts and footer -- that belong to the same MHTML document (see 138 // the header, parts and footer -- that belong to the same MHTML document (see
100 // also rfc1341, section 7.2.1, "boundary" description). 139 // also rfc1341, section 7.2.1, "boundary" description).
101 static std::tuple<MhtmlSaveStatus, int64_t> CloseFileOnFileThread( 140 static std::tuple<MhtmlSaveStatus, int64_t> CloseFileOnFileThread(
102 MhtmlSaveStatus save_status, 141 MhtmlSaveStatus save_status,
103 const std::string& boundary, 142 const std::string& boundary,
104 base::File file); 143 base::File file,
144 const MHTMLExtraData* extra_parts);
105 void AddFrame(RenderFrameHost* render_frame_host); 145 void AddFrame(RenderFrameHost* render_frame_host);
106 146
147 // If we have any extra MHTML parts to write out, write them into the file
148 // while on the file thread. Returns true for success.
149 static bool WriteExtraDataPartsOnFileThread(const std::string& boundary,
150 base::File& file,
151 const MHTMLExtraData* extra_data);
152
107 // Creates a new map with values (content ids) the same as in 153 // Creates a new map with values (content ids) the same as in
108 // |frame_tree_node_to_content_id_| map, but with the keys translated from 154 // |frame_tree_node_to_content_id_| map, but with the keys translated from
109 // frame_tree_node_id into a |site_instance|-specific routing_id. 155 // frame_tree_node_id into a |site_instance|-specific routing_id.
110 std::map<int, std::string> CreateFrameRoutingIdToContentId( 156 std::map<int, std::string> CreateFrameRoutingIdToContentId(
111 SiteInstance* site_instance); 157 SiteInstance* site_instance);
112 158
113 // Id used to map renderer responses to jobs. 159 // Id used to map renderer responses to jobs.
114 // See also MHTMLGenerationManager::id_to_job_ map. 160 // See also MHTMLGenerationManager::id_to_job_ map.
115 const int job_id_; 161 const int job_id_;
116 162
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 std::string salt_; 195 std::string salt_;
150 196
151 // The callback to call once generation is complete. 197 // The callback to call once generation is complete.
152 const GenerateMHTMLCallback callback_; 198 const GenerateMHTMLCallback callback_;
153 199
154 // Whether the job is finished (set to true only for the short duration of 200 // Whether the job is finished (set to true only for the short duration of
155 // time between MHTMLGenerationManager::JobFinished is called and the job is 201 // time between MHTMLGenerationManager::JobFinished is called and the job is
156 // destroyed by MHTMLGenerationManager::OnFileClosed). 202 // destroyed by MHTMLGenerationManager::OnFileClosed).
157 bool is_finished_; 203 bool is_finished_;
158 204
205 // Any extra data parts that should be emitted into the output MHTML.
206 MHTMLExtraData* extra_data_;
207
159 // RAII helper for registering this Job as a RenderProcessHost observer. 208 // RAII helper for registering this Job as a RenderProcessHost observer.
160 ScopedObserver<RenderProcessHost, MHTMLGenerationManager::Job> 209 ScopedObserver<RenderProcessHost, MHTMLGenerationManager::Job>
161 observed_renderer_process_host_; 210 observed_renderer_process_host_;
162 211
163 DISALLOW_COPY_AND_ASSIGN(Job); 212 DISALLOW_COPY_AND_ASSIGN(Job);
164 }; 213 };
165 214
166 MHTMLGenerationManager::Job::Job(int job_id, 215 MHTMLGenerationManager::Job::Job(int job_id,
167 WebContents* web_contents, 216 WebContents* web_contents,
168 const MHTMLGenerationParams& params, 217 const MHTMLGenerationParams& params,
169 const GenerateMHTMLCallback& callback) 218 const GenerateMHTMLCallback& callback)
170 : job_id_(job_id), 219 : job_id_(job_id),
171 creation_time_(base::TimeTicks::Now()), 220 creation_time_(base::TimeTicks::Now()),
172 params_(params), 221 params_(params),
173 frame_tree_node_id_of_busy_frame_(FrameTreeNode::kFrameTreeNodeInvalidId), 222 frame_tree_node_id_of_busy_frame_(FrameTreeNode::kFrameTreeNodeInvalidId),
174 mhtml_boundary_marker_(net::GenerateMimeMultipartBoundary()), 223 mhtml_boundary_marker_(net::GenerateMimeMultipartBoundary()),
175 salt_(base::GenerateGUID()), 224 salt_(base::GenerateGUID()),
176 callback_(callback), 225 callback_(callback),
177 is_finished_(false), 226 is_finished_(false),
178 observed_renderer_process_host_(this) { 227 observed_renderer_process_host_(this) {
179 DCHECK_CURRENTLY_ON(BrowserThread::UI); 228 DCHECK_CURRENTLY_ON(BrowserThread::UI);
180 web_contents->ForEachFrame(base::Bind( 229 web_contents->ForEachFrame(base::Bind(
181 &MHTMLGenerationManager::Job::AddFrame, 230 &MHTMLGenerationManager::Job::AddFrame,
182 base::Unretained(this))); // Safe because ForEachFrame is synchronous. 231 base::Unretained(this))); // Safe because ForEachFrame is synchronous.
183 232
184 // Main frame needs to be processed first. 233 // Main frame needs to be processed first.
185 DCHECK(!pending_frame_tree_node_ids_.empty()); 234 DCHECK(!pending_frame_tree_node_ids_.empty());
186 DCHECK(FrameTreeNode::GloballyFindByID(pending_frame_tree_node_ids_.front()) 235 DCHECK(FrameTreeNode::GloballyFindByID(pending_frame_tree_node_ids_.front())
187 ->parent() == nullptr); 236 ->parent() == nullptr);
237
238 // Save off any extra data.
239 extra_data_ = MHTMLExtraData::FromWebContents(web_contents);
188 } 240 }
189 241
190 MHTMLGenerationManager::Job::~Job() { 242 MHTMLGenerationManager::Job::~Job() {
191 DCHECK_CURRENTLY_ON(BrowserThread::UI); 243 DCHECK_CURRENTLY_ON(BrowserThread::UI);
192 } 244 }
193 245
194 std::map<int, std::string> 246 std::map<int, std::string>
195 MHTMLGenerationManager::Job::CreateFrameRoutingIdToContentId( 247 MHTMLGenerationManager::Job::CreateFrameRoutingIdToContentId(
196 SiteInstance* site_instance) { 248 SiteInstance* site_instance) {
197 std::map<int, std::string> result; 249 std::map<int, std::string> result;
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 return; 400 return;
349 } 401 }
350 402
351 // If no previous error occurred the boundary should be sent. 403 // If no previous error occurred the boundary should be sent.
352 BrowserThread::PostTaskAndReplyWithResult( 404 BrowserThread::PostTaskAndReplyWithResult(
353 BrowserThread::FILE, FROM_HERE, 405 BrowserThread::FILE, FROM_HERE,
354 base::Bind( 406 base::Bind(
355 &MHTMLGenerationManager::Job::CloseFileOnFileThread, save_status, 407 &MHTMLGenerationManager::Job::CloseFileOnFileThread, save_status,
356 (save_status == MhtmlSaveStatus::SUCCESS ? mhtml_boundary_marker_ 408 (save_status == MhtmlSaveStatus::SUCCESS ? mhtml_boundary_marker_
357 : std::string()), 409 : std::string()),
358 base::Passed(&browser_file_)), 410 base::Passed(&browser_file_), extra_data_),
359 callback); 411 callback);
360 } 412 }
361 413
362 bool MHTMLGenerationManager::Job::IsMessageFromFrameExpected( 414 bool MHTMLGenerationManager::Job::IsMessageFromFrameExpected(
363 RenderFrameHostImpl* sender) { 415 RenderFrameHostImpl* sender) {
364 int sender_id = sender->frame_tree_node()->frame_tree_node_id(); 416 int sender_id = sender->frame_tree_node()->frame_tree_node_id();
365 if (sender_id != frame_tree_node_id_of_busy_frame_) 417 if (sender_id != frame_tree_node_id_of_busy_frame_)
366 return false; 418 return false;
367 419
368 // We only expect one message per frame - let's make sure subsequent messages 420 // We only expect one message per frame - let's make sure subsequent messages
(...skipping 25 matching lines...) Expand all
394 446
395 // Report success if all frames have been processed. 447 // Report success if all frames have been processed.
396 if (pending_frame_tree_node_ids_.empty()) 448 if (pending_frame_tree_node_ids_.empty())
397 return MhtmlSaveStatus::SUCCESS; 449 return MhtmlSaveStatus::SUCCESS;
398 450
399 return SendToNextRenderFrame(); 451 return SendToNextRenderFrame();
400 } 452 }
401 453
402 // static 454 // static
403 std::tuple<MhtmlSaveStatus, int64_t> 455 std::tuple<MhtmlSaveStatus, int64_t>
404 MHTMLGenerationManager::Job::CloseFileOnFileThread(MhtmlSaveStatus save_status, 456 MHTMLGenerationManager::Job::CloseFileOnFileThread(
405 const std::string& boundary, 457 MhtmlSaveStatus save_status,
406 base::File file) { 458 const std::string& boundary,
459 base::File file,
460 const MHTMLExtraData* extra_data) {
407 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 461 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
462 int64_t file_size = -1;
408 463
409 // If no previous error occurred the boundary should have been provided. 464 // If no previous error occurred the boundary should have been provided.
410 if (save_status == MhtmlSaveStatus::SUCCESS) { 465 if (save_status == MhtmlSaveStatus::SUCCESS) {
411 TRACE_EVENT0("page-serialization", 466 TRACE_EVENT0("page-serialization",
412 "MHTMLGenerationManager::Job MHTML footer writing"); 467 "MHTMLGenerationManager::Job MHTML footer writing");
413 DCHECK(!boundary.empty()); 468 DCHECK(!boundary.empty());
469
470 // Write the extra data into a part of its own, if we have any.
471 if (!WriteExtraDataPartsOnFileThread(boundary, file, extra_data)) {
472 save_status = MhtmlSaveStatus::FILE_WRITTING_ERROR;
473 return std::make_tuple(save_status, file_size);
474 }
475
414 std::string footer = base::StringPrintf("--%s--\r\n", boundary.c_str()); 476 std::string footer = base::StringPrintf("--%s--\r\n", boundary.c_str());
415 DCHECK(base::IsStringASCII(footer)); 477 DCHECK(base::IsStringASCII(footer));
416 if (file.WriteAtCurrentPos(footer.data(), footer.size()) < 0) 478 if (file.WriteAtCurrentPos(footer.data(), footer.size()) < 0) {
417 save_status = MhtmlSaveStatus::FILE_WRITTING_ERROR; 479 save_status = MhtmlSaveStatus::FILE_WRITTING_ERROR;
480 return std::make_tuple(save_status, file_size);
481 }
418 } 482 }
419 483
420 // If the file is still valid try to close it. Only update the status if that 484 // If the file is still valid try to close it. Only update the status if that
421 // won't hide an earlier error. 485 // won't hide an earlier error.
422 int64_t file_size = -1;
423 if (file.IsValid()) { 486 if (file.IsValid()) {
424 file_size = file.GetLength(); 487 file_size = file.GetLength();
425 file.Close(); 488 file.Close();
426 } else if (save_status == MhtmlSaveStatus::SUCCESS) { 489 } else if (save_status == MhtmlSaveStatus::SUCCESS) {
427 save_status = MhtmlSaveStatus::FILE_CLOSING_ERROR; 490 save_status = MhtmlSaveStatus::FILE_CLOSING_ERROR;
428 } 491 }
429 492
430 return std::make_tuple(save_status, file_size); 493 return std::make_tuple(save_status, file_size);
431 } 494 }
432 495
496 // static
497 bool MHTMLGenerationManager::Job::WriteExtraDataPartsOnFileThread(
498 const std::string& boundary,
499 base::File& file,
500 const MHTMLExtraData* extra_data) {
501 // Don't write an extra data part if there is none.
502 if (extra_data == nullptr)
503 return true;
504
505 const std::vector<MHTMLExtraPart>& extra_parts(extra_data->parts());
506 if (extra_parts.empty())
507 return true;
508
509 std::string extra_parts_serialized;
510
511 // For each extra part, serialize that part and add to our accumulator
512 // string.
513 for (auto part : extra_parts) {
514 // Write a newline, then a boundary, another newline, then the content
515 // location, another newline, the content type, another newline, the extra
516 // data string, and end with a newline.
517 std::string extra_data_part = base::StringPrintf(
518 "--%s--\r\n%s%s\r\n%s%s\r\n%s\r\n", boundary.c_str(), kContentLocation,
519 part.content_location.c_str(), kContentType, part.content_type.c_str(),
520 part.body.c_str());
521 DCHECK(base::IsStringASCII(extra_data_part));
522
523 extra_parts_serialized += extra_data_part;
524 }
525
526 // Write the string into the file. Returns false if we failed the write.
527 return (file.WriteAtCurrentPos(extra_parts_serialized.data(),
528 extra_parts_serialized.size()) >= 0);
529 }
530
433 MHTMLGenerationManager* MHTMLGenerationManager::GetInstance() { 531 MHTMLGenerationManager* MHTMLGenerationManager::GetInstance() {
434 return base::Singleton<MHTMLGenerationManager>::get(); 532 return base::Singleton<MHTMLGenerationManager>::get();
435 } 533 }
436 534
535 void MHTMLGenerationManager::StashMHTMLPartForAdditionToPage(
536 content::WebContents* contents,
537 const std::string& content_type,
538 const std::string& content_location,
539 const std::string& body) {
540 MHTMLExtraPart part;
541 part.content_type = content_type;
542 part.content_location = content_location;
543 part.body = body;
544
545 MHTMLExtraData* extra_data = MHTMLExtraData::FromWebContents(contents);
546 // If we don't already have any extra data, add it now.
547 if (extra_data == nullptr) {
548 extra_data = new MHTMLExtraData();
549 // Note that we hold onto extra_data until the end of this function, even
550 // though we transfer it to the web contents user data here.
551 contents->SetUserData(&kMHTMLExtraDataKey,
552 std::unique_ptr<MHTMLExtraData>(extra_data));
553 }
554 // Add this part to the list of parts to be saved out when the file is
555 // written.
556 extra_data->parts().push_back(part);
557 }
558
437 MHTMLGenerationManager::MHTMLGenerationManager() : next_job_id_(0) {} 559 MHTMLGenerationManager::MHTMLGenerationManager() : next_job_id_(0) {}
438 560
439 MHTMLGenerationManager::~MHTMLGenerationManager() { 561 MHTMLGenerationManager::~MHTMLGenerationManager() {
440 } 562 }
441 563
442 void MHTMLGenerationManager::SaveMHTML(WebContents* web_contents, 564 void MHTMLGenerationManager::SaveMHTML(WebContents* web_contents,
443 const MHTMLGenerationParams& params, 565 const MHTMLGenerationParams& params,
444 const GenerateMHTMLCallback& callback) { 566 const GenerateMHTMLCallback& callback) {
445 DCHECK_CURRENTLY_ON(BrowserThread::UI); 567 DCHECK_CURRENTLY_ON(BrowserThread::UI);
446 568
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
592 return iter->second.get(); 714 return iter->second.get();
593 } 715 }
594 716
595 void MHTMLGenerationManager::RenderProcessExited(Job* job) { 717 void MHTMLGenerationManager::RenderProcessExited(Job* job) {
596 DCHECK_CURRENTLY_ON(BrowserThread::UI); 718 DCHECK_CURRENTLY_ON(BrowserThread::UI);
597 DCHECK(job); 719 DCHECK(job);
598 JobFinished(job, MhtmlSaveStatus::RENDER_PROCESS_EXITED); 720 JobFinished(job, MhtmlSaveStatus::RENDER_PROCESS_EXITED);
599 } 721 }
600 722
601 } // namespace content 723 } // namespace content
OLDNEW
« content/browser/BUILD.gn ('K') | « content/browser/download/mhtml_generation_manager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698