1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h"
#include "base/base64.h"
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/sha1.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/web_contents.h"
#include "net/base/filename_util.h"
namespace offline_pages {
namespace {
const base::FilePath::CharType kMHTMLExtension[] = FILE_PATH_LITERAL("mhtml");
const base::FilePath::CharType kDefaultFileName[] =
FILE_PATH_LITERAL("offline_page");
const int kTitleLengthMax = 80;
const char kMHTMLFileNameExtension[] = ".mhtml";
const char kFileNameComponentsSeparator[] = "-";
const char kReplaceChars[] = " ";
const char kReplaceWith[] = "_";
} // namespace
// static
std::string OfflinePageMHTMLArchiver::GetFileNameExtension() {
return kMHTMLFileNameExtension;
}
// static
base::FilePath OfflinePageMHTMLArchiver::GenerateFileName(
const GURL& url,
const std::string& title) {
std::string title_part(title.substr(0, kTitleLengthMax));
std::string url_hash(base::SHA1HashString(url.spec()));
base::Base64Encode(url_hash, &url_hash);
std::string suggested_name(url.host() + kFileNameComponentsSeparator +
title_part + kFileNameComponentsSeparator +
url_hash);
// Substitute spaces out from title.
base::ReplaceChars(suggested_name, kReplaceChars, kReplaceWith,
&suggested_name);
return net::GenerateFileName(url,
std::string(), // content disposition
std::string(), // charset
suggested_name,
std::string(), // mime-type
kDefaultFileName)
.AddExtension(kMHTMLExtension);
}
OfflinePageMHTMLArchiver::OfflinePageMHTMLArchiver(
content::WebContents* web_contents)
: web_contents_(web_contents),
weak_ptr_factory_(this) {
DCHECK(web_contents_);
}
OfflinePageMHTMLArchiver::OfflinePageMHTMLArchiver()
: web_contents_(nullptr),
weak_ptr_factory_(this) {
}
OfflinePageMHTMLArchiver::~OfflinePageMHTMLArchiver() {
}
void OfflinePageMHTMLArchiver::CreateArchive(
const base::FilePath& archives_dir,
const CreateArchiveCallback& callback) {
DCHECK(callback_.is_null());
DCHECK(!callback.is_null());
callback_ = callback;
GenerateMHTML(archives_dir);
}
void OfflinePageMHTMLArchiver::GenerateMHTML(
const base::FilePath& archives_dir) {
if (archives_dir.empty()) {
DVLOG(1) << "Archive path was empty. Can't create archive.";
ReportFailure(ArchiverResult::ERROR_ARCHIVE_CREATION_FAILED);
return;
}
if (!web_contents_) {
DVLOG(1) << "WebContents is missing. Can't create archive.";
ReportFailure(ArchiverResult::ERROR_CONTENT_UNAVAILABLE);
return;
}
if (!web_contents_->GetRenderViewHost()) {
DVLOG(1) << "RenderViewHost is not created yet. Can't create archive.";
ReportFailure(ArchiverResult::ERROR_CONTENT_UNAVAILABLE);
return;
}
// TODO(fgorski): Figure out if the actual URL can be different at
// the end of MHTML generation. Perhaps we should pull it out after the MHTML
// is generated.
GURL url(web_contents_->GetLastCommittedURL());
base::string16 title(web_contents_->GetTitle());
base::FilePath file_path(
archives_dir.Append(GenerateFileName(url, base::UTF16ToUTF8(title))));
web_contents_->GenerateMHTML(
file_path, base::Bind(&OfflinePageMHTMLArchiver::OnGenerateMHTMLDone,
weak_ptr_factory_.GetWeakPtr(), url, file_path));
}
void OfflinePageMHTMLArchiver::OnGenerateMHTMLDone(
const GURL& url,
const base::FilePath& file_path,
int64_t file_size) {
if (file_size < 0) {
ReportFailure(ArchiverResult::ERROR_ARCHIVE_CREATION_FAILED);
} else {
callback_.Run(this, ArchiverResult::SUCCESSFULLY_CREATED, url, file_path,
file_size);
}
}
void OfflinePageMHTMLArchiver::ReportFailure(ArchiverResult result) {
DCHECK(result != ArchiverResult::SUCCESSFULLY_CREATED);
callback_.Run(this, result, GURL(), base::FilePath(), 0);
}
} // namespace offline_pages
|