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

Side by Side Diff: ios/chrome/browser/reading_list/url_downloader.cc

Issue 2320403002: Update reading list entry on download (Closed)
Patch Set: address comments Created 4 years, 3 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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 "ios/chrome/browser/reading_list/url_downloader.h" 5 #include "ios/chrome/browser/reading_list/url_downloader.h"
6 6
7 #include <string> 7 #include <string>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/files/file_path.h" 10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h" 11 #include "base/files/file_util.h"
12 #include "base/md5.h" 12 #include "base/md5.h"
13 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
14 #include "base/path_service.h" 14 #include "base/path_service.h"
15 #include "ios/chrome/browser/chrome_paths.h" 15 #include "ios/chrome/browser/chrome_paths.h"
16 #include "ios/chrome/browser/dom_distiller/distiller_viewer.h" 16 #include "ios/chrome/browser/dom_distiller/distiller_viewer.h"
17 #include "ios/web/public/web_thread.h" 17 #include "ios/web/public/web_thread.h"
18 #include "url/gurl.h" 18 #include "url/gurl.h"
19 19
20 namespace { 20 namespace {
21 char const kOfflineDirectory[] = "Offline"; 21 char const kOfflineDirectory[] = "Offline";
22
23 // TODO(crbug.com/629771): Handle errors & retrying of failed saves, including
24 // distillation failure.
25
26 } // namespace 22 } // namespace
27 23
28 // URLDownloader 24 // URLDownloader
29 25
30 URLDownloader::URLDownloader( 26 URLDownloader::URLDownloader(
31 dom_distiller::DomDistillerService* distiller_service, 27 dom_distiller::DomDistillerService* distiller_service,
32 PrefService* prefs, 28 PrefService* prefs,
33 base::FilePath chrome_profile_path, 29 base::FilePath chrome_profile_path,
34 const SuccessCompletion& download_completion, 30 const DownloadCompletion& download_completion,
35 const SuccessCompletion& delete_completion) 31 const SuccessCompletion& delete_completion)
36 : distiller_service_(distiller_service), 32 : distiller_service_(distiller_service),
37 pref_service_(prefs), 33 pref_service_(prefs),
38 download_completion_(download_completion), 34 download_completion_(download_completion),
39 delete_completion_(delete_completion), 35 delete_completion_(delete_completion),
40 working_(false), 36 working_(false),
41 base_directory_(chrome_profile_path), 37 base_directory_(chrome_profile_path),
42 task_tracker_() {} 38 task_tracker_() {}
43 39
44 URLDownloader::~URLDownloader() { 40 URLDownloader::~URLDownloader() {
(...skipping 18 matching lines...) Expand all
63 } 59 }
64 60
65 void URLDownloader::DownloadOfflineURL(const GURL& url) { 61 void URLDownloader::DownloadOfflineURL(const GURL& url) {
66 if (std::find(tasks_.begin(), tasks_.end(), std::make_pair(DOWNLOAD, url)) == 62 if (std::find(tasks_.begin(), tasks_.end(), std::make_pair(DOWNLOAD, url)) ==
67 tasks_.end()) { 63 tasks_.end()) {
68 tasks_.push_back(std::make_pair(DOWNLOAD, url)); 64 tasks_.push_back(std::make_pair(DOWNLOAD, url));
69 HandleNextTask(); 65 HandleNextTask();
70 } 66 }
71 } 67 }
72 68
73 void URLDownloader::DownloadCompletionHandler(const GURL& url, bool success) { 69 void URLDownloader::DownloadCompletionHandler(const GURL& url,
70 const std::string& title,
71 SuccessState success) {
74 DCHECK(working_); 72 DCHECK(working_);
75 download_completion_.Run(url, success); 73
76 distiller_.reset(); 74 auto post_delete = base::Bind(
77 working_ = false; 75 [](URLDownloader* _this, const GURL& url, const std::string& title,
78 HandleNextTask(); 76 SuccessState success) {
77 _this->download_completion_.Run(
78 url, success,
79 GURL(std::string(url::kFileScheme) + url::kStandardSchemeSeparator +
80 _this->OfflineURLPagePath(url).value()),
81 title);
82 _this->distiller_.reset();
83 _this->working_ = false;
84 _this->HandleNextTask();
85 },
86 base::Unretained(this), url, title, success);
87
88 // If downloading failed, clean up any partial download.
89 if (success == ERROR_RETRY || success == ERROR_PERMANENT) {
90 task_tracker_.PostTaskAndReply(
91 web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE).get(),
92 FROM_HERE, base::Bind(
93 [](const base::FilePath& offline_directory_path) {
94 base::DeleteFile(offline_directory_path, true);
95 },
96 OfflineURLDirectoryPath(url)),
97 post_delete);
98 } else {
99 post_delete.Run();
100 }
79 } 101 }
80 102
81 void URLDownloader::DeleteCompletionHandler(const GURL& url, bool success) { 103 void URLDownloader::DeleteCompletionHandler(const GURL& url, bool success) {
82 DCHECK(working_); 104 DCHECK(working_);
83 delete_completion_.Run(url, success); 105 delete_completion_.Run(url, success);
84 working_ = false; 106 working_ = false;
85 HandleNextTask(); 107 HandleNextTask();
86 } 108 }
87 109
88 void URLDownloader::HandleNextTask() { 110 void URLDownloader::HandleNextTask() {
(...skipping 13 matching lines...) Expand all
102 base::Bind(&base::DeleteFile, OfflineURLDirectoryPath(url), true), 124 base::Bind(&base::DeleteFile, OfflineURLDirectoryPath(url), true),
103 base::Bind(&URLDownloader::DeleteCompletionHandler, 125 base::Bind(&URLDownloader::DeleteCompletionHandler,
104 base::Unretained(this), url)); 126 base::Unretained(this), url));
105 } else if (task.first == DOWNLOAD) { 127 } else if (task.first == DOWNLOAD) {
106 DCHECK(!distiller_); 128 DCHECK(!distiller_);
107 OfflineURLExists(url, base::Bind(&URLDownloader::DownloadURL, 129 OfflineURLExists(url, base::Bind(&URLDownloader::DownloadURL,
108 base::Unretained(this), url)); 130 base::Unretained(this), url));
109 } 131 }
110 } 132 }
111 133
112 void URLDownloader::DownloadURL(GURL url, bool offlineURLExists) { 134 void URLDownloader::DownloadURL(GURL url, bool offline_url_exists) {
113 if (offlineURLExists) { 135 if (offline_url_exists) {
114 DownloadCompletionHandler(url, false); 136 DownloadCompletionHandler(url, std::string(), DOWNLOAD_EXISTS);
115 return; 137 return;
116 } 138 }
117 139
118 distiller_.reset(new dom_distiller::DistillerViewer( 140 distiller_.reset(new dom_distiller::DistillerViewer(
119 distiller_service_, pref_service_, url, 141 distiller_service_, pref_service_, url,
120 base::Bind(&URLDownloader::DistillerCallback, base::Unretained(this)))); 142 base::Bind(&URLDownloader::DistillerCallback, base::Unretained(this))));
121 } 143 }
122 144
123 void URLDownloader::DistillerCallback( 145 void URLDownloader::DistillerCallback(
124 const GURL& pageURL, 146 const GURL& page_url,
125 const std::string& html, 147 const std::string& html,
126 const std::vector<dom_distiller::DistillerViewerInterface::ImageInfo>& 148 const std::vector<dom_distiller::DistillerViewerInterface::ImageInfo>&
127 images) { 149 images,
128 std::vector<dom_distiller::DistillerViewer::ImageInfo> imagesBlock = images; 150 const std::string& title) {
129 std::string blockHTML = html; 151 std::vector<dom_distiller::DistillerViewer::ImageInfo> images_block = images;
152 std::string block_html = html;
153 if (html.empty()) {
154 // TODO identify retry from permanent errors
155 DownloadCompletionHandler(page_url, std::string(), ERROR_PERMANENT);
156 return;
157 }
130 task_tracker_.PostTaskAndReplyWithResult( 158 task_tracker_.PostTaskAndReplyWithResult(
131 web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE).get(), 159 web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE).get(),
132 FROM_HERE, 160 FROM_HERE,
133 base::Bind(&URLDownloader::SaveDistilledHTML, base::Unretained(this), 161 base::Bind(&URLDownloader::SaveDistilledHTML, base::Unretained(this),
134 pageURL, imagesBlock, blockHTML), 162 page_url, images_block, block_html),
135 base::Bind(&URLDownloader::DownloadCompletionHandler, 163 base::Bind(&URLDownloader::DownloadCompletionHandler,
136 base::Unretained(this), pageURL)); 164 base::Unretained(this), page_url, title));
137 } 165 }
138 166
139 bool URLDownloader::SaveDistilledHTML( 167 URLDownloader::SuccessState URLDownloader::SaveDistilledHTML(
140 const GURL& url, 168 const GURL& url,
141 std::vector<dom_distiller::DistillerViewerInterface::ImageInfo> images, 169 std::vector<dom_distiller::DistillerViewerInterface::ImageInfo> images,
142 std::string html) { 170 std::string html) {
143 if (CreateOfflineURLDirectory(url)) { 171 if (CreateOfflineURLDirectory(url)) {
144 return SaveHTMLForURL(SaveAndReplaceImagesInHTML(url, html, images), url); 172 return SaveHTMLForURL(SaveAndReplaceImagesInHTML(url, html, images), url)
173 ? DOWNLOAD_SUCCESS
174 : ERROR_PERMANENT;
145 } 175 }
146 return false; 176 return ERROR_PERMANENT;
147 } 177 }
148 178
149 base::FilePath URLDownloader::OfflineDirectoryPath() { 179 base::FilePath URLDownloader::OfflineDirectoryPath() {
150 return base_directory_.Append(kOfflineDirectory); 180 return base_directory_.Append(kOfflineDirectory);
151 } 181 }
152 182
153 base::FilePath URLDownloader::OfflineURLDirectoryPath(const GURL& url) { 183 base::FilePath URLDownloader::OfflineURLDirectoryPath(const GURL& url) {
154 std::string hash = base::MD5String(url.spec()); 184 std::string hash = base::MD5String(url.spec());
155 return OfflineDirectoryPath().Append(hash); 185 return OfflineDirectoryPath().Append(hash);
156 } 186 }
157 187
158 base::FilePath URLDownloader::OfflineURLPagePath(const GURL& url) { 188 base::FilePath URLDownloader::OfflineURLPagePath(const GURL& url) {
159 return OfflineURLDirectoryPath(url).Append("page.html"); 189 return OfflineURLDirectoryPath(url).Append("page.html");
160 } 190 }
161 191
162 bool URLDownloader::CreateOfflineURLDirectory(const GURL& url) { 192 bool URLDownloader::CreateOfflineURLDirectory(const GURL& url) {
163 base::FilePath path = OfflineURLDirectoryPath(url); 193 base::FilePath path = OfflineURLDirectoryPath(url);
164 if (!DirectoryExists(path)) { 194 if (!DirectoryExists(path)) {
165 return CreateDirectoryAndGetError(path, nil); 195 return CreateDirectoryAndGetError(path, nil);
166 } 196 }
167 return true; 197 return true;
168 } 198 }
169 199
170 std::string URLDownloader::SaveImage(const GURL& url, 200 bool URLDownloader::SaveImage(const GURL& url,
171 const GURL& imageURL, 201 const GURL& image_url,
172 const std::string& data) { 202 const std::string& data,
173 base::FilePath path = 203 base::FilePath& path) {
174 OfflineURLDirectoryPath(url).Append(base::MD5String(imageURL.spec())); 204 path = OfflineURLDirectoryPath(url).Append(base::MD5String(image_url.spec()));
175 if (!base::PathExists(path)) { 205 if (!base::PathExists(path)) {
176 base::WriteFile(path, data.c_str(), data.length()); 206 return base::WriteFile(path, data.c_str(), data.length()) > 0;
177 } 207 }
178 return path.AsUTF8Unsafe(); 208 return true;
179 } 209 }
180 210
181 // TODO(crbug.com/625621) DomDistiller doesn't correctly handle srcset
182 // attributes in img tags.
183 std::string URLDownloader::SaveAndReplaceImagesInHTML( 211 std::string URLDownloader::SaveAndReplaceImagesInHTML(
184 const GURL& url, 212 const GURL& url,
185 const std::string& html, 213 const std::string& html,
186 const std::vector<dom_distiller::DistillerViewerInterface::ImageInfo>& 214 const std::vector<dom_distiller::DistillerViewerInterface::ImageInfo>&
187 images) { 215 images) {
188 std::string mutableHTML = html; 216 std::string mutable_html = html;
189 for (size_t i = 0; i < images.size(); i++) { 217 for (size_t i = 0; i < images.size(); i++) {
190 const std::string& localImagePath = 218 base::FilePath local_image_path;
191 SaveImage(url, images[i].url, images[i].data); 219 if (!SaveImage(url, images[i].url, images[i].data, local_image_path)) {
192 const std::string& imageURL = images[i].url.spec(); 220 return std::string();
193 size_t imageURLSize = imageURL.size(); 221 }
194 size_t pos = mutableHTML.find(imageURL, 0); 222 const std::string& image_url = images[i].url.spec();
223 size_t image_url_size = image_url.size();
224 size_t pos = mutable_html.find(image_url, 0);
195 while (pos != std::string::npos) { 225 while (pos != std::string::npos) {
196 mutableHTML.replace(pos, imageURLSize, localImagePath); 226 mutable_html.replace(pos, image_url_size,
197 pos = mutableHTML.find(imageURL, pos + imageURLSize); 227 local_image_path.AsUTF8Unsafe());
228 pos = mutable_html.find(image_url, pos + image_url_size);
198 } 229 }
199 } 230 }
200 return mutableHTML; 231 return mutable_html;
201 } 232 }
202 233
203 bool URLDownloader::SaveHTMLForURL(std::string html, const GURL& url) { 234 bool URLDownloader::SaveHTMLForURL(std::string html, const GURL& url) {
235 if (html.empty()) {
236 return false;
237 }
204 base::FilePath path = OfflineURLPagePath(url); 238 base::FilePath path = OfflineURLPagePath(url);
205 return base::WriteFile(path, html.c_str(), html.length()) < 0; 239 return base::WriteFile(path, html.c_str(), html.length()) > 0;
206 } 240 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698